Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / Microsoft / Scripting / Compiler / LambdaCompiler.Address.cs / 1305376 / LambdaCompiler.Address.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.Collections.Generic;
using System.Diagnostics;
using System.Dynamic.Utils;
using System.Reflection;
using System.Reflection.Emit;
namespace System.Linq.Expressions.Compiler {
partial class LambdaCompiler {
private void EmitAddress(Expression node, Type type) {
EmitAddress(node, type, CompilationFlags.EmitExpressionStart);
}
// We don't want "ref" parameters to modify values of expressions
// except where it would in IL: locals, args, fields, and array elements
// (Unbox is an exception, it's intended to emit a ref to the orignal
// boxed value)
private void EmitAddress(Expression node, Type type, CompilationFlags flags) {
Debug.Assert(node != null);
bool emitStart = (flags & CompilationFlags.EmitExpressionStartMask) == CompilationFlags.EmitExpressionStart;
CompilationFlags startEmitted = emitStart ? EmitExpressionStart(node) : CompilationFlags.EmitNoExpressionStart;
switch (node.NodeType) {
default:
EmitExpressionAddress(node, type);
break;
case ExpressionType.ArrayIndex:
AddressOf((BinaryExpression)node, type);
break;
case ExpressionType.Parameter:
AddressOf((ParameterExpression)node, type);
break;
case ExpressionType.MemberAccess:
AddressOf((MemberExpression)node, type);
break;
case ExpressionType.Unbox:
AddressOf((UnaryExpression)node, type);
break;
case ExpressionType.Call:
AddressOf((MethodCallExpression)node, type);
break;
case ExpressionType.Index:
AddressOf((IndexExpression)node, type);
break;
}
if (emitStart) {
EmitExpressionEnd(startEmitted);
}
}
private void AddressOf(BinaryExpression node, Type type) {
Debug.Assert(node.NodeType == ExpressionType.ArrayIndex && node.Method == null);
if (TypeUtils.AreEquivalent(type, node.Type)) {
EmitExpression(node.Left);
EmitExpression(node.Right);
Type rightType = node.Right.Type;
if (TypeUtils.IsNullableType(rightType)) {
LocalBuilder loc = GetLocal(rightType);
_ilg.Emit(OpCodes.Stloc, loc);
_ilg.Emit(OpCodes.Ldloca, loc);
_ilg.EmitGetValue(rightType);
FreeLocal(loc);
}
Type indexType = TypeUtils.GetNonNullableType(rightType);
if (indexType != typeof(int)) {
_ilg.EmitConvertToType(indexType, typeof(int), true);
}
_ilg.Emit(OpCodes.Ldelema, node.Type);
} else {
EmitExpressionAddress(node, type);
}
}
private void AddressOf(ParameterExpression node, Type type) {
if (TypeUtils.AreEquivalent(type, node.Type)) {
if (node.IsByRef) {
_scope.EmitGet(node);
} else {
_scope.EmitAddressOf(node);
}
} else {
EmitExpressionAddress(node, type);
}
}
private void AddressOf(MemberExpression node, Type type) {
if (TypeUtils.AreEquivalent(type, node.Type)) {
// emit "this", if any
Type objectType = null;
if (node.Expression != null) {
EmitInstance(node.Expression, objectType = node.Expression.Type);
}
EmitMemberAddress(node.Member, objectType);
} else {
EmitExpressionAddress(node, type);
}
}
// assumes the instance is already on the stack
private void EmitMemberAddress(MemberInfo member, Type objectType) {
if (member.MemberType == MemberTypes.Field) {
FieldInfo field = (FieldInfo)member;
// Verifiable code may not take the address of an init-only field.
// If we are asked to do so then get the value out of the field, stuff it
// into a local of the same type, and then take the address of the local.
// Typically this is what we want to do anyway; if we are saying
// Foo.bar.ToString() for a static value-typed field bar then we don't need
// the address of field bar to do the call. The address of a local which
// has the same value as bar is sufficient.
//
if (!field.IsLiteral && !field.IsInitOnly) {
_ilg.EmitFieldAddress(field);
return;
}
}
EmitMemberGet(member, objectType);
LocalBuilder temp = GetLocal(GetMemberType(member));
_ilg.Emit(OpCodes.Stloc, temp);
_ilg.Emit(OpCodes.Ldloca, temp);
}
private void AddressOf(MethodCallExpression node, Type type) {
// An array index of a multi-dimensional array is represented by a call to Array.Get,
// rather than having its own array-access node. This means that when we are trying to
// get the address of a member of a multi-dimensional array, we'll be trying to
// get the address of a Get method, and it will fail to do so. Instead, detect
// this situation and replace it with a call to the Address method.
if (!node.Method.IsStatic &&
node.Object.Type.IsArray &&
node.Method == node.Object.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance)) {
MethodInfo mi = node.Object.Type.GetMethod("Address", BindingFlags.Public | BindingFlags.Instance);
EmitMethodCall(node.Object, mi, node);
} else {
EmitExpressionAddress(node, type);
}
}
private void AddressOf(IndexExpression node, Type type) {
if (!TypeUtils.AreEquivalent(type, node.Type) || node.Indexer != null) {
EmitExpressionAddress(node, type);
return;
}
if (node.Arguments.Count == 1) {
EmitExpression(node.Object);
EmitExpression(node.Arguments[0]);
_ilg.Emit(OpCodes.Ldelema, node.Type);
} else {
var address = node.Object.Type.GetMethod("Address", BindingFlags.Public | BindingFlags.Instance);
EmitMethodCall(node.Object, address, node);
}
}
private void AddressOf(UnaryExpression node, Type type) {
Debug.Assert(node.NodeType == ExpressionType.Unbox);
Debug.Assert(type.IsValueType && !TypeUtils.IsNullableType(type));
// Unbox leaves a pointer to the boxed value on the stack
EmitExpression(node.Operand);
_ilg.Emit(OpCodes.Unbox, type);
}
private void EmitExpressionAddress(Expression node, Type type) {
Debug.Assert(TypeUtils.AreReferenceAssignable(type, node.Type));
EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
LocalBuilder tmp = GetLocal(type);
_ilg.Emit(OpCodes.Stloc, tmp);
_ilg.Emit(OpCodes.Ldloca, tmp);
}
// Emits the address of the expression, returning the write back if necessary
//
// For properties, we want to write back into the property if it's
// passed byref.
private WriteBack EmitAddressWriteBack(Expression node, Type type) {
CompilationFlags startEmitted = EmitExpressionStart(node);
WriteBack result = null;
if (TypeUtils.AreEquivalent(type, node.Type)) {
switch (node.NodeType) {
case ExpressionType.MemberAccess:
result = AddressOfWriteBack((MemberExpression)node);
break;
case ExpressionType.Index:
result = AddressOfWriteBack((IndexExpression)node);
break;
}
}
if (result == null) {
EmitAddress(node, type, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
}
EmitExpressionEnd(startEmitted);
return result;
}
private WriteBack AddressOfWriteBack(MemberExpression node) {
if (node.Member.MemberType != MemberTypes.Property || !((PropertyInfo)node.Member).CanWrite) {
return null;
}
// emit instance, if any
LocalBuilder instanceLocal = null;
Type instanceType = null;
if (node.Expression != null) {
EmitInstance(node.Expression, instanceType = node.Expression.Type);
// store in local
_ilg.Emit(OpCodes.Dup);
_ilg.Emit(OpCodes.Stloc, instanceLocal = GetLocal(instanceType));
}
PropertyInfo pi = (PropertyInfo)node.Member;
// emit the get
EmitCall(instanceType, pi.GetGetMethod(true));
// emit the address of the value
var valueLocal = GetLocal(node.Type);
_ilg.Emit(OpCodes.Stloc, valueLocal);
_ilg.Emit(OpCodes.Ldloca, valueLocal);
// Set the property after the method call
// don't re-evaluate anything
return delegate() {
if (instanceLocal != null) {
_ilg.Emit(OpCodes.Ldloc, instanceLocal);
FreeLocal(instanceLocal);
}
_ilg.Emit(OpCodes.Ldloc, valueLocal);
FreeLocal(valueLocal);
EmitCall(instanceType, pi.GetSetMethod(true));
};
}
private WriteBack AddressOfWriteBack(IndexExpression node) {
if (node.Indexer == null || !node.Indexer.CanWrite) {
return null;
}
// emit instance, if any
LocalBuilder instanceLocal = null;
Type instanceType = null;
if (node.Object != null) {
EmitInstance(node.Object, instanceType = node.Object.Type);
_ilg.Emit(OpCodes.Dup);
_ilg.Emit(OpCodes.Stloc, instanceLocal = GetLocal(instanceType));
}
// Emit indexes. We don't allow byref args, so no need to worry
// about writebacks or EmitAddress
List args = new List();
foreach (var arg in node.Arguments) {
EmitExpression(arg);
var argLocal = GetLocal(arg.Type);
_ilg.Emit(OpCodes.Dup);
_ilg.Emit(OpCodes.Stloc, argLocal);
args.Add(argLocal);
}
// emit the get
EmitGetIndexCall(node, instanceType);
// emit the address of the value
var valueLocal = GetLocal(node.Type);
_ilg.Emit(OpCodes.Stloc, valueLocal);
_ilg.Emit(OpCodes.Ldloca, valueLocal);
// Set the property after the method call
// don't re-evaluate anything
return delegate() {
if (instanceLocal != null) {
_ilg.Emit(OpCodes.Ldloc, instanceLocal);
FreeLocal(instanceLocal);
}
foreach (var arg in args) {
_ilg.Emit(OpCodes.Ldloc, arg);
FreeLocal(arg);
}
_ilg.Emit(OpCodes.Ldloc, valueLocal);
FreeLocal(valueLocal);
EmitSetIndexCall(node, instanceType);
};
}
}
}
// 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
- SectionUpdates.cs
- SafeNativeMethods.cs
- Assert.cs
- ProvidersHelper.cs
- ResolveNameEventArgs.cs
- SignedXmlDebugLog.cs
- SettingsPropertyValueCollection.cs
- StatusBarAutomationPeer.cs
- Logging.cs
- SqlMethods.cs
- LinearGradientBrush.cs
- TimelineClockCollection.cs
- ObjectDataSourceStatusEventArgs.cs
- TranslateTransform.cs
- ResourcePermissionBase.cs
- DataRowExtensions.cs
- FixedDocument.cs
- Helper.cs
- ImageMetadata.cs
- IdnMapping.cs
- RNGCryptoServiceProvider.cs
- TypefaceCollection.cs
- DecoderBestFitFallback.cs
- Int32Animation.cs
- CellLabel.cs
- XmlArrayAttribute.cs
- SQLInt64.cs
- DataGridComponentEditor.cs
- TempFiles.cs
- embossbitmapeffect.cs
- ListViewItem.cs
- DoubleAnimation.cs
- FixedSOMPageElement.cs
- DrawingCollection.cs
- IncomingWebRequestContext.cs
- XhtmlConformanceSection.cs
- DbBuffer.cs
- DelayedRegex.cs
- ToolStripGripRenderEventArgs.cs
- SmiTypedGetterSetter.cs
- InternalDispatchObject.cs
- NotificationContext.cs
- FormatterServices.cs
- ImageFormatConverter.cs
- ExpandSegment.cs
- ComUdtElement.cs
- OutOfProcStateClientManager.cs
- _TLSstream.cs
- ConstraintEnumerator.cs
- TypeBuilder.cs
- QueryOperatorEnumerator.cs
- HyperLinkField.cs
- ServiceDefaults.cs
- FileUtil.cs
- PageOutputQuality.cs
- SlotInfo.cs
- EntityDataSourceReferenceGroup.cs
- EncoderExceptionFallback.cs
- SettingsBindableAttribute.cs
- WindowsGraphicsWrapper.cs
- LocatorManager.cs
- AssertSection.cs
- DataViewManagerListItemTypeDescriptor.cs
- HttpPostClientProtocol.cs
- SystemColors.cs
- Ipv6Element.cs
- DesignerRegionCollection.cs
- Decoder.cs
- LateBoundBitmapDecoder.cs
- EventLogWatcher.cs
- FormsAuthenticationUserCollection.cs
- MenuItemStyle.cs
- GeometryDrawing.cs
- CustomErrorCollection.cs
- PeerResolverElement.cs
- TextDecorationCollectionConverter.cs
- ServiceHttpHandlerFactory.cs
- WebPartManager.cs
- SafeEventLogReadHandle.cs
- ExpressionBuilder.cs
- ContextBase.cs
- PointAnimationClockResource.cs
- WindowsRichEditRange.cs
- ObjectDataSourceStatusEventArgs.cs
- Light.cs
- HostExecutionContextManager.cs
- propertytag.cs
- MatrixCamera.cs
- DocumentSchemaValidator.cs
- MediaTimeline.cs
- SoapDocumentMethodAttribute.cs
- DBSqlParser.cs
- DesignerContextDescriptor.cs
- SamlAuthenticationClaimResource.cs
- TypeSystem.cs
- VerticalAlignConverter.cs
- Encoding.cs
- GridViewSortEventArgs.cs
- SBCSCodePageEncoding.cs
- HtmlTable.cs