/Dependencies/boo/src/Boo.Lang.Compiler/Steps/EmitAssembly.cs
C# | 5083 lines | 4246 code | 661 blank | 176 comment | 657 complexity | 3e45febc9971fe9c8c2caf56aeaa552b MD5 | raw file
Possible License(s): GPL-2.0
Large files files are truncated, but you can click here to view the full file
- #region license
- // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without modification,
- // are permitted provided that the following conditions are met:
- //
- // * Redistributions of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- // * Neither the name of Rodrigo B. de Oliveira nor the names of its
- // contributors may be used to endorse or promote products derived from this
- // software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- #endregion
- using System;
- using System.Collections;
- using System.Diagnostics;
- using System.Diagnostics.SymbolStore;
- using System.IO;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Resources;
- using System.Text;
- using System.Text.RegularExpressions;
- using System.Threading;
- using Boo.Lang.Compiler.Ast;
- using Boo.Lang.Compiler.TypeSystem;
- using Boo.Lang.Runtime;
- using Attribute = Boo.Lang.Compiler.Ast.Attribute;
- using Module = Boo.Lang.Compiler.Ast.Module;
- namespace Boo.Lang.Compiler.Steps
- {
- class LoopInfo
- {
- public Label BreakLabel;
-
- public Label ContinueLabel;
-
- public int TryBlockDepth;
-
- public LoopInfo(Label breakLabel, Label continueLabel, int tryBlockDepth)
- {
- BreakLabel = breakLabel;
- ContinueLabel = continueLabel;
- TryBlockDepth = tryBlockDepth;
- }
- }
-
- public class EmitAssembly : AbstractVisitorCompilerStep
- {
- static ConstructorInfo DebuggableAttribute_Constructor = typeof(DebuggableAttribute).GetConstructor(new Type[] { Types.Bool, Types.Bool });
-
- static ConstructorInfo RuntimeCompatibilityAttribute_Constructor = typeof(System.Runtime.CompilerServices.RuntimeCompatibilityAttribute).GetConstructor(new Type[0]);
-
- static PropertyInfo[] RuntimeCompatibilityAttribute_Property = new PropertyInfo[] { typeof(System.Runtime.CompilerServices.RuntimeCompatibilityAttribute).GetProperty("WrapNonExceptionThrows") };
- static ConstructorInfo DuckTypedAttribute_Constructor = Types.DuckTypedAttribute.GetConstructor(new Type[0]);
-
- static ConstructorInfo ParamArrayAttribute_Constructor = Types.ParamArrayAttribute.GetConstructor(new Type[0]);
-
- static MethodInfo RuntimeServices_NormalizeArrayIndex = Types.RuntimeServices.GetMethod("NormalizeArrayIndex");
-
- static MethodInfo RuntimeServices_ToBool_Object = Types.RuntimeServices.GetMethod("ToBool", new Type[] { Types.Object });
- static MethodInfo RuntimeServices_ToBool_Decimal = Types.RuntimeServices.GetMethod("ToBool", new Type[] { Types.Decimal });
-
- static MethodInfo RuntimeServices_ToBool_Single = Types.RuntimeServices.GetMethod("ToBool", new Type[] { Types.Single });
-
- static MethodInfo RuntimeServices_ToBool_Double = Types.RuntimeServices.GetMethod("ToBool", new Type[] { Types.Double });
- static MethodInfo Builtins_ArrayTypedConstructor = Types.Builtins.GetMethod("array", new Type[] { Types.Type, Types.Int });
-
- static MethodInfo Builtins_ArrayTypedCollectionConstructor = Types.Builtins.GetMethod("array", new Type[] { Types.Type, Types.ICollection });
-
- static MethodInfo Math_Pow = typeof(Math).GetMethod("Pow");
-
- static ConstructorInfo List_EmptyConstructor = Types.List.GetConstructor(Type.EmptyTypes);
-
- static ConstructorInfo List_ArrayBoolConstructor = Types.List.GetConstructor(new Type[] { Types.ObjectArray, Types.Bool });
-
- static ConstructorInfo Hash_Constructor = Types.Hash.GetConstructor(new Type[0]);
-
- static ConstructorInfo Regex_Constructor = typeof(Regex).GetConstructor(new Type[] { Types.String });
-
- static MethodInfo Hash_Add = Types.Hash.GetMethod("Add", new Type[] { typeof(object), typeof(object) });
-
- static ConstructorInfo TimeSpan_LongConstructor = Types.TimeSpan.GetConstructor(new Type[] { typeof(long) });
-
- static MethodInfo Type_GetTypeFromHandle = Types.Type.GetMethod("GetTypeFromHandle");
-
- AssemblyBuilder _asmBuilder;
-
- ModuleBuilder _moduleBuilder;
-
- Hashtable _symbolDocWriters = new Hashtable();
-
- // IL generation state
- ILGenerator _il;
- Label _returnLabel; // current label for method return
- LocalBuilder _returnValueLocal; // returnValueLocal
- IType _returnType;
- int _tryBlock; // are we in a try block?
- bool _checked = true;
- bool _rawArrayIndexing = false;
- Hashtable _typeCache = new Hashtable();
-
- // keeps track of types on the IL stack
- Stack _types = new Stack();
-
- Stack _loopInfoStack = new Stack();
-
- AttributeCollection _assemblyAttributes = new AttributeCollection();
-
- LoopInfo _currentLoopInfo;
-
- void EnterLoop(Label breakLabel, Label continueLabel)
- {
- _loopInfoStack.Push(_currentLoopInfo);
- _currentLoopInfo = new LoopInfo(breakLabel, continueLabel, _tryBlock);
- }
-
- bool InTryInLoop()
- {
- return _tryBlock > _currentLoopInfo.TryBlockDepth;
- }
-
- void LeaveLoop()
- {
- _currentLoopInfo = (LoopInfo)_loopInfoStack.Pop();
- }
-
- void PushType(IType type)
- {
- _types.Push(type);
- }
-
- void PushBool()
- {
- PushType(TypeSystemServices.BoolType);
- }
-
- void PushVoid()
- {
- PushType(TypeSystemServices.VoidType);
- }
-
- IType PopType()
- {
- return (IType)_types.Pop();
- }
-
- IType PeekTypeOnStack()
- {
- return (IType)_types.Peek();
- }
-
- void AssertStackIsEmpty(string message)
- {
- if (0 != _types.Count)
- {
- throw new ApplicationException(
- string.Format("{0}: {1} items still on the stack.", message, _types.Count)
- );
- }
- }
-
- override public void Run()
- {
- if (Errors.Count > 0)
- {
- return;
- }
-
- GatherAssemblyAttributes();
- SetUpAssembly();
-
- DefineTypes();
-
- DefineResources();
- DefineAssemblyAttributes();
- DefineEntryPoint();
- }
-
- void GatherAssemblyAttributes()
- {
- foreach (Module module in CompileUnit.Modules)
- {
- foreach (Attribute attribute in module.AssemblyAttributes)
- {
- _assemblyAttributes.Add(attribute);
- }
- }
- }
-
- void DefineTypes()
- {
- if (CompileUnit.Modules.Count > 0)
- {
- List types = CollectTypes();
-
- foreach (TypeDefinition type in types)
- {
- DefineType(type);
- }
-
- foreach (TypeDefinition type in types)
- {
- DefineTypeMembers(type);
- }
-
- foreach (Module module in CompileUnit.Modules)
- {
- OnModule(module);
- }
-
- EmitAttributes();
- CreateTypes(types);
- }
- }
-
- class AttributeEmitVisitor : DepthFirstVisitor
- {
- EmitAssembly _emitter;
-
- public AttributeEmitVisitor(EmitAssembly emitter)
- {
- _emitter = emitter;
- }
-
- public override void OnField(Field node)
- {
- _emitter.EmitFieldAttributes(node);
- }
-
- public override void OnEnumMember(EnumMember node)
- {
- _emitter.EmitFieldAttributes(node);
- }
-
- public override void OnEvent(Event node)
- {
- _emitter.EmitEventAttributes(node);
- }
-
- public override void OnProperty(Property node)
- {
- Visit(node.Getter);
- Visit(node.Setter);
- _emitter.EmitPropertyAttributes(node);
- }
-
- public override void OnConstructor(Constructor node)
- {
- Visit(node.Parameters);
- _emitter.EmitConstructorAttributes(node);
- }
-
- public override void OnMethod(Method node)
- {
- Visit(node.Parameters);
- _emitter.EmitMethodAttributes(node);
- }
-
- public override void OnParameterDeclaration(ParameterDeclaration node)
- {
- _emitter.EmitParameterAttributes(node);
- }
-
- public override void LeaveClassDefinition(ClassDefinition node)
- {
- _emitter.EmitTypeAttributes(node);
- }
-
- public override void LeaveInterfaceDefinition(InterfaceDefinition node)
- {
- _emitter.EmitTypeAttributes(node);
- }
-
- public override void LeaveEnumDefinition(EnumDefinition node)
- {
- _emitter.EmitTypeAttributes(node);
- }
- }
-
- delegate void CustomAttributeSetter(CustomAttributeBuilder attribute);
-
- void EmitAttributes(INodeWithAttributes node, CustomAttributeSetter setCustomAttribute)
- {
- foreach (Attribute attribute in node.Attributes)
- {
- setCustomAttribute(GetCustomAttributeBuilder(attribute));
- }
- }
-
- void EmitPropertyAttributes(Property node)
- {
- PropertyBuilder builder = GetPropertyBuilder(node);
- EmitAttributes(node, new CustomAttributeSetter(builder.SetCustomAttribute));
- }
-
- void EmitParameterAttributes(ParameterDeclaration node)
- {
- ParameterBuilder builder = (ParameterBuilder)GetBuilder(node);
- EmitAttributes(node, new CustomAttributeSetter(builder.SetCustomAttribute));
- }
-
- void EmitEventAttributes(Event node)
- {
- EventBuilder builder = (EventBuilder)GetBuilder(node);
- EmitAttributes(node, new CustomAttributeSetter(builder.SetCustomAttribute));
- }
-
- void EmitConstructorAttributes(Constructor node)
- {
- ConstructorBuilder builder = (ConstructorBuilder)GetBuilder(node);
- EmitAttributes(node, new CustomAttributeSetter(builder.SetCustomAttribute));
- }
-
- void EmitMethodAttributes(Method node)
- {
- MethodBuilder builder = GetMethodBuilder(node);
- EmitAttributes(node, new CustomAttributeSetter(builder.SetCustomAttribute));
- }
-
- void EmitTypeAttributes(TypeDefinition node)
- {
- TypeBuilder builder = GetTypeBuilder(node);
- EmitAttributes(node, new CustomAttributeSetter(builder.SetCustomAttribute));
- }
-
- void EmitFieldAttributes(TypeMember node)
- {
- FieldBuilder builder = GetFieldBuilder(node);
- EmitAttributes(node, new CustomAttributeSetter(builder.SetCustomAttribute));
- }
-
- void EmitAttributes()
- {
- AttributeEmitVisitor visitor = new AttributeEmitVisitor(this);
- foreach (Module module in CompileUnit.Modules)
- {
- module.Accept(visitor);
- }
- }
-
- void CreateTypes(List types)
- {
- new TypeCreator(this, types).Run();
- }
-
- /// <summary>
- /// Ensures that all types are created in the correct order.
- /// </summary>
- class TypeCreator
- {
- EmitAssembly _emitter;
-
- Hashtable _created;
-
- List _types;
-
- TypeMember _current;
-
- public TypeCreator(EmitAssembly emitter, List types)
- {
- _emitter = emitter;
- _types = types;
- _created = new Hashtable();
- }
-
- public void Run()
- {
- ResolveEventHandler resolveHandler = new ResolveEventHandler(OnTypeResolve);
- AppDomain current = Thread.GetDomain();
-
- try
- {
- current.TypeResolve += resolveHandler;
- CreateTypes();
- }
- finally
- {
- current.TypeResolve -= resolveHandler;
- }
- }
-
- void CreateTypes()
- {
- foreach (TypeMember type in _types)
- {
- CreateType(type);
- }
- }
-
- void CreateType(TypeMember type)
- {
- if (!_created.ContainsKey(type))
- {
- TypeMember saved = _current;
- _current = type;
-
- _created.Add(type, type);
-
- Trace("creating type '{0}'", type);
-
- if (IsNestedType(type))
- {
- CreateType((TypeMember)type.ParentNode);
- }
-
- TypeDefinition typedef = type as TypeDefinition;
- if (null != typedef)
- {
- foreach (TypeReference baseTypeRef in typedef.BaseTypes)
- {
- IType baseType = _emitter.GetType(baseTypeRef);
-
- EnsureInternalDependency(baseType);
- // If base type is a constructed generic type, create any internal
- // parameters it might have
- if (baseType.ConstructedInfo != null)
- {
- foreach (IType argument in baseType.ConstructedInfo.GenericArguments)
- {
- EnsureInternalDependency(argument);
- }
- }
- }
- }
-
- _emitter.GetTypeBuilder(type).CreateType();
-
- Trace("type '{0}' successfully created", type);
-
- _current = saved;
- }
- }
-
- private void EnsureInternalDependency(IType type)
- {
- AbstractInternalType tag = type as AbstractInternalType;
- if (null != tag)
- {
- CreateType(tag.TypeDefinition);
- }
- else
- {
- GenericConstructedType gtag = type as GenericConstructedType;
- if(null != gtag)
- {
- EnsureInternalDependency(gtag.GenericDefinition);
- }
- }
- }
-
- bool IsNestedType(TypeMember type)
- {
- NodeType parent = type.ParentNode.NodeType;
- return (NodeType.ClassDefinition == parent) ||
- (NodeType.InterfaceDefinition == parent);
- }
-
- Assembly OnTypeResolve(object sender, ResolveEventArgs args)
- {
- Trace("OnTypeResolve('{0}') during '{1}' creation.", args.Name, _current);
-
- // TypeResolve is generated whenever a type
- // contains fields of a value type not created yet.
- // All we need to do is look for value type fields
- // and create them all.
- ClassDefinition classdef = _current as ClassDefinition;
- foreach (TypeMember member in classdef.Members)
- {
- if (NodeType.Field == member.NodeType)
- {
- AbstractInternalType type = _emitter.GetType(((Field)member).Type) as AbstractInternalType;
- if (type != null && type.IsValueType)
- {
- CreateType(type.TypeDefinition);
- }
- }
- }
- return _emitter._asmBuilder;
- }
-
- void Trace(string format, params object[] args)
- {
- _emitter.Context.TraceVerbose(format, args);
- }
- }
-
- List CollectTypes()
- {
- List types = new List();
- foreach (Module module in CompileUnit.Modules)
- {
- CollectTypes(types, module.Members);
- }
- return types;
- }
-
- void CollectTypes(List types, TypeMemberCollection members)
- {
- foreach (TypeMember member in members)
- {
- switch (member.NodeType)
- {
- case NodeType.InterfaceDefinition:
- case NodeType.ClassDefinition:
- {
- types.Add(member);
- CollectTypes(types, ((TypeDefinition)member).Members);
- break;
- }
- case NodeType.EnumDefinition:
- {
- types.Add(member);
- break;
- }
- }
- }
- }
-
- override public void Dispose()
- {
- base.Dispose();
-
- _asmBuilder = null;
- _moduleBuilder = null;
- _symbolDocWriters.Clear();
- _il = null;
- _returnValueLocal = null;
- _returnType = null;
- _tryBlock = 0;
- _checked = true;
- _rawArrayIndexing = false;
- _types.Clear();
- _typeCache.Clear();
- _builders.Clear();
- _assemblyAttributes.Clear();
- }
-
- override public void OnAttribute(Attribute node)
- {
- }
-
- override public void OnModule(Module module)
- {
- Visit(module.Members);
- }
- override public void OnEnumDefinition(EnumDefinition node)
- {
- TypeBuilder builder = GetTypeBuilder(node);
- foreach (EnumMember member in node.Members)
- {
- FieldBuilder field = builder.DefineField(member.Name, builder,
- FieldAttributes.Public |
- FieldAttributes.Static |
- FieldAttributes.Literal);
- field.SetConstant((int)member.Initializer.Value);
- SetBuilder(member, field);
- }
- }
-
- override public void OnArrayTypeReference(ArrayTypeReference node)
- {
- }
-
- override public void OnClassDefinition(ClassDefinition node)
- {
- EmitTypeDefinition(node);
- }
-
- override public void OnField(Field node)
- {
- FieldBuilder builder = GetFieldBuilder(node);
- if (builder.IsLiteral)
- {
- builder.SetConstant(GetInternalFieldStaticValue((InternalField)node.Entity));
- }
- }
-
- override public void OnInterfaceDefinition(InterfaceDefinition node)
- {
- TypeBuilder builder = GetTypeBuilder(node);
- foreach (TypeReference baseType in node.BaseTypes)
- {
- builder.AddInterfaceImplementation(GetSystemType(baseType));
- }
- }
-
- override public void OnMacroStatement(MacroStatement node)
- {
- NotImplemented(node, "Unexpected macro: " + node.ToCodeString());
- }
-
- override public void OnCallableDefinition(CallableDefinition node)
- {
- NotImplemented(node, "Unexpected callable definition!");
- }
-
- void EmitTypeDefinition(TypeDefinition node)
- {
- TypeBuilder current = GetTypeBuilder(node);
- EmitBaseTypesAndAttributes(node, current);
- Visit(node.Members);
- }
-
- override public void OnMethod(Method method)
- {
- if (method.IsRuntime) return;
- if (IsPInvoke(method)) return;
-
- MethodBuilder methodBuilder = GetMethodBuilder(method);
- if (null != method.ExplicitInfo)
- {
- IMethod ifaceMethod = (IMethod)method.ExplicitInfo.Entity;
- MethodInfo ifaceInfo = GetMethodInfo(ifaceMethod);
- MethodInfo implInfo = GetMethodInfo((IMethod)method.Entity);
- TypeBuilder typeBuilder = GetTypeBuilder(method.DeclaringType);
- typeBuilder.DefineMethodOverride(implInfo, ifaceInfo);
- }
- EmitMethod(method, methodBuilder.GetILGenerator());
- }
-
- void EmitMethod(Method method, ILGenerator generator)
- {
- _il = generator;
-
- DefineLabels(method);
- Visit(method.Locals);
-
- BeginMethodBody(GetEntity(method).ReturnType);
- Visit(method.Body);
- EndMethodBody();
- }
-
- void BeginMethodBody(IType returnType)
- {
- _returnType = returnType;
- _returnLabel = _il.DefineLabel();
- if (TypeSystemServices.VoidType != _returnType)
- {
- _returnValueLocal = _il.DeclareLocal(GetSystemType(_returnType));
- }
- }
-
- void EndMethodBody()
- {
- _il.MarkLabel(_returnLabel);
- if (null != _returnValueLocal)
- {
- _il.Emit(OpCodes.Ldloc, _returnValueLocal);
- _returnValueLocal = null;
- }
- _il.Emit(OpCodes.Ret);
- }
- private bool IsPInvoke(Method method)
- {
- return GetEntity(method).IsPInvoke;
- }
- override public void OnBlock(Block block)
- {
- bool currentChecked = _checked;
- _checked = AstAnnotations.IsChecked(block, Parameters.Checked);
-
- bool currentArrayIndexing = _rawArrayIndexing;
- _rawArrayIndexing = AstAnnotations.IsRawIndexing(block);
- Visit(block.Statements);
- _rawArrayIndexing = currentArrayIndexing;
- _checked = currentChecked;
- }
- void DefineLabels(Method method)
- {
- foreach (InternalLabel label in ((InternalMethod)method.Entity).Labels)
- {
- label.Label = _il.DefineLabel();
- }
- }
-
- override public void OnConstructor(Constructor constructor)
- {
- if (constructor.IsRuntime) return;
-
- ConstructorBuilder builder = GetConstructorBuilder(constructor);
- EmitMethod(constructor, builder.GetILGenerator());
- }
-
- override public void OnLocal(Local local)
- {
- InternalLocal info = GetInternalLocal(local);
- info.LocalBuilder = _il.DeclareLocal(GetSystemType(local));
- if (Parameters.Debug)
- {
- info.LocalBuilder.SetLocalSymInfo(local.Name);
- }
- }
-
- override public void OnForStatement(ForStatement node)
- {
- NotImplemented("ForStatement");
- }
-
- override public void OnReturnStatement(ReturnStatement node)
- {
- EmitDebugInfo(node);
- OpCode retOpCode = _tryBlock > 0 ? OpCodes.Leave : OpCodes.Br;
-
- if (null != node.Expression)
- {
- Visit(node.Expression);
- EmitCastIfNeeded(_returnType, PopType());
- _il.Emit(OpCodes.Stloc, _returnValueLocal);
- }
- _il.Emit(retOpCode, _returnLabel);
- }
-
- override public void OnRaiseStatement(RaiseStatement node)
- {
- EmitDebugInfo(node);
- if (node.Exception == null)
- {
- _il.Emit(OpCodes.Rethrow);
- }
- else
- {
- Visit(node.Exception); PopType();
- _il.Emit(OpCodes.Throw);
- }
- }
- override public void OnTryStatement(TryStatement node)
- {
- ++_tryBlock;
- Label end = _il.BeginExceptionBlock();
-
- // The fault handler isn't very well supported by the
- // the ILGenerator. Thus, when there is a failure block
- // in the same try as an except or ensure block, we
- // need to do some special brute forcing with the exception
- // block context in the ILGenerator.
- if(null != node.FailureBlock && null != node.EnsureBlock)
- {
- ++_tryBlock;
- _il.BeginExceptionBlock();
- }
- if(null != node.FailureBlock && node.ExceptionHandlers.Count > 0)
- {
- ++_tryBlock;
- _il.BeginExceptionBlock();
- }
- Visit(node.ProtectedBlock);
-
- Visit(node.ExceptionHandlers);
- if(null != node.FailureBlock)
- {
- // Logic to back out of the manually forced blocks
- if(node.ExceptionHandlers.Count > 0)
- {
- _il.EndExceptionBlock();
- --_tryBlock;
- }
-
- _il.BeginFaultBlock();
- Visit(node.FailureBlock);
-
- // Logic to back out of the manually forced blocks once more
- if(null != node.EnsureBlock)
- {
- _il.EndExceptionBlock();
- --_tryBlock;
- }
- }
-
- if (null != node.EnsureBlock)
- {
- _il.BeginFinallyBlock();
- Visit(node.EnsureBlock);
- }
- _il.EndExceptionBlock();
- --_tryBlock;
- }
-
- override public void OnExceptionHandler(ExceptionHandler node)
- {
- if((node.Flags & ExceptionHandlerFlags.Filter) == ExceptionHandlerFlags.Filter)
- {
- _il.BeginExceptFilterBlock();
-
- Label endLabel = _il.DefineLabel();
-
- // If the filter is not untyped, then test the exception type
- // before testing the filter condition
- if((node.Flags & ExceptionHandlerFlags.Untyped) == ExceptionHandlerFlags.None)
- {
- Label filterCondition = _il.DefineLabel();
-
- // Test the type of the exception.
- _il.Emit(OpCodes.Isinst, GetSystemType(node.Declaration.Type));
-
- // Duplicate it. If it is null, then it will be used to
- // skip the filter.
- _il.Emit(OpCodes.Dup);
- // If the exception is of the right type, branch
- // to test the filter condition.
- _il.Emit(OpCodes.Brtrue, filterCondition);
- // Otherwise, clean up the stack and prepare the stack
- // to skip the filter.
- EmitStoreOrPopException(node);
-
- _il.Emit(OpCodes.Ldc_I4_0);
- _il.Emit(OpCodes.Br, endLabel);
- _il.MarkLabel(filterCondition);
- }
- else if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None)
- {
- // Cast the exception to the default except type
- _il.Emit(OpCodes.Isinst, GetSystemType(node.Declaration.Type));
- }
-
- EmitStoreOrPopException(node);
-
- // Test the condition and convert to boolean if needed.
- node.FilterCondition.Accept(this);
- PopType();
- EmitToBoolIfNeeded(node.FilterCondition);
-
- // If the type is right and the condition is true,
- // proceed with the handler.
- _il.MarkLabel(endLabel);
- _il.Emit(OpCodes.Ldc_I4_0);
- _il.Emit(OpCodes.Cgt_Un);
-
- _il.BeginCatchBlock(null);
- }
- else
- {
- // Begin a normal catch block of the appropriate type.
- _il.BeginCatchBlock(GetSystemType(node.Declaration.Type));
-
- // Clean up the stack or store the exception if not anonymous.
- EmitStoreOrPopException(node);
- }
- Visit(node.Block);
- }
-
- private void EmitStoreOrPopException(ExceptionHandler node)
- {
- if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None)
- {
- _il.Emit(OpCodes.Stloc, GetLocalBuilder(node.Declaration));
- }
- else
- {
- _il.Emit(OpCodes.Pop);
- }
- }
-
- override public void OnUnpackStatement(UnpackStatement node)
- {
- NotImplemented("Unpacking");
- }
-
- override public bool EnterExpressionStatement(ExpressionStatement node)
- {
- EmitDebugInfo(node);
- return true;
- }
-
- override public void LeaveExpressionStatement(ExpressionStatement node)
- {
- // if the type of the inner expression is not
- // void we need to pop its return value to leave
- // the stack sane
- DiscardValueOnStack();
- AssertStackIsEmpty("stack must be empty after a statement! Offending statement: '" + node.ToCodeString() + "'");
- }
-
- void DiscardValueOnStack()
- {
- if (PopType() != TypeSystemServices.VoidType)
- {
- _il.Emit(OpCodes.Pop);
- }
- }
-
- override public void OnUnlessStatement(UnlessStatement node)
- {
- Label endLabel = _il.DefineLabel();
- EmitDebugInfo(node);
- EmitBranchTrue(node.Condition, endLabel);
- node.Block.Accept(this);
- _il.MarkLabel(endLabel);
- }
-
- void OnSwitch(MethodInvocationExpression node)
- {
- ExpressionCollection args = node.Arguments;
- Visit(args[0]);
- EmitCastIfNeeded(TypeSystemServices.IntType, PopType());
-
- Label[] labels = new Label[args.Count-1];
- for (int i=0; i<labels.Length; ++i)
- {
- labels[i] = ((InternalLabel)args[i+1].Entity).Label;
- }
- _il.Emit(OpCodes.Switch, labels);
-
- PushVoid();
- }
-
- override public void OnGotoStatement(GotoStatement node)
- {
- EmitDebugInfo(node);
-
- InternalLabel label = (InternalLabel)GetEntity(node.Label);
- int gotoDepth = AstAnnotations.GetTryBlockDepth(node);
- int targetDepth = AstAnnotations.GetTryBlockDepth(label.LabelStatement);
-
- if (targetDepth == gotoDepth)
- {
- _il.Emit(OpCodes.Br, label.Label);
- }
- else
- {
- _il.Emit(OpCodes.Leave, label.Label);
- }
- }
-
- override public void OnLabelStatement(LabelStatement node)
- {
- EmitDebugInfo(node);
- _il.MarkLabel(((InternalLabel)node.Entity).Label);
- }
-
- override public void OnConditionalExpression(ConditionalExpression node)
- {
- IType type = GetExpressionType(node);
-
- Label endLabel = _il.DefineLabel();
-
- EmitBranchFalse(node.Condition, endLabel);
- node.TrueValue.Accept(this);
- EmitCastIfNeeded(type, PopType());
-
- Label elseEndLabel = _il.DefineLabel();
- _il.Emit(OpCodes.Br, elseEndLabel);
- _il.MarkLabel(endLabel);
-
- endLabel = elseEndLabel;
- node.FalseValue.Accept(this);
- EmitCastIfNeeded(type, PopType());
-
- _il.MarkLabel(endLabel);
-
- PushType(type);
- }
-
- override public void OnIfStatement(IfStatement node)
- {
- Label endLabel = _il.DefineLabel();
-
- EmitDebugInfo(node);
- EmitBranchFalse(node.Condition, endLabel);
-
- node.TrueBlock.Accept(this);
- if (null != node.FalseBlock)
- {
- Label elseEndLabel = _il.DefineLabel();
- _il.Emit(OpCodes.Br, elseEndLabel);
- _il.MarkLabel(endLabel);
-
- endLabel = elseEndLabel;
- node.FalseBlock.Accept(this);
- }
-
- _il.MarkLabel(endLabel);
- }
-
- void EmitBranchTrue(UnaryExpression expression, Label label)
- {
- if (UnaryOperatorType.LogicalNot == expression.Operator)
- {
- EmitBranchFalse(expression.Operand, label);
- }
- else
- {
- DefaultBranchTrue(expression, label);
- }
- }
-
- void EmitBranchTrue(BinaryExpression expression, Label label)
- {
- switch (expression.Operator)
- {
- case BinaryOperatorType.TypeTest:
- {
- EmitTypeTest(expression);
- _il.Emit(OpCodes.Brtrue, label);
- break;
- }
-
- case BinaryOperatorType.Or:
- {
- EmitBranchTrue(expression.Left, label);
- EmitBranchTrue(expression.Right, label);
- break;
- }
-
- case BinaryOperatorType.And:
- {
- Label skipRhs = _il.DefineLabel();
- EmitBranchFalse(expression.Left, skipRhs);
- EmitBranchTrue(expression.Right, label);
- _il.MarkLabel(skipRhs);
- break;
- }
-
- case BinaryOperatorType.Equality:
- {
- LoadCmpOperands(expression);
- _il.Emit(OpCodes.Beq, label);
- break;
- }
-
- case BinaryOperatorType.ReferenceEquality:
- {
- Visit(expression.Left); PopType();
- Visit(expression.Right); PopType();
- _il.Emit(OpCodes.Beq, label);
- break;
- }
-
- case BinaryOperatorType.ReferenceInequality:
- {
- if (IsNull(expression.Left))
- {
- EmitRawBranchTrue(expression.Right, label);
- break;
- }
- if (IsNull(expression.Right))
- {
- EmitRawBranchTrue(expression.Left, label);
- break;
- }
- Visit(expression.Left); PopType();
- Visit(expression.Right); PopType();
- _il.Emit(OpCodes.Ceq);
- _il.Emit(OpCodes.Brfalse, label);
- break;
- }
-
- case BinaryOperatorType.GreaterThan:
- {
- LoadCmpOperands(expression);
- _il.Emit(OpCodes.Bgt, label);
- break;
- }
-
- case BinaryOperatorType.GreaterThanOrEqual:
- {
- LoadCmpOperands(expression);
- _il.Emit(OpCodes.Bge, label);
- break;
- }
-
- case BinaryOperatorType.LessThan:
- {
- LoadCmpOperands(expression);
- _il.Emit(OpCodes.Blt, label);
- break;
- }
-
- case BinaryOperatorType.LessThanOrEqual:
- {
- LoadCmpOperands(expression);
- _il.Emit(OpCodes.Ble, label);
- break;
- }
-
- default:
- {
- DefaultBranchTrue(expression, label);
- break;
- }
- }
- }
-
- void EmitRawBranchTrue(Expression expression, Label label)
- {
- expression.Accept(this); PopType();
- _il.Emit(OpCodes.Brtrue, label);
- }
-
- void EmitBranchTrue(Expression expression, Label label)
- {
- switch (expression.NodeType)
- {
- case NodeType.BinaryExpression:
- {
- EmitBranchTrue((BinaryExpression)expression, label);
- break;
- }
-
- case NodeType.UnaryExpression:
- {
- EmitBranchTrue((UnaryExpression)expression, label);
- break;
- }
-
- default:
- {
- DefaultBranchTrue(expression, label);
- break;
- }
- }
- }
-
- void DefaultBranchTrue(Expression expression, Label label)
- {
- expression.Accept(this);
- IType type = PopType();
- if (TypeSystemServices.DoubleType == type)
- {
- _il.Emit(OpCodes.Ldc_R8, 0.0);
- _il.Emit(OpCodes.Bne_Un, label);
- }
- else if (TypeSystemServices.SingleType == type)
- {
- _il.Emit(OpCodes.Ldc_R4, 0.0f);
- _il.Emit(OpCodes.Bne_Un, label);
- }
- else
- {
- EmitToBoolIfNeeded(expression);
- _il.Emit(OpCodes.Brtrue, label);
- }
- }
-
- void EmitBranchFalse(BinaryExpression expression, Label label)
- {
- switch (expression.Operator)
- {
- case BinaryOperatorType.TypeTest:
- {
- EmitTypeTest(expression);
- _il.Emit(OpCodes.Brfalse, label);
- break;
- }
-
- case BinaryOperatorType.Or:
- {
- Label end = _il.DefineLabel();
- EmitBranchTrue(expression.Left, end);
- EmitBranchFalse(expression.Right, label);
- _il.MarkLabel(end);
- break;
- }
-
- case BinaryOperatorType.And:
- {
- EmitBranchFalse(expression.Left, label);
- EmitBranchFalse(expression.Right, label);
- break;
- }
- case BinaryOperatorType.Equality:
- {
- if (CanOptimizeAwayZeroOrFalseComparison(expression.Left, expression.Right))
- {
- EmitBranchTrue(expression.Right, label);
- }
- else if (CanOptimizeAwayZeroOrFalseComparison(expression.Right, expression.Left))
- {
- EmitBranchTrue(expression.Left, label);
- }
- else
- {
- DefaultBranchFalse(expression, label);
- }
- break;
- }
- case BinaryOperatorType.Inequality:
- {
- if (CanOptimizeAwayZeroOrFalseComparison(expression.Left, expression.Right))
- {
- EmitBranchFalse(expression.Right, label);
- }
- else if (CanOptimizeAwayZeroOrFalseComparison(expression.Right, expression.Left))
- {
- EmitBranchFalse(expression.Left, label);
- }
- else
- {
- DefaultBranchFalse(expression, label);
- }
- break;
- }
-
- default:
- {
- DefaultBranchFalse(expression, label);
- break;
- }
- }
- }
- private bool IsNull(Expression expression)
- {
- return NodeType.NullLiteralExpression == expression.NodeType;
- }
- private bool CanOptimizeAwayZeroOrFalseComparison(Expression expression, Expression operand)
- {
- return (IsZero(expression) || IsFalse(expression));
- }
- private bool IsFalse(Expression expression)
- {
- return NodeType.BoolLiteralExpression == expression.NodeType
- && (false == ((BoolLiteralExpression)expression).Value);
- }
- private bool IsZero(Expression expression)
- {
- return NodeType.IntegerLiteralExpression == expression.NodeType
- && (0 == ((IntegerLiteralExpression)expression).Value);
- }
- void EmitBranchFalse(Expression expression, Label label)
- {
- switch (expression.NodeType)
- {
- case NodeType.UnaryExpression:
- {
- EmitBranchFalse((UnaryExpression)expression, label);
- break;
- }
-
- case NodeType.BinaryExpression:
- {
- EmitBranchFalse((BinaryExpression)expression, label);
- break;
- }
-
- default:
- {
- DefaultBranchFalse(expression, label);
- break;
- }
- }
- }
-
- void EmitBranchFalse(UnaryExpression expression, Label label)
- {
- switch (expression.Operator)
- {
- case UnaryOperatorType.LogicalNot:
- {
- EmitBranchTrue(expression.Operand, label);
- break;
- }
-
- default:
- {
- DefaultBranchFalse(expression, label);
- break;
- }
- }
- }
-
- void DefaultBranchFalse(Expression expression, Label label)
- {
- expression.Accept(this);
- IType type = PopType();
- if (TypeSystemServices.DoubleType == type)
- {
- _il.Emit(OpCodes.Ldc_R8, (double)0.0);
- _il.Emit(OpCodes.Ceq);
- _il.Emit(OpCodes.Brtrue, label);
- }
- else if (TypeSystemServices.SingleType == type)
- {
- _il.Emit(OpCodes.Ldc_R4, (float)0.0);
- _il.Emit(OpCodes.Ceq);
- _il.Emit(OpCodes.Brtrue, label);
- }
- else
- {
- EmitToBoolIfNeeded(expression);
- _il.Emit(OpCodes.Brfalse, label);
- }
- }
-
- override public void OnBreakStatement(BreakStatement node)
- {
- EmitDebugInfo(node);
- if (InTryInLoop())
- {
- _il.Emit(OpCodes.Leave, _currentLoopInfo.BreakLabel);
- }
- else
- {
- _il.Emit(OpCodes.Br, _currentLoopInfo.BreakLabel);
- }
- }
-
- override public void OnContinueStatement(ContinueStatement node)
- {
- EmitDebugInfo(node);
- if (InTryInLoop())
- {
- _il.Emit(OpCodes.Leave, _currentLoopInfo.ContinueLabel);
- }
- else
- {
- _il.Emit(OpCodes.Br, _currentLoopInfo.ContinueLabel);
- }
- }
-
- override public void OnWhileStatement(WhileStatement node)
- {
- Label endLabel = _il.DefineLabel();
- Label bodyLabel = _il.DefineLabel();
- Label thenLabel = _il.DefineLabel();
- Label conditionLabel = _il.DefineLabel();
- LocalBuilder enteredLoop = null;
-
- if(null != node.OrBlock)
- {
- enteredLoop = _il.DeclareLocal(typeof(bool));
- _il.Emit(OpCodes.Ldc_I4_0);
- _il.Emit(OpCodes.Stloc, enteredLoop);
- }
-
- _il.Emit(OpCodes.Br, conditionLabel);
- _il.MarkLabel(bodyLabel);
-
- EnterLoop(endLabel, conditionLabel);
- if(null != node.OrBlock)
- {
- _il.Emit(OpCodes.Ldc_I4_1);
- _il.Emit(OpCodes.Stloc, enteredLoop);
- }
- node.Block.Accept(this);
- LeaveLoop();
-
- _il.MarkLabel(conditionLabel);
- EmitDebugInfo(node);
- EmitBranchTrue(node.Condition, bodyLabel);
- if(null != node.OrBlock)
- {
- _il.Emit(OpCodes.Ldloc, enteredLoop);
- _il.Emit(OpCodes.Brtrue, thenLabel);
- EnterLoop(endLabel, thenLabel);
- node.OrBlock.Accept(this);
- LeaveLoop();
- _il.MarkLabel(thenLabel);
- }
- if(null != node.ThenBlock)
- {
- node.ThenBlock.Accept(this);
- }
- _il.MarkLabel(endLabel);
- }
-
- void EmitIntNot()
- {
- _il.Emit(OpCodes.Ldc_I4_0);
- _il.Emit(OpCodes.Ceq);
- }
-
- void EmitGenericNot()
- {
- // bool codification:
- // value_on_stack ? 0 : 1
- Label wasTrue = _il.DefineLabel();
- Label wasFalse = _il.DefineLabel();
- _il.Emit(OpCodes.Brfalse, wasFalse);
- _il.Emit(OpCodes.Ldc_I4_0);
- _il.Emit(OpCodes.Br, wasTrue);
- _il.MarkLabel(wasFalse);
- _il.Emit(OpCodes.Ldc_I4_1);
- _il.MarkLabel(wasTrue);
- }
-
- override public void OnUnaryExpression(UnaryExpression node)
- {
- switch (node.Operator)
- {
- case UnaryOperatorType.LogicalNot:
- {
- EmitLogicalNot(node);
- break;
- }
-
- case UnaryOperatorType.UnaryNegation:
- {
- EmitUnaryNegation(node);
- break;
- }
- case UnaryOperatorType.OnesComplement:
- {
- EmitOnesComplement(node);
- break;
- }
-
- default:
- {
- NotImplemented(node, "unary operator not supported");
- break;
- }
- }
- }
- private void EmitOnesComplement(UnaryExpression node)
- {
- node.Operand.Accept(this);
- _il.Emit(OpCodes.Not);
- }
- private void EmitLogicalNot(UnaryExpression node)
- {
- Expression operand = node.Operand;
- operand.Accept(this);
- IType typeOnStack = PopType();
- if (IsBoolOrInt(typeOnStack) || EmitToBoolIfNeeded(operand))
- {
- EmitIntNot();
- }
- else
- {
- EmitGenericNot();
- }
- PushBool();
- }
- private void EmitUnaryNegation(UnaryExpression node)
- {
- node.Operand.Accept(this);
- IType type = PopType();
- _il.Emit(OpCodes.Ldc_I4, -1);
- EmitCastIfNeeded(type, TypeSystemServices.IntType);
- _il.Emit(OpCodes.Mul);
- PushType(type);
- }
- bool ShouldLeaveValueOnStack(Expression node)
- {
- return node.ParentNode.NodeType != NodeType.ExpressionStatement;
- }
-
- void OnReferenceComparison(BinaryExpression node)
- {
- node.Left.Accept(this); PopType();
- node.Right.Accept(this); PopType();
- _il.Emit(OpCodes.Ceq);
- if (BinaryOperatorType.ReferenceInequality == node.Operator)
- {
- EmitIntNot();
- }
- PushBool();
- }
-
- void OnAssignmentToSlice(BinaryExpression node)
- {
- SlicingExpression slice = (SlicingExpression)node.Left;
- Visit(slice.Target);
-
- IArrayType arrayType = (IArrayType)PopType();
- IType elementType = arrayType.GetElementType();
- OpCode opcode = GetStoreEntityOpCode(elementType);
-
- Slice index = slice.Indices[0];
- EmitNormalizedArrayIndex(slice, index.Begin);
-
- bool stobj = IsStobj(opcode);
- if (stobj)
- {
- _il.Emit(OpCodes.Ldelema, GetSystemType(elementType));
- }
-
- Visit(node.Right);
- EmitCastIfNeeded(elementType, PopType());
-
- bool leaveValueOnStack = ShouldLeaveValueOnStack(node);
- LocalBuilder temp = null;
- if (leaveValueOnStack)
- {
- _il.Emit(OpCodes.Dup);
- temp = StoreTempLocal(elementType);
- }
-
- if (stobj)
- {
- _il.Emit(opcode, GetSystemType(elementType));
- }
- else
- {
- _il.Emit(opcode);
- }
-
- if (leaveValueOnStack)
- {
- LoadLocal(temp, elementType);
- }
- else
- {
- PushVoid();
- }
- }
- private void LoadLocal(LocalBuilder local, IType localType)
- {
- _il.Emit(OpCodes.Ldloc, local);
- PushType(localType);
- }
- private LocalBuilder StoreTempLocal(IType elementType)
- {
- LocalBuilder temp;
- temp = _il.DeclareLocal(GetSystemType(elementType));
- _il.Emit(OpCodes.Stloc, temp);
- return temp;
- }
- void OnAssignment(BinaryExpression node)
- {
- if (NodeType.SlicingExpression == node.Left.NodeType)
- {
- OnAssignmentToSlice(node);
- return;
- }
-
- // when the parent is not a statement we need to leave
- // the value on the stack
- bool leaveValueOnStack = ShouldLeaveValueOnStack(node);
- IEntity tag = TypeSystemServices.GetEntity(node.Left);
- switch (tag.EntityType)
- {
- case EntityType.Local:
- {
- SetLocal(node, (InternalLocal)tag, leaveValueOnStack);
- break;
- }
-
- case EntityType.Parameter:
- {
- InternalParameter param = (InternalParameter)tag;
- if (param.Parameter.IsByRef)
- {
- SetByRefParam(param, node.Right, leaveValueOnStack);
- break;
- }
-
- Visit(node.Right);
- EmitCastIfNeeded(param.Type, PopType());
-
- if (leaveValueOnStack)
- {
- _il.Emit(OpCodes.Dup);
- PushType(param.Type);
- }
- _il.Emit(OpCodes.Starg, param.Index);
- break;
- }
-
- case EntityType.Field:
- {
- IField field = (IField)tag;
- SetField(node, field, node.Left, node.Right, leaveValueOnStack);
- break;
- }
-
- case EntityType.Property:
- {
- SetProperty(node, (IProperty)tag, node.Left, node.Right, leaveValueOnStack);
- break;
- }
-
- default:
- {
- NotImplemented(node, tag.ToString());
- break;
- }
- }
- if (!leaveValueOnStack)
- {
- PushVoid();
- }
- }
- private void SetByRefParam(InternalParameter param, Expression right, bool leaveValueOnStack)
- {
- LocalBuilder temp = null;
- IType tempType = null;
- if (leaveValueOnStack)
- {
- Visit(right);
- tempType = PopType();
- temp = StoreTempLocal(tempType);
- }
- LoadParam(param);
- if (temp != null)
- {
- LoadLocal(temp, tempType);
- }
- else
- {
- Visit(right);
- }
-
- EmitCastIfNeeded(param.Type, PopType());
-
- OpCode storecode = GetStoreRefParamCode(param.Type);
- if (IsStobj(storecode)) //passing struct/decimal byref
- {
- _il.Emit(storecode, GetSystemType(param.Type));
- }
- else
- {
- _il.Emit(storecode);
- }
- if (null != temp)
- {
- LoadLocal(temp, tempType);
- }
- }
- void EmitTypeTest(BinaryExpression node)
- {
- Visit(node.Left); PopType();
-
- Type type = null;
- if (NodeType.TypeofExpression == node.Right.NodeType)
- {
- type = GetSystemType(((TypeofExpression)node.Right).Type);
- }
- else
- {
- type = GetSystemType(node.Right);
- }
- _il.Emit(OpCodes.Isinst, type);
- }
-
- void OnTypeTest(BinaryExpression node)
- {
- EmitTypeTest(node);
-
- Label isTrue = _il.DefineLabel();
- Label isFalse = _il.DefineLabel();
- _il.Emit(OpCodes.Brtrue, isTrue);
- _il.Emit(OpCodes.Ldc_I4_0);
- _il.Emit(OpCodes.Br, isFalse);
- _il.MarkLabel(isTrue);
- _il.Emit(OpCodes.Ldc_I4_1);
- _il.MarkLabel(isFalse);
-
- PushBool();
- }
-
- void LoadCmpOperands(BinaryExpression node)
- {
- IType lhs = node.Left.ExpressionType;
- IType rhs = node.Right.ExpressionType;
-
- IType type = TypeSystemServices.GetPromotedNumberType(lhs, rhs);
- Visit(node.Left);
- EmitCastIfNeeded(type, PopType());
- Visit(node.Right);
- EmitCastIfNeeded(type, PopType());
- }
-
- void OnEquality(BinaryExpression node)
- {
- LoadCmpOperands(node);
- _il.Emit(OpCodes.Ceq);
- PushBool();
- }
-
- void OnInequality(BinaryExpression node)
- {
- LoadCmpOperands(node);
- _il.Emit(OpCodes.Ceq);
- EmitIntNot();
- PushBool();
- }
-
- void OnGreaterThan(BinaryExpression node)
- {
- LoadCmpOperands(node);
- _il.Emit(OpCodes.Cgt);
- PushBool();
- }
-
- void OnGreaterThanOrEqual(BinaryExpression node)
- {
- OnLessThan(node);
- EmitIntNot();
- }
-
- void OnLessThan(BinaryExpression node)
- {
- LoadCmpOperands(node);
- _il.Emit(OpCodes.Clt);
- PushBool();
- }
-
- void OnLessThanOrEqual(BinaryExpression node)
- {
- OnGreaterThan(node);
- EmitIntNot();
- }
-
- void OnExponentiation(BinaryExpression node)
- {
- Visit(node.Left);
- EmitCastIfNeeded(TypeSystemServices.DoubleType, PopType());
- Visit(node.Right);
- EmitCastIfNeeded(TypeSystemServices.DoubleType, PopType());
- _il.EmitCall(OpCodes.Call, Math_Pow, null);
- PushType(TypeSystemServices.DoubleType);
- }
-
- void OnArithmeticOperator(BinaryExpression node)
- {
- IType type = node.ExpressionType;
- node.Left.Accept(this); EmitCastIfNeeded(type, PopType());
- node.Right.Accept(this); EmitCastIfNeeded(type, PopType());
- _il.Emit(GetArithmeticOpCode(type, node.Operator));
- PushType(type);
- }
-
- bool EmitToBoolIfNeeded(Expression expression)
- {
- IType type = GetExpressionType(expression);
- if (TypeSystemServices.ObjectType == type ||
- TypeSystemServices.DuckType == type)
- {
- _il.EmitCall(OpCodes.Call, RuntimeServices_ToBool_Object, null);
- return true;
- }
- if (TypeSystemServices.DecimalType == type)
- {
- _il.EmitCall(OpCodes.Call, RuntimeServices_ToBool_Decimal, null);
- return true;
- }
- if (TypeSystemServices.SingleType == type)
- {
- _il.EmitCall(OpCodes.Call, RuntimeServices_ToBool_Single, null);
- return true;
- }
- if (TypeSystemServices.DoubleType == type)
- {
- _il.EmitCall(OpCodes.Call, RuntimeServices_ToBool_Double, null);
- return true;
- }
- return false;
- }
-
- void EmitAnd(BinaryExpression node)
- {
- EmitLogicalOperator(node, OpCodes.Brtrue, OpCodes.Brfalse);
- }
-
- void EmitOr(BinaryExpression node)
- {
- EmitLogicalOperator(node, OpCodes.Brfalse, OpCodes.Brtrue);
- }
-
- void EmitLogicalOperator(BinaryExpression node, OpCode brForValueType, OpCode brForRefType)
- {
- IType type = GetExpressionType(node);
- Visit(node.Left);
-
- IType lhsType = PopType();
-
- if (null != lhsType && lhsType.IsValueType && !type.IsValueType)
- {
- // if boxing, first evaluate the value
- // as it is and then box it...
- Label evalRhs = _il.DefineLabel();
- Label end = _il.DefineLabel();
-
- _il.Emit(OpCodes.Dup);
- EmitToBoolIfNeeded(node.Left); // may need to convert decimal to bool
- _il.Emit(brForValueType, evalRhs);
- EmitCastIfNeeded(type, lhsType);
- _il.Emit(OpCodes.Br, end);
-
- _il.MarkLabel(evalRhs);
- _il.Emit(OpCodes.Pop);
- Visit(node.Right);
- EmitCastIfNeeded(type, PopType());
-
- _il.MarkLabel(end);
-
- }
- else
- {
- Label end = _il.DefineLabel();
-
- EmitCastIfNeeded(type, lhsType);
- _il.Emit(OpCodes.Dup);
-
- EmitToBoolIfNeeded(node.Left);
-
- _il.Emit(brForRefType, end);
-
- _il.Emit(OpCodes.Pop);
- Visit(node.Right);
- EmitCastIfNeeded(type, PopType());
- _il.MarkLabel(end);
- }
-
- PushType(type);
- }
-
- IType GetExpectedTypeForBitwiseRightOperand(BinaryExpression node)
- {
- switch (node.Operator)
- {
- // BOO-705
- case BinaryOperatorType.ShiftLeft:
- case BinaryOperatorType.ShiftRight:
- return TypeSystemServices.IntType;
- }
- return GetExpressionType(node);
- }
-
- void EmitBitwiseOperator(BinaryExpression node)
- {
- IType type = node.ExpressionType;
-
- Visit(node.Left);
- EmitCastIfNeeded(type, PopType());
-
- Visit(node.Right);
- EmitCastIfNeeded(
- GetExpectedTypeForBitwiseRightOperand(node),
- PopType());
-
- switch (node.Operator)
- {
- case BinaryOperatorType.BitwiseOr:
- {
- _il.Emit(OpCodes.Or);
- break;
- }
-
- case BinaryOperatorType.BitwiseAnd:
- {
- _il.Emit(OpCodes.And);
- break;
- }
-
- case BinaryOperatorType.ExclusiveOr:
- {
- _il.Emit(OpCodes.Xor);
- break;
- }
- case BinaryOperatorType.ShiftLeft:
- {
- _il.Emit(OpCodes.Shl);
- break;
- }
- case BinaryOperatorType.ShiftRight:
- {
- _il.Emit(OpCodes.Shr);
- break;
- }
- }
-
- PushType(type);
- }
-
- override public void OnBinaryExpression(BinaryExpression node)
- {
- switch (node.Operator)
- {
- case BinaryOperatorType.ShiftLeft:
- case BinaryOperatorType.ShiftRight:
- case BinaryOperatorType.ExclusiveOr:
- case BinaryOperatorType.BitwiseAnd:
- case BinaryOperatorType.BitwiseOr:
- {
- EmitBitwiseOperator(node);
- break;
- }
-
- case BinaryOperatorType.Or:
- {
- EmitOr(node);
- break;
- }
-
- case BinaryOperatorType.And:
- {
- EmitAnd(node);
- break;
- }
-
- case BinaryOperatorType.Addition:
- case BinaryOperatorType.Subtraction:
- case BinaryOperatorType.Multiply:
- case BinaryOperatorType.Division:
- case BinaryOperatorType.Modulus:
- {
- OnArithmeticOperator(node);
- break;
- }
-
- case BinaryOperatorType.Exponentiation:
- {
- OnExponentiation(node);
- break;
- }
-
- case BinaryOperatorType.Assign:
- {
- OnAssignment(node);
- break;
- }
-
- case BinaryOperatorType.Equality:
- {
- OnEquality(node);
- break;
- }
-
- case BinaryOperatorType.Inequality:
- {
- OnInequality(node);
- break;
- }
-
- case BinaryOperatorType.GreaterThan:
- {
- OnGreaterThan(node);
- break;
- }
-
- case BinaryOperatorType.LessThan:
- {
- OnLessThan(node);
- break;
- }
-
- case BinaryOperatorType.GreaterThanOrEqual:
- {
- OnGreaterThanOrEqual(node);
- break;
- }
-
- case BinaryOperatorType.LessThanOrEqual:
- {
- OnLessThanOrEqual(node);
- break;
- }
-
- case BinaryOperatorType.ReferenceInequality:
- {
- OnReferenceComparison(node);
- break;
- }
-
- case BinaryOperatorType.ReferenceEquality:
- {
- OnReferenceComparison(node);
- break;
- }
-
- case BinaryOperatorType.TypeTest:
- {
- OnTypeTest(node);
- break;
- }
-
- default:
- {
- OperatorNotImplemented(node);
- break;
- }
- }
- }
-
- void OperatorNotImplemented(BinaryExpression node)
- {
- NotImplemented(node, node.Operator.ToString());
- }
-
- override public void OnTypeofExpression(TypeofExpression node)
- {
- EmitGetTypeFromHandle(GetSystemType(node.Type));
- }
-
- override public void OnCastExpression(CastExpression node)
- {
- IType type = GetType(node.Type);
- Visit(node.Target);
- EmitCastIfNeeded(type, PopType());
- PushType(type);
- }
-
- override public void OnTryCastExpression(TryCastExpression node)
- {
- Type type = GetSystemType(node.Type);
-
- node.Target.Accept(this); PopType();
- _il.Emit(OpCodes.Isinst, type);
- PushType(node.ExpressionType);
- }
-
- void InvokeMethod(IMethod method, MethodInvocationExpression node)
- {
- MethodInfo mi = GetMethodInfo(method);
- if (!InvokeOptimizedMethod(method, mi, node))
- {
- InvokeRegularMethod(method, mi, node);
- }
- }
-
- bool InvokeOptimizedMethod(IMethod method, MethodInfo mi, MethodInvocationExpression node)
- {
- if (Builtins_ArrayTypedConstructor == mi)
- {
- // optimize constructs such as:
- // array(int, 2)
- IType type = TypeSystemServices.GetReferencedType(node.Arguments[0]);
- if (null != type)
- {
- Visit(node.Arguments[1]);
- EmitCastIfNeeded(TypeSystemServices.IntType, PopType());
- _il.Emit(OpCodes.Newarr, GetSystemType(type));
- PushType(TypeSystemServices.GetArrayType(type, 1));
- return true;
- }
- }
- else if (Builtins_ArrayTypedCollectionConstructor == mi)
- {
- // optimize constructs such as:
- …
Large files files are truncated, but you can click here to view the full file