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
- DockPattern.cs
- FixedStringLookup.cs
- BaseServiceProvider.cs
- EntityTemplateUserControl.cs
- GridToolTip.cs
- DataSourceIDConverter.cs
- SHA1.cs
- CursorConverter.cs
- ViewKeyConstraint.cs
- CompilerErrorCollection.cs
- PropertyDescriptorComparer.cs
- TransactionManager.cs
- UpDownEvent.cs
- KnownColorTable.cs
- OrderedHashRepartitionStream.cs
- VectorConverter.cs
- HttpHeaderCollection.cs
- MSAAWinEventWrap.cs
- BidOverLoads.cs
- SoapIgnoreAttribute.cs
- SinglePageViewer.cs
- HashAlgorithm.cs
- TextEvent.cs
- RoleGroupCollection.cs
- DataGridViewRowsRemovedEventArgs.cs
- ToolStripPanelRow.cs
- SpecialNameAttribute.cs
- HtmlTextArea.cs
- HotCommands.cs
- InkPresenter.cs
- SiteMapDataSourceView.cs
- UIElementCollection.cs
- WeakEventManager.cs
- ComContractElementCollection.cs
- XslNumber.cs
- HebrewCalendar.cs
- DataViewManagerListItemTypeDescriptor.cs
- ExpressionServices.cs
- NameValuePair.cs
- OperationFormatUse.cs
- XmlMapping.cs
- QueryReaderSettings.cs
- XDeferredAxisSource.cs
- AlignmentXValidation.cs
- ProjectionRewriter.cs
- DoubleCollection.cs
- ApplicationActivator.cs
- UpDownEvent.cs
- IncrementalReadDecoders.cs
- DashStyle.cs
- SqlNamer.cs
- WebPartEditorCancelVerb.cs
- WebPartEditorApplyVerb.cs
- StreamSecurityUpgradeAcceptorBase.cs
- Attributes.cs
- EdmFunction.cs
- RegexGroup.cs
- Graphics.cs
- HtmlElementCollection.cs
- Separator.cs
- PtsHost.cs
- TemplateKeyConverter.cs
- EventRouteFactory.cs
- Pointer.cs
- DrawListViewColumnHeaderEventArgs.cs
- TraceHandlerErrorFormatter.cs
- SiblingIterators.cs
- ChangeToolStripParentVerb.cs
- AudioStateChangedEventArgs.cs
- WebPartEditVerb.cs
- IsolatedStorageException.cs
- WebDescriptionAttribute.cs
- EventLog.cs
- XmlWriter.cs
- AssemblyAssociatedContentFileAttribute.cs
- TimeoutException.cs
- DataError.cs
- SqlWorkflowInstanceStoreLock.cs
- MethodAccessException.cs
- Publisher.cs
- FlowPosition.cs
- ClickablePoint.cs
- WebServiceErrorEvent.cs
- TextShapeableCharacters.cs
- SQLBytesStorage.cs
- PersonalizableTypeEntry.cs
- FloaterBaseParagraph.cs
- Perspective.cs
- BamlRecordWriter.cs
- WindowsStatusBar.cs
- RewritingPass.cs
- XmlStringTable.cs
- XPathPatternBuilder.cs
- Util.cs
- ModelTreeEnumerator.cs
- DateTimeFormat.cs
- RouteParametersHelper.cs
- SystemUdpStatistics.cs
- XpsDigitalSignature.cs
- ComponentConverter.cs