Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / Microsoft / Scripting / Compiler / LambdaCompiler.ControlFlow.cs / 1305376 / LambdaCompiler.ControlFlow.cs
/* **************************************************************************** * * Copyright (c) Microsoft Corporation. * * This source code is subject to terms and conditions of the Microsoft Public License. A * copy of the license can be found in the License.html file at the root of this distribution. If * you cannot locate the Microsoft Public License, please send an email to * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound * by the terms of the Microsoft Public License. * * You must not remove this notice, or any other, from this software. * * * ***************************************************************************/ using System.Diagnostics; using System.Dynamic.Utils; namespace System.Linq.Expressions.Compiler { // The part of the LambdaCompiler dealing with low level control flow // break, contiue, return, exceptions, etc partial class LambdaCompiler { private LabelInfo EnsureLabel(LabelTarget node) { LabelInfo result; if (!_labelInfo.TryGetValue(node, out result)) { _labelInfo.Add(node, result = new LabelInfo(_ilg, node, false)); } return result; } private LabelInfo ReferenceLabel(LabelTarget node) { LabelInfo result = EnsureLabel(node); result.Reference(_labelBlock); return result; } private LabelInfo DefineLabel(LabelTarget node) { if (node == null) { return new LabelInfo(_ilg, null, false); } LabelInfo result = EnsureLabel(node); result.Define(_labelBlock); return result; } private void PushLabelBlock(LabelScopeKind type) { _labelBlock = new LabelScopeInfo(_labelBlock, type); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "kind")] private void PopLabelBlock(LabelScopeKind kind) { Debug.Assert(_labelBlock != null && _labelBlock.Kind == kind); _labelBlock = _labelBlock.Parent; } private void EmitLabelExpression(Expression expr, CompilationFlags flags) { var node = (LabelExpression)expr; Debug.Assert(node.Target != null); // If we're an immediate child of a block, our label will already // be defined. If not, we need to define our own block so this // label isn't exposed except to its own child expression. LabelInfo label = null; if (_labelBlock.Kind == LabelScopeKind.Block) { _labelBlock.TryGetLabelInfo(node.Target, out label); // We're in a block but didn't find our label, try switch if (label == null && _labelBlock.Parent.Kind == LabelScopeKind.Switch) { _labelBlock.Parent.TryGetLabelInfo(node.Target, out label); } // if we're in a switch or block, we should've found the label Debug.Assert(label != null); } if (label == null) { label = DefineLabel(node.Target); } if (node.DefaultValue != null) { if (node.Target.Type == typeof(void)) { EmitExpressionAsVoid(node.DefaultValue, flags); } else { flags = UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart); EmitExpression(node.DefaultValue, flags); } } label.Mark(); } private void EmitGotoExpression(Expression expr, CompilationFlags flags) { var node = (GotoExpression)expr; var labelInfo = ReferenceLabel(node.Target); var tailCall = flags & CompilationFlags.EmitAsTailCallMask; if (tailCall != CompilationFlags.EmitAsNoTail) { // Since tail call flags are not passed into EmitTryExpression, CanReturn // means the goto will be emitted as Ret. Therefore we can emit the goto's // default value with tail call. This can be improved by detecting if the // target label is equivalent to the return label. tailCall = labelInfo.CanReturn ? CompilationFlags.EmitAsTail : CompilationFlags.EmitAsNoTail; flags = UpdateEmitAsTailCallFlag(flags, tailCall); } if (node.Value != null) { if (node.Target.Type == typeof(void)) { EmitExpressionAsVoid(node.Value, flags); } else { flags = UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart); EmitExpression(node.Value, flags); } } labelInfo.EmitJump(); EmitUnreachable(node, flags); } // We need to push default(T), unless we're emitting ourselves as // void. Even though the code is unreachable, we still have to // generate correct IL. We can get rid of this once we have better // reachability analysis. private void EmitUnreachable(Expression node, CompilationFlags flags) { if (node.Type != typeof(void) && (flags & CompilationFlags.EmitAsVoidType) == 0) { _ilg.EmitDefault(node.Type); } } private bool TryPushLabelBlock(Expression node) { // Anything that is "statement-like" -- e.g. has no associated // stack state can be jumped into, with the exception of try-blocks // We indicate this by a "Block" // // Otherwise, we push an "Expression" to indicate that it can't be // jumped into switch (node.NodeType) { default: if (_labelBlock.Kind != LabelScopeKind.Expression) { PushLabelBlock(LabelScopeKind.Expression); return true; } return false; case ExpressionType.Label: // LabelExpression is a bit special, if it's directly in a // block it becomes associate with the block's scope. Same // thing if it's in a switch case body. if (_labelBlock.Kind == LabelScopeKind.Block) { var label = ((LabelExpression)node).Target; if (_labelBlock.ContainsTarget(label)) { return false; } if (_labelBlock.Parent.Kind == LabelScopeKind.Switch && _labelBlock.Parent.ContainsTarget(label)) { return false; } } PushLabelBlock(LabelScopeKind.Statement); return true; case ExpressionType.Block: if (node is SpilledExpressionBlock) { // treat it as an expression goto default; } PushLabelBlock(LabelScopeKind.Block); // Labels defined immediately in the block are valid for // the whole block. if (_labelBlock.Parent.Kind != LabelScopeKind.Switch) { DefineBlockLabels(node); } return true; case ExpressionType.Switch: PushLabelBlock(LabelScopeKind.Switch); // Define labels inside of the switch cases so theyare in // scope for the whole switch. This allows "goto case" and // "goto default" to be considered as local jumps. var @switch = (SwitchExpression)node; foreach (SwitchCase c in @switch.Cases) { DefineBlockLabels(c.Body); } DefineBlockLabels(@switch.DefaultBody); return true; // Remove this when Convert(Void) goes away. case ExpressionType.Convert: if (node.Type != typeof(void)) { // treat it as an expression goto default; } PushLabelBlock(LabelScopeKind.Statement); return true; case ExpressionType.Conditional: case ExpressionType.Loop: case ExpressionType.Goto: PushLabelBlock(LabelScopeKind.Statement); return true; } } private void DefineBlockLabels(Expression node) { var block = node as BlockExpression; if (block == null || block is SpilledExpressionBlock) { return; } for (int i = 0, n = block.ExpressionCount; i < n; i++) { Expression e = block.GetExpression(i); var label = e as LabelExpression; if (label != null) { DefineLabel(label.Target); } } } // See if this lambda has a return label // If so, we'll create it now and mark it as allowing the "ret" opcode // This allows us to generate better IL private void AddReturnLabel(LambdaExpression lambda) { var expression = lambda.Body; while (true) { switch (expression.NodeType) { default: // Didn't find return label return; case ExpressionType.Label: // Found the label. We can directly return from this place // only if the label type is reference assignable to the lambda return type. var label = ((LabelExpression)expression).Target; _labelInfo.Add(label, new LabelInfo(_ilg, label, TypeUtils.AreReferenceAssignable(lambda.ReturnType, label.Type))); return; case ExpressionType.Block: // Look in the last significant expression of a block var body = (BlockExpression)expression; // omit empty and debuginfo at the end of the block since they // are not going to emit any IL for (int i = body.ExpressionCount - 1; i >= 0; i--) { expression = body.GetExpression(i); if (Significant(expression)) { break; } } continue; } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. /* **************************************************************************** * * Copyright (c) Microsoft Corporation. * * This source code is subject to terms and conditions of the Microsoft Public License. A * copy of the license can be found in the License.html file at the root of this distribution. If * you cannot locate the Microsoft Public License, please send an email to * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound * by the terms of the Microsoft Public License. * * You must not remove this notice, or any other, from this software. * * * ***************************************************************************/ using System.Diagnostics; using System.Dynamic.Utils; namespace System.Linq.Expressions.Compiler { // The part of the LambdaCompiler dealing with low level control flow // break, contiue, return, exceptions, etc partial class LambdaCompiler { private LabelInfo EnsureLabel(LabelTarget node) { LabelInfo result; if (!_labelInfo.TryGetValue(node, out result)) { _labelInfo.Add(node, result = new LabelInfo(_ilg, node, false)); } return result; } private LabelInfo ReferenceLabel(LabelTarget node) { LabelInfo result = EnsureLabel(node); result.Reference(_labelBlock); return result; } private LabelInfo DefineLabel(LabelTarget node) { if (node == null) { return new LabelInfo(_ilg, null, false); } LabelInfo result = EnsureLabel(node); result.Define(_labelBlock); return result; } private void PushLabelBlock(LabelScopeKind type) { _labelBlock = new LabelScopeInfo(_labelBlock, type); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "kind")] private void PopLabelBlock(LabelScopeKind kind) { Debug.Assert(_labelBlock != null && _labelBlock.Kind == kind); _labelBlock = _labelBlock.Parent; } private void EmitLabelExpression(Expression expr, CompilationFlags flags) { var node = (LabelExpression)expr; Debug.Assert(node.Target != null); // If we're an immediate child of a block, our label will already // be defined. If not, we need to define our own block so this // label isn't exposed except to its own child expression. LabelInfo label = null; if (_labelBlock.Kind == LabelScopeKind.Block) { _labelBlock.TryGetLabelInfo(node.Target, out label); // We're in a block but didn't find our label, try switch if (label == null && _labelBlock.Parent.Kind == LabelScopeKind.Switch) { _labelBlock.Parent.TryGetLabelInfo(node.Target, out label); } // if we're in a switch or block, we should've found the label Debug.Assert(label != null); } if (label == null) { label = DefineLabel(node.Target); } if (node.DefaultValue != null) { if (node.Target.Type == typeof(void)) { EmitExpressionAsVoid(node.DefaultValue, flags); } else { flags = UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart); EmitExpression(node.DefaultValue, flags); } } label.Mark(); } private void EmitGotoExpression(Expression expr, CompilationFlags flags) { var node = (GotoExpression)expr; var labelInfo = ReferenceLabel(node.Target); var tailCall = flags & CompilationFlags.EmitAsTailCallMask; if (tailCall != CompilationFlags.EmitAsNoTail) { // Since tail call flags are not passed into EmitTryExpression, CanReturn // means the goto will be emitted as Ret. Therefore we can emit the goto's // default value with tail call. This can be improved by detecting if the // target label is equivalent to the return label. tailCall = labelInfo.CanReturn ? CompilationFlags.EmitAsTail : CompilationFlags.EmitAsNoTail; flags = UpdateEmitAsTailCallFlag(flags, tailCall); } if (node.Value != null) { if (node.Target.Type == typeof(void)) { EmitExpressionAsVoid(node.Value, flags); } else { flags = UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart); EmitExpression(node.Value, flags); } } labelInfo.EmitJump(); EmitUnreachable(node, flags); } // We need to push default(T), unless we're emitting ourselves as // void. Even though the code is unreachable, we still have to // generate correct IL. We can get rid of this once we have better // reachability analysis. private void EmitUnreachable(Expression node, CompilationFlags flags) { if (node.Type != typeof(void) && (flags & CompilationFlags.EmitAsVoidType) == 0) { _ilg.EmitDefault(node.Type); } } private bool TryPushLabelBlock(Expression node) { // Anything that is "statement-like" -- e.g. has no associated // stack state can be jumped into, with the exception of try-blocks // We indicate this by a "Block" // // Otherwise, we push an "Expression" to indicate that it can't be // jumped into switch (node.NodeType) { default: if (_labelBlock.Kind != LabelScopeKind.Expression) { PushLabelBlock(LabelScopeKind.Expression); return true; } return false; case ExpressionType.Label: // LabelExpression is a bit special, if it's directly in a // block it becomes associate with the block's scope. Same // thing if it's in a switch case body. if (_labelBlock.Kind == LabelScopeKind.Block) { var label = ((LabelExpression)node).Target; if (_labelBlock.ContainsTarget(label)) { return false; } if (_labelBlock.Parent.Kind == LabelScopeKind.Switch && _labelBlock.Parent.ContainsTarget(label)) { return false; } } PushLabelBlock(LabelScopeKind.Statement); return true; case ExpressionType.Block: if (node is SpilledExpressionBlock) { // treat it as an expression goto default; } PushLabelBlock(LabelScopeKind.Block); // Labels defined immediately in the block are valid for // the whole block. if (_labelBlock.Parent.Kind != LabelScopeKind.Switch) { DefineBlockLabels(node); } return true; case ExpressionType.Switch: PushLabelBlock(LabelScopeKind.Switch); // Define labels inside of the switch cases so theyare in // scope for the whole switch. This allows "goto case" and // "goto default" to be considered as local jumps. var @switch = (SwitchExpression)node; foreach (SwitchCase c in @switch.Cases) { DefineBlockLabels(c.Body); } DefineBlockLabels(@switch.DefaultBody); return true; // Remove this when Convert(Void) goes away. case ExpressionType.Convert: if (node.Type != typeof(void)) { // treat it as an expression goto default; } PushLabelBlock(LabelScopeKind.Statement); return true; case ExpressionType.Conditional: case ExpressionType.Loop: case ExpressionType.Goto: PushLabelBlock(LabelScopeKind.Statement); return true; } } private void DefineBlockLabels(Expression node) { var block = node as BlockExpression; if (block == null || block is SpilledExpressionBlock) { return; } for (int i = 0, n = block.ExpressionCount; i < n; i++) { Expression e = block.GetExpression(i); var label = e as LabelExpression; if (label != null) { DefineLabel(label.Target); } } } // See if this lambda has a return label // If so, we'll create it now and mark it as allowing the "ret" opcode // This allows us to generate better IL private void AddReturnLabel(LambdaExpression lambda) { var expression = lambda.Body; while (true) { switch (expression.NodeType) { default: // Didn't find return label return; case ExpressionType.Label: // Found the label. We can directly return from this place // only if the label type is reference assignable to the lambda return type. var label = ((LabelExpression)expression).Target; _labelInfo.Add(label, new LabelInfo(_ilg, label, TypeUtils.AreReferenceAssignable(lambda.ReturnType, label.Type))); return; case ExpressionType.Block: // Look in the last significant expression of a block var body = (BlockExpression)expression; // omit empty and debuginfo at the end of the block since they // are not going to emit any IL for (int i = body.ExpressionCount - 1; i >= 0; i--) { expression = body.GetExpression(i); if (Significant(expression)) { break; } } continue; } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- LabelAutomationPeer.cs
- XmlAtomErrorReader.cs
- mda.cs
- DiscriminatorMap.cs
- SQLDecimalStorage.cs
- HttpCacheParams.cs
- PipeStream.cs
- MinimizableAttributeTypeConverter.cs
- TextTreeInsertElementUndoUnit.cs
- NativeConfigurationLoader.cs
- FormsAuthenticationEventArgs.cs
- FieldAccessException.cs
- MemberHolder.cs
- IPHostEntry.cs
- DocumentXPathNavigator.cs
- TemplateControlCodeDomTreeGenerator.cs
- AssociationEndMember.cs
- MetadataArtifactLoaderResource.cs
- xdrvalidator.cs
- Error.cs
- ValueType.cs
- ThemeDictionaryExtension.cs
- InkPresenter.cs
- FunctionCommandText.cs
- TextDecorationUnitValidation.cs
- XPathDescendantIterator.cs
- RouteParameter.cs
- UIntPtr.cs
- TabControl.cs
- HitTestFilterBehavior.cs
- CompiledELinqQueryState.cs
- ForceCopyBuildProvider.cs
- PluralizationService.cs
- EntityCommandDefinition.cs
- FrameworkContentElementAutomationPeer.cs
- InvalidDocumentContentsException.cs
- ScriptControlManager.cs
- ClientConvert.cs
- DirectoryNotFoundException.cs
- IProducerConsumerCollection.cs
- Stream.cs
- IdentifierService.cs
- SystemKeyConverter.cs
- PatternMatcher.cs
- AssemblyCacheEntry.cs
- HttpCacheVaryByContentEncodings.cs
- FileResponseElement.cs
- RandomDelaySendsAsyncResult.cs
- _LocalDataStore.cs
- _HelperAsyncResults.cs
- XmlSerializationReader.cs
- CopyNamespacesAction.cs
- CodeTypeMember.cs
- RectangleGeometry.cs
- SmtpSpecifiedPickupDirectoryElement.cs
- SessionStateContainer.cs
- AnnotationMap.cs
- FormViewActionList.cs
- FunctionNode.cs
- SamlSerializer.cs
- UnsettableComboBox.cs
- PeerResolverBindingElement.cs
- ImageAnimator.cs
- BlurEffect.cs
- Overlapped.cs
- GridViewSortEventArgs.cs
- DataViewListener.cs
- HashAlgorithm.cs
- FrameworkContentElement.cs
- ISessionStateStore.cs
- QualifiedCellIdBoolean.cs
- LayoutTable.cs
- BitmapEffectGeneralTransform.cs
- GlyphElement.cs
- WebPartZone.cs
- TreeNodeCollection.cs
- TextEffect.cs
- FrameworkElement.cs
- UnmanagedBitmapWrapper.cs
- DockPatternIdentifiers.cs
- OleDbRowUpdatedEvent.cs
- ExecutionContext.cs
- RtfToXamlLexer.cs
- ColorIndependentAnimationStorage.cs
- AlignmentXValidation.cs
- XmlComplianceUtil.cs
- PngBitmapDecoder.cs
- HtmlTitle.cs
- ICspAsymmetricAlgorithm.cs
- TreeBuilder.cs
- EventToken.cs
- CapabilitiesSection.cs
- IndividualDeviceConfig.cs
- WebPartMenu.cs
- Bitmap.cs
- Attributes.cs
- Lease.cs
- Rotation3D.cs
- X509PeerCertificateAuthentication.cs
- BinaryOperationBinder.cs