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
- AdCreatedEventArgs.cs
- XmlCollation.cs
- EntityCollectionChangedParams.cs
- BufferModesCollection.cs
- RepeaterCommandEventArgs.cs
- WebConvert.cs
- DesignerView.Commands.cs
- CurrentChangingEventArgs.cs
- BaseCollection.cs
- ListBoxItem.cs
- ProviderUtil.cs
- Evidence.cs
- JumpItem.cs
- NavigatorInput.cs
- SplineQuaternionKeyFrame.cs
- BindingSource.cs
- MonthChangedEventArgs.cs
- PrivilegeNotHeldException.cs
- MarginsConverter.cs
- CheckBoxFlatAdapter.cs
- ExtensionCollection.cs
- MenuCommandsChangedEventArgs.cs
- FixedTextPointer.cs
- EntityDataSourceView.cs
- CollectionTypeElement.cs
- AdjustableArrowCap.cs
- SimpleType.cs
- LoginCancelEventArgs.cs
- basenumberconverter.cs
- Int32CollectionConverter.cs
- VectorAnimation.cs
- SiteMapNode.cs
- LoginView.cs
- AttachedPropertyBrowsableWhenAttributePresentAttribute.cs
- PointLight.cs
- WorkflowInstance.cs
- IsolatedStorageFileStream.cs
- ResourceDescriptionAttribute.cs
- EmptyQuery.cs
- Soap12ServerProtocol.cs
- HtmlContainerControl.cs
- SchemaImporterExtensionElementCollection.cs
- _AutoWebProxyScriptHelper.cs
- Configuration.cs
- PathFigure.cs
- WindowsPen.cs
- PeerCollaborationPermission.cs
- DbTransaction.cs
- DataFormats.cs
- SqlInfoMessageEvent.cs
- Trace.cs
- ActivityExecutionContextCollection.cs
- DescriptionAttribute.cs
- DoubleAnimation.cs
- ReadOnlyHierarchicalDataSource.cs
- ProcessActivityTreeOptions.cs
- BuildProvider.cs
- TreeNodeStyleCollection.cs
- WindowCollection.cs
- AliasedSlot.cs
- Deflater.cs
- WeakReferenceList.cs
- PrintDocument.cs
- SerializationException.cs
- SharedHttpsTransportManager.cs
- Misc.cs
- PackageRelationshipSelector.cs
- BindStream.cs
- ComponentManagerBroker.cs
- PeerInvitationResponse.cs
- BlurEffect.cs
- TrackingProfileCache.cs
- OleDbStruct.cs
- Point.cs
- CapabilitiesAssignment.cs
- DefaultTypeArgumentAttribute.cs
- PageAdapter.cs
- EncoderParameter.cs
- Win32.cs
- TextMarkerSource.cs
- TransformerTypeCollection.cs
- OutputScopeManager.cs
- MessageQueueAccessControlEntry.cs
- AnonymousIdentificationModule.cs
- TransactionalPackage.cs
- LocalFileSettingsProvider.cs
- TargetParameterCountException.cs
- NamedPermissionSet.cs
- Itemizer.cs
- NotifyIcon.cs
- XmlBaseWriter.cs
- CrossAppDomainChannel.cs
- XmlText.cs
- CharEntityEncoderFallback.cs
- WebPartMinimizeVerb.cs
- RectangleF.cs
- TagMapInfo.cs
- XmlUrlResolver.cs
- HostedNamedPipeTransportManager.cs
- Model3DCollection.cs