Index: Boo.Lang.Compiler/Steps/EmitAssembly.cs =================================================================== --- Boo.Lang.Compiler/Steps/EmitAssembly.cs (revision 2354) +++ Boo.Lang.Compiler/Steps/EmitAssembly.cs (working copy) @@ -1,4697 +1,4704 @@ -#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 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 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(); - } - - /// - /// Ensures that all types are created in the correct order. - /// - 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) - { - AbstractInternalType tag = _emitter.GetType(baseTypeRef) as AbstractInternalType; - if (null != tag) - { - CreateType(tag.TypeDefinition); - } - } - } - - ((AbstractInternalType)type.Entity).GeneratedType = _emitter.GetTypeBuilder(type).CreateType(); - - Trace("type '{0}' successfully created", type); - - _current = saved; - } - } - - 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) - { - Type baseType = typeof(int); - - TypeBuilder builder = GetTypeBuilder(node); - - builder.DefineField("value__", baseType, - FieldAttributes.Public | - FieldAttributes.SpecialName | - FieldAttributes.RTSpecialName); - - 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 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); - - 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); - EmitNopDebugInfo(node); - } - - 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); - } - EmitNopDebugInfo(node); - } - - private void EmitNopDebugInfo(Statement node) - { - // HACK: workaround - mono reports the position of - // raise as being the position of the next instruction - // after it - if (EmitDebugInfo(node)) - { - _il.Emit(OpCodes.Nop); - } - } - - override public void OnTryStatement(TryStatement node) - { - ++_tryBlock; - - _il.BeginExceptionBlock(); - Visit(node.ProtectedBlock); - Visit(node.ExceptionHandlers); - if (null != node.EnsureBlock) - { - _il.BeginFinallyBlock(); - Visit(node.EnsureBlock); - } - _il.EndExceptionBlock(); - - --_tryBlock; - } - - override public void OnExceptionHandler(ExceptionHandler node) - { - _il.BeginCatchBlock(GetSystemType(node.Declaration)); - _il.Emit(OpCodes.Stloc, GetLocalBuilder(node.Declaration)); - Visit(node.Block); - } - - 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!"); - - EmitNopDebugInfo(node); - } - - 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); - EmitNopDebugInfo(node); - 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 0) - { - EmitObjectArray(node.Items); - _il.Emit(OpCodes.Ldc_I4_1); - _il.Emit(OpCodes.Newobj, List_ArrayBoolConstructor); - } - else - { - _il.Emit(OpCodes.Newobj, List_EmptyConstructor); - } - PushType(TypeSystemServices.ListType); - } - - override public void OnArrayLiteralExpression(ArrayLiteralExpression node) - { - IArrayType type = (IArrayType)node.ExpressionType; - EmitArray(type.GetElementType(), node.Items); - PushType(type); - } - - override public void OnRELiteralExpression(RELiteralExpression node) - { - _il.Emit(OpCodes.Ldstr, RuntimeServices.Mid(node.Value, 1, -1)); - _il.Emit(OpCodes.Newobj, Regex_Constructor); - PushType(node.ExpressionType); - } - - override public void OnStringLiteralExpression(StringLiteralExpression node) - { - _il.Emit(OpCodes.Ldstr, node.Value); - PushType(TypeSystemServices.StringType); - } - - override public void OnCharLiteralExpression(CharLiteralExpression node) - { - _il.Emit(OpCodes.Ldc_I4, node.Value[0]); - PushType(TypeSystemServices.CharType); - } - - override public void OnSlicingExpression(SlicingExpression node) - { - if (AstUtil.IsLhsOfAssignment(node)) - { - return; - } - - Visit(node.Target); - - IArrayType type = (IArrayType)PopType(); - EmitNormalizedArrayIndex(node, node.Indices[0].Begin); - - IType elementType = type.GetElementType(); - OpCode opcode = GetLoadEntityOpCode(elementType); - if (OpCodes.Ldelema.Value == opcode.Value) - { - Type systemType = GetSystemType(elementType); - _il.Emit(opcode, systemType); - _il.Emit(OpCodes.Ldobj, systemType); - } - else - { - _il.Emit(opcode); - } - PushType(elementType); - } - - void EmitNormalizedArrayIndex(SlicingExpression sourceNode, Expression index) - { - bool isNegative = false; - if (CanBeNegative(index, ref isNegative) - && !_rawArrayIndexing - && !AstAnnotations.IsRawIndexing(sourceNode)) - { - if (isNegative) - { - _il.Emit(OpCodes.Dup); - _il.Emit(OpCodes.Ldlen); - EmitLoadInt(index); - _il.Emit(OpCodes.Add); - } - else - { - _il.Emit(OpCodes.Dup); - EmitLoadInt(index); - _il.EmitCall(OpCodes.Call, RuntimeServices_NormalizeArrayIndex, null); - } - } - else - { - EmitLoadInt(index); - } - } - - bool CanBeNegative(Expression expression, ref bool isNegative) - { - IntegerLiteralExpression integer = expression as IntegerLiteralExpression; - if (null != integer) - { - if (integer.Value >= 0) - { - return false; - } - isNegative = true; - } - return true; - } - - void EmitLoadInt(Expression expression) - { - Visit(expression); - EmitCastIfNeeded(TypeSystemServices.IntType, PopType()); - } - - override public void OnExpressionInterpolationExpression(ExpressionInterpolationExpression node) - { - Type stringBuilderType = typeof(StringBuilder); - ConstructorInfo constructor = stringBuilderType.GetConstructor(new Type[0]); - MethodInfo appendObject = stringBuilderType.GetMethod("Append", new Type[] { typeof(object) }); - MethodInfo appendString = stringBuilderType.GetMethod("Append", new Type[] { typeof(string) }); - - _il.Emit(OpCodes.Newobj, constructor); - - foreach (Expression arg in node.Expressions) - { - Visit(arg); - - IType argType = PopType(); - if (TypeSystemServices.StringType == argType) - { - _il.EmitCall(OpCodes.Call, appendString, null); - } - else - { - EmitCastIfNeeded(TypeSystemServices.ObjectType, argType); - _il.EmitCall(OpCodes.Call, appendObject, null); - } - } - _il.EmitCall(OpCodes.Call, stringBuilderType.GetMethod("ToString", new Type[0]), null); - PushType(TypeSystemServices.StringType); - } - - void LoadMemberTarget(Expression self, IMember member) - { - if (member.DeclaringType.IsValueType) - { - LoadAddress(self); - } - else - { - Visit(self); - PopType(); - } - } - - void EmitLoadFieldAddress(Expression expression, IField field) - { - if (field.IsStatic) - { - _il.Emit(OpCodes.Ldsflda, GetFieldInfo(field)); - } - else - { - LoadMemberTarget(((MemberReferenceExpression)expression).Target, field); - _il.Emit(OpCodes.Ldflda, GetFieldInfo(field)); - } - } - - void EmitLoadField(Expression self, IField fieldInfo) - { - if (fieldInfo.IsStatic) - { - if (fieldInfo.IsLiteral) - { - EmitLoadLiteralField(self, fieldInfo); - } - else - { - _il.Emit(OpCodes.Ldsfld, GetFieldInfo(fieldInfo)); - } - } - else - { - LoadMemberTarget(self, fieldInfo); - _il.Emit(OpCodes.Ldfld, GetFieldInfo(fieldInfo)); - } - PushType(fieldInfo.Type); - } - - object GetStaticValue(IField field) - { - InternalField internalField = field as InternalField; - if (null != internalField) - { - return GetInternalFieldStaticValue(internalField); - } - return field.StaticValue; - } - - object GetInternalFieldStaticValue(InternalField field) - { - return GetValue(field.Type, (Expression)field.StaticValue); - } - - void EmitLoadLiteralField(Node node, IField fieldInfo) - { - object value = GetStaticValue(fieldInfo); - if (null == value) - { - _il.Emit(OpCodes.Ldnull); - } - else - { - TypeCode type = Type.GetTypeCode(value.GetType()); - switch (type) - { - case TypeCode.Byte: - { - _il.Emit(OpCodes.Ldc_I4, (int)(byte)value); - _il.Emit(OpCodes.Conv_U1); - break; - } - - case TypeCode.SByte: - { - _il.Emit(OpCodes.Ldc_I4, (int)(sbyte)value); - _il.Emit(OpCodes.Conv_I1); - break; - } - - case TypeCode.Char: - { - _il.Emit(OpCodes.Ldc_I4, (int)(char)value); - break; - } - - case TypeCode.Int16: - { - _il.Emit(OpCodes.Ldc_I4, (int)(short)value); - break; - } - - case TypeCode.UInt16: - { - _il.Emit(OpCodes.Ldc_I4, (int)(ushort)value); - break; - } - - case TypeCode.Int32: - { - _il.Emit(OpCodes.Ldc_I4, (int)value); - break; - } - - case TypeCode.UInt32: - { - uint uValue = (uint)value; - unchecked - { - _il.Emit(OpCodes.Ldc_I4, (int)uValue); - } - _il.Emit(OpCodes.Conv_U4); - break; - } - - case TypeCode.Int64: - { - _il.Emit(OpCodes.Ldc_I8, (long)value); - break; - } - - case TypeCode.UInt64: - { - ulong uValue = (ulong)value; - unchecked - { - _il.Emit(OpCodes.Ldc_I8, (long)uValue); - } - _il.Emit(OpCodes.Conv_U8); - break; - } - - case TypeCode.Single: - { - _il.Emit(OpCodes.Ldc_R4, (float)value); - break; - } - - case TypeCode.Double: - { - _il.Emit(OpCodes.Ldc_R8, (double)value); - break; - } - - case TypeCode.String: - { - _il.Emit(OpCodes.Ldstr, (string)value); - break; - } - - default: - { - NotImplemented(node, "Literal: " + type.ToString()); - break; - } - } - } - } - - override public void OnGenericReferenceExpression(GenericReferenceExpression node) - { - IEntity tag = TypeSystem.TypeSystemServices.GetEntity(node); - switch (tag.EntityType) - { - case EntityType.Type: - { - EmitGetTypeFromHandle(GetSystemType(node)); - break; - } - - default: - { - NotImplemented(node, tag.ToString()); - break; - } - } - } - - override public void OnMemberReferenceExpression(MemberReferenceExpression node) - { - IEntity tag = TypeSystem.TypeSystemServices.GetEntity(node); - switch (tag.EntityType) - { - case EntityType.Method: - { - node.Target.Accept(this); - break; - } - - case EntityType.Field: - { - EmitLoadField(node.Target, (IField)tag); - break; - } - - case EntityType.Type: - { - EmitGetTypeFromHandle(GetSystemType(node)); - break; - } - - default: - { - NotImplemented(node, tag.ToString()); - break; - } - } - } - - void LoadAddress(Expression expression) - { - if (NodeType.SelfLiteralExpression == expression.NodeType) - { - if (expression.ExpressionType.IsValueType) - { - _il.Emit(OpCodes.Ldarg_0); - return; - } - } - - IEntity tag = expression.Entity; - if (null != tag) - { - switch (tag.EntityType) - { - case EntityType.Local: - { - _il.Emit(OpCodes.Ldloca, ((InternalLocal)tag).LocalBuilder); - return; - } - - case EntityType.Parameter: - { - InternalParameter param = (InternalParameter)tag; - if (param.Parameter.IsByRef) - { - LoadParam(param); - } - else - { - _il.Emit(OpCodes.Ldarga, param.Index); - } - return; - } - - case EntityType.Field: - { - IField field = (IField)tag; - if (!field.IsLiteral) - { - EmitLoadFieldAddress(expression, field); - return; - } - break; - } - } - } - - if (IsValueTypeArraySlicing(expression)) - { - SlicingExpression slicing = (SlicingExpression)expression; - Visit(slicing.Target); - IArrayType arrayType = (IArrayType)PopType(); - EmitNormalizedArrayIndex(slicing, slicing.Indices[0].Begin); - _il.Emit(OpCodes.Ldelema, GetSystemType(arrayType.GetElementType())); - } - else - { - // declare local to hold value type - Visit(expression); - LocalBuilder temp = _il.DeclareLocal(GetSystemType(PopType())); - _il.Emit(OpCodes.Stloc, temp); - _il.Emit(OpCodes.Ldloca, temp); - } - } - - bool IsValueTypeArraySlicing(Expression expression) - { - SlicingExpression slicing = expression as SlicingExpression; - if (null != slicing) - { - IArrayType type = (IArrayType)slicing.Target.ExpressionType; - return type.GetElementType().IsValueType; - } - return false; - } - - override public void OnSelfLiteralExpression(SelfLiteralExpression node) - { - _il.Emit(OpCodes.Ldarg_0); - if (node.ExpressionType.IsValueType) - { - _il.Emit(OpCodes.Ldobj, GetSystemType(node.ExpressionType)); - } - PushType(node.ExpressionType); - } - - override public void OnSuperLiteralExpression(SuperLiteralExpression node) - { - _il.Emit(OpCodes.Ldarg_0); - if (node.ExpressionType.IsValueType) - { - _il.Emit(OpCodes.Ldobj, GetSystemType(node.ExpressionType)); - } - PushType(node.ExpressionType); - } - - override public void OnNullLiteralExpression(NullLiteralExpression node) - { - _il.Emit(OpCodes.Ldnull); - PushType(null); - } - - override public void OnReferenceExpression(ReferenceExpression node) - { - IEntity info = TypeSystem.TypeSystemServices.GetEntity(node); - switch (info.EntityType) - { - case EntityType.Local: - { - InternalLocal local = (InternalLocal)info; - LocalBuilder builder = local.LocalBuilder; - _il.Emit(OpCodes.Ldloc, builder); - PushType(local.Type); - break; - } - - case EntityType.Parameter: - { - InternalParameter param = (InternalParameter)info; - LoadParam(param); - - if (param.Parameter.IsByRef) - { - OpCode code = GetLoadRefParamCode(param.Type); - if (code.Value == OpCodes.Ldobj.Value) - { - _il.Emit(code, GetSystemType(param.Type)); - } - else { - _il.Emit(code); - } - } - PushType(param.Type); - break; - } - - case EntityType.Array: - case EntityType.Type: - { - EmitGetTypeFromHandle(GetSystemType(node)); - break; - } - - default: - { - NotImplemented(node, info.ToString()); - break; - } - - } - } - - void LoadParam(InternalParameter param) - { - int index = param.Index; - - switch (index) - { - case 0: - { - _il.Emit(OpCodes.Ldarg_0); - break; - } - - case 1: - { - _il.Emit(OpCodes.Ldarg_1); - break; - } - - case 2: - { - _il.Emit(OpCodes.Ldarg_2); - break; - } - - case 3: - { - _il.Emit(OpCodes.Ldarg_3); - break; - } - - default: - { - if (index < 256) - { - _il.Emit(OpCodes.Ldarg_S, index); - } - else - { - _il.Emit(OpCodes.Ldarg, index); - } - break; - } - } - } - void SetLocal(BinaryExpression node, InternalLocal tag, bool leaveValueOnStack) - { - node.Right.Accept(this); // leaves type on stack - - IType typeOnStack = null; - - if (leaveValueOnStack) - { - typeOnStack = PeekTypeOnStack(); - _il.Emit(OpCodes.Dup); - } - else - { - typeOnStack = PopType(); - } - EmitAssignment(tag, typeOnStack); - } - - void EmitAssignment(InternalLocal tag, IType typeOnStack) - { - // todo: assignment result must be type on the left in the - // case of casting - LocalBuilder local = tag.LocalBuilder; - EmitCastIfNeeded(tag.Type, typeOnStack); - _il.Emit(OpCodes.Stloc, local); - } - - void SetField(Node sourceNode, IField field, Expression reference, Expression value, bool leaveValueOnStack) - { - OpCode opSetField = OpCodes.Stsfld; - if (!field.IsStatic) - { - opSetField = OpCodes.Stfld; - if (null != reference) - { - LoadMemberTarget( - ((MemberReferenceExpression)reference).Target, - field); - } - } - - value.Accept(this); - EmitCastIfNeeded(field.Type, PopType()); - - FieldInfo fi = GetFieldInfo(field); - LocalBuilder local = null; - if (leaveValueOnStack) - { - _il.Emit(OpCodes.Dup); - local = _il.DeclareLocal(fi.FieldType); - _il.Emit(OpCodes.Stloc, local); - } - - _il.Emit(opSetField, fi); - - if (leaveValueOnStack) - { - _il.Emit(OpCodes.Ldloc, local); - PushType(field.Type); - } - } - - void SetProperty(Node sourceNode, IProperty property, Expression reference, Expression value, bool leaveValueOnStack) - { - OpCode callOpCode = OpCodes.Call; - - MethodInfo setMethod = GetMethodInfo(property.GetSetMethod()); - - if (null != reference) - { - if (!setMethod.IsStatic) - { - Expression target = ((MemberReferenceExpression)reference).Target; - if (setMethod.DeclaringType.IsValueType) - { - LoadAddress(target); - } - else - { - callOpCode = OpCodes.Callvirt; - target.Accept(this); - PopType(); - } - } - } - - value.Accept(this); - EmitCastIfNeeded(property.Type, PopType()); - - LocalBuilder local = null; - if (leaveValueOnStack) - { - _il.Emit(OpCodes.Dup); - local = _il.DeclareLocal(GetSystemType(property.Type)); - _il.Emit(OpCodes.Stloc, local); - } - - _il.EmitCall(callOpCode, setMethod, null); - - if (leaveValueOnStack) - { - _il.Emit(OpCodes.Ldloc, local); - PushType(property.Type); - } - } - - bool EmitDebugInfo(Node node) - { - return EmitDebugInfo(node, node); - } - - bool EmitDebugInfo(Node startNode, Node endNode) - { - if (!Parameters.Debug) return false; - - LexicalInfo start = startNode.LexicalInfo; - if (!start.IsValid) return false; - - ISymbolDocumentWriter writer = GetDocumentWriter(start.FullPath); - if (null == writer) return false; - - try - { - _il.MarkSequencePoint(writer, start.Line, 0, start.Line+1, 0); - } - catch (Exception x) - { - Error(CompilerErrorFactory.InternalError(startNode, x)); - return false; - } - - return true; - } - - private ISymbolDocumentWriter GetDocumentWriter(string fname) - { - ISymbolDocumentWriter writer = GetCachedDocumentWriter(fname); - if (null != writer) return writer; - - writer = _moduleBuilder.DefineDocument( - fname, - Guid.Empty, - Guid.Empty, - SymDocumentType.Text); - _symbolDocWriters.Add(fname, writer); - - return writer; - } - - private ISymbolDocumentWriter GetCachedDocumentWriter(string fname) - { - return (ISymbolDocumentWriter) _symbolDocWriters[fname]; - } - - bool IsBoolOrInt(IType type) - { - return TypeSystemServices.BoolType == type || - TypeSystemServices.IntType == type; - } - - void PushArguments(IMethodBase entity, ExpressionCollection args) - { - IParameter[] parameters = entity.GetParameters(); - for (int i=0; i 1) - { - type = Array.CreateInstance(GetSystemType(arrayType.GetElementType()), new int[arrayType.GetArrayRank()]).GetType(); - } - else - { - type = Array.CreateInstance(GetSystemType(arrayType.GetElementType()), 0).GetType(); - } - } - } - else if (Null.Default == tag) - { - type = Types.Object; - } - else - { - type = (Type)GetBuilder(((AbstractInternalType)tag).TypeDefinition); - } - - if (null == type) - { - throw new InvalidOperationException(string.Format("Could not find a Type for {0}.", tag)); - } - - _typeCache.Add(tag, type); - return type; - } - - IType GetSimpleEntityType(IArrayType tag) - { - return GetSimpleEntityType(tag.GetElementType()); - } - - IType GetSimpleEntityType(IType tag) - { - if (tag.IsArray) - { - return GetSimpleEntityType(((IArrayType)tag).GetElementType()); - } - return tag; - } - - string GetArrayTypeName(IType tag) - { - StringBuilder builder = new StringBuilder(); - GetArrayTypeName(builder, tag); - return builder.ToString(); - } - - void GetArrayTypeName(StringBuilder buffer, IType tag) - { - if (tag.IsArray) - { - IArrayType array = (IArrayType)tag; - GetArrayTypeName(buffer, array.GetElementType()); - buffer.Append("["); - for (int i = 1; i < array.GetArrayRank(); i++) - { - buffer.Append(","); - } - buffer.Append("]"); - } - else - { - AppendFullTypeName(buffer, tag); - } - } - - void AppendFullTypeName(StringBuilder buffer, IType type) - { - AbstractInternalType internalType = (AbstractInternalType)type; - AppendFullTypeName(buffer, internalType.TypeDefinition); - } - - void AppendFullTypeName(StringBuilder buffer, TypeDefinition type) - { - TypeDefinition parent = type.DeclaringType; - if (null != parent) - { - if (NodeType.Module == parent.NodeType) - { - NamespaceDeclaration ns = parent.EnclosingNamespace; - if (null != ns) - { - buffer.Append(ns.Name); - buffer.Append('.'); - } - } - else - { - AppendFullTypeName(buffer, parent); - buffer.Append('+'); // nested type - } - } - buffer.Append(type.Name); - } - - TypeAttributes GetNestedTypeAttributes(TypeMember type) - { - return GetExtendedTypeAttributes(GetNestedTypeAccessibility(type), type); - } - - TypeAttributes GetNestedTypeAccessibility(TypeMember type) - { - if (type.IsPublic) return TypeAttributes.NestedPublic; - if (type.IsInternal) return TypeAttributes.NestedAssembly; - return TypeAttributes.NestedPrivate; - } - - TypeAttributes GetTypeAttributes(TypeMember type) - { - TypeAttributes attributes = type.IsPublic ? TypeAttributes.Public : TypeAttributes.NotPublic; - return GetExtendedTypeAttributes(attributes, type); - } - - TypeAttributes GetExtendedTypeAttributes(TypeAttributes attributes, TypeMember type) - { - switch (type.NodeType) - { - case NodeType.ClassDefinition: - { - attributes |= (TypeAttributes.AnsiClass | TypeAttributes.AutoLayout); - attributes |= TypeAttributes.Class; - attributes |= TypeAttributes.BeforeFieldInit; - - if (!type.IsTransient) - { - attributes |= TypeAttributes.Serializable; - } - if (type.IsAbstract) - { - attributes |= TypeAttributes.Abstract; - } - if (type.IsFinal) - { - attributes |= TypeAttributes.Sealed; - } - if (((IType)type.Entity).IsValueType) - { - attributes |= TypeAttributes.SequentialLayout; - } - break; - } - - case NodeType.EnumDefinition: - { - attributes |= TypeAttributes.Sealed; - attributes |= TypeAttributes.Serializable; - break; - } - - case NodeType.InterfaceDefinition: - { - attributes |= (TypeAttributes.Interface | TypeAttributes.Abstract); - break; - } - - case NodeType.Module: - { - attributes |= TypeAttributes.Sealed; - break; - } - } - return attributes; - } - - PropertyAttributes GetPropertyAttributes(Property property) - { - PropertyAttributes attributes = PropertyAttributes.None; - - if (property.ExplicitInfo != null) - { - attributes |= PropertyAttributes.SpecialName | PropertyAttributes.RTSpecialName; - } - return attributes; - } - - MethodAttributes GetMethodAttributesFromTypeMember(TypeMember member) - { - MethodAttributes attributes = (MethodAttributes)0; - if (member.IsPublic) - { - attributes = MethodAttributes.Public; - } - else if (member.IsProtected) - { - attributes = member.IsInternal - ? MethodAttributes.FamORAssem - : MethodAttributes.Family; - } - else if (member.IsPrivate) - { - attributes = MethodAttributes.Private; - } - else if (member.IsInternal) - { - attributes = MethodAttributes.Assembly; - } - if (member.IsStatic) - { - attributes |= MethodAttributes.Static; - - if (member.Name.StartsWith("op_")) - { - attributes |= MethodAttributes.SpecialName; - } - } - if (member.IsFinal) - { - attributes |= MethodAttributes.Final; - } - if (member.IsAbstract) - { - attributes |= (MethodAttributes.Abstract | MethodAttributes.Virtual); - } - if (member.IsVirtual || member.IsOverride) - { - attributes |= MethodAttributes.Virtual; - } - return attributes; - } - - MethodAttributes GetPropertyMethodAttributes(TypeMember property) - { - MethodAttributes attributes = MethodAttributes.SpecialName | MethodAttributes.HideBySig; - attributes |= GetMethodAttributesFromTypeMember(property); - return attributes; - } - - MethodAttributes GetMethodAttributes(Method method) - { - MethodAttributes attributes = MethodAttributes.HideBySig; - if (method.ExplicitInfo != null) - { - attributes |= MethodAttributes.NewSlot; - } - if (IsPInvoke(method)) - { - Debug.Assert(method.IsStatic); - attributes |= MethodAttributes.PinvokeImpl; - } - attributes |= GetMethodAttributesFromTypeMember(method); - return attributes; - } - - FieldAttributes GetFieldAttributes(Field field) - { - FieldAttributes attributes = 0; - if (field.IsProtected) - { - attributes |= FieldAttributes.Family; - } - else if (field.IsPublic) - { - attributes |= FieldAttributes.Public; - } - else if (field.IsPrivate) - { - attributes |= FieldAttributes.Private; - } - else if (field.IsInternal) - { - attributes |= FieldAttributes.Assembly; - } - if (field.IsStatic) - { - attributes |= FieldAttributes.Static; - } - if (field.IsTransient) - { - attributes |= FieldAttributes.NotSerialized; - } - if (field.IsFinal) - { - IField entity = (IField)field.Entity; - if (entity.IsLiteral) - { - attributes |= FieldAttributes.Literal; - } - else - { - attributes |= FieldAttributes.InitOnly; - } - } - return attributes; - } - - ParameterAttributes GetParameterAttributes(ParameterDeclaration param) - { - return ParameterAttributes.None; - } - - void DefineEvent(TypeBuilder typeBuilder, Event node) - { - EventBuilder builder = typeBuilder.DefineEvent(node.Name, - EventAttributes.None, - GetSystemType(node.Type)); - //MethodAttributes attribs = GetPropertyMethodAttributes(node); - MethodAttributes baseAttributes = MethodAttributes.SpecialName; - builder.SetAddOnMethod(DefineMethod(typeBuilder, node.Add, baseAttributes|GetMethodAttributes(node.Add))); - builder.SetRemoveOnMethod(DefineMethod(typeBuilder, node.Remove, baseAttributes|GetMethodAttributes(node.Remove))); - - if (null != node.Raise) - { - builder.SetRaiseMethod(DefineMethod(typeBuilder, node.Raise, baseAttributes|GetMethodAttributes(node.Raise))); - } - - SetBuilder(node, builder); - } - - void DefineProperty(TypeBuilder typeBuilder, Property property) - { - string name; - if (property.ExplicitInfo != null) - { - name = property.ExplicitInfo.InterfaceType.Name + "." + property.Name; - } - else - { - name = property.Name; - } - - PropertyBuilder builder = typeBuilder.DefineProperty(name, - GetPropertyAttributes(property), - GetSystemType(property.Type), - GetParameterTypes(property.Parameters)); - Method getter = property.Getter; - Method setter = property.Setter; - - MethodAttributes attribs = GetPropertyMethodAttributes(property); - if (null != getter) - { - MethodBuilder getterBuilder = - DefineMethod(typeBuilder, getter, attribs); - builder.SetGetMethod(getterBuilder); - } - if (null != setter) - { - MethodBuilder setterBuilder = - DefineMethod(typeBuilder, setter, attribs); - builder.SetSetMethod(setterBuilder); - } - bool isDuckTyped = GetEntity(property).IsDuckTyped; - if (isDuckTyped) - { - builder.SetCustomAttribute(CreateDuckTypedCustomAttribute()); - } - - SetBuilder(property, builder); - } - - void DefineField(TypeBuilder typeBuilder, Field field) - { - FieldBuilder builder = typeBuilder.DefineField(field.Name, - GetSystemType(field), - GetFieldAttributes(field)); - SetBuilder(field, builder); - } - - delegate ParameterBuilder ParameterFactory(int index, System.Reflection.ParameterAttributes attributes, string name); - - void DefineParameters(ConstructorBuilder builder, ParameterDeclarationCollection parameters) - { - DefineParameters(parameters, new ParameterFactory(builder.DefineParameter)); - } - - void DefineParameters(MethodBuilder builder, ParameterDeclarationCollection parameters) - { - DefineParameters(parameters, new ParameterFactory(builder.DefineParameter)); - } - - void DefineParameters(ParameterDeclarationCollection parameters, ParameterFactory defineParameter) - { - int last = parameters.Count - 1; - for (int i=0; i 0) - { - PropertyInfo[] namedProperties; - object[] propertyValues; - FieldInfo[] namedFields; - object[] fieldValues; - GetNamedValues(namedArgs, - out namedProperties, out propertyValues, - out namedFields, out fieldValues); - return new CustomAttributeBuilder( - constructorInfo, constructorArgs, - namedProperties, propertyValues, - namedFields, fieldValues); - } - return new CustomAttributeBuilder(constructorInfo, constructorArgs); - } - - void GetNamedValues(ExpressionPairCollection values, - out PropertyInfo[] outNamedProperties, - out object[] outPropertyValues, - out FieldInfo[] outNamedFields, - out object[] outFieldValues) - { - List namedProperties = new List(); - List propertyValues = new List(); - List namedFields = new List(); - List fieldValues = new List(); - foreach (ExpressionPair pair in values) - { - ITypedEntity entity = (ITypedEntity)GetEntity(pair.First); - object value = GetValue(entity.Type, pair.Second); - if (EntityType.Property == entity.EntityType) - { - namedProperties.Add(GetPropertyInfo(entity)); - propertyValues.Add(value); - } - else - { - namedFields.Add(GetFieldInfo((IField)entity)); - fieldValues.Add(value); - } - } - - outNamedProperties = (PropertyInfo[])namedProperties.ToArray(typeof(PropertyInfo)); - outPropertyValues = propertyValues.ToArray(); - outNamedFields = (FieldInfo[])namedFields.ToArray(typeof(FieldInfo)); - outFieldValues = fieldValues.ToArray(); - } - - object[] GetValues(IParameter[] targetParameters, ExpressionCollection expressions) - { - object[] values = new object[expressions.Count]; - for (int i=0; i 0) - { - if (!Path.IsPathRooted(fname)) - { - fname = ResolveRelative(outputFile, srcFile, fname); - } - using (FileStream stream = File.OpenRead(fname)) - { - //Parameters.DelaySign is ignored. - return new StrongNameKeyPair(stream); - } - } - return null; - } - - string ResolveRelative(string targetFile, string srcFile, string relativeFile) - { - //relative to current directory: - string fname = Path.GetFullPath(relativeFile); - if (File.Exists(fname)) - { - return fname; - } - - //relative to source file: - if (srcFile != null) - { - fname = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(srcFile), - relativeFile)); - if (File.Exists(fname)) - { - return fname; - } - } - - //relative to output assembly: - if (targetFile != null) - { - fname = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(targetFile), - relativeFile)); - } - return fname; - } - - Version GetAssemblyVersion() - { - string version = GetAssemblyAttributeValue("System.Reflection.AssemblyVersionAttribute"); - if (null == version) - { - version = "0.0.0.0"; - } - /* 1.0.* -- BUILD -- based on days since January 1, 2000 - * 1.0.0.* -- REVISION -- based on seconds since midnight, January 1, 2000, divided by 2 * - */ - string[] sliced = version.Split('.'); - if (sliced.Length > 2) - { - DateTime baseTime = new DateTime(2000, 1, 1); - TimeSpan mark = (DateTime.Now - baseTime); - if (sliced[2].StartsWith("*")) - { - sliced[2] = Math.Round(mark.TotalDays).ToString(); - } - if (sliced.Length > 3) - { - if (sliced[3].StartsWith("*")) - { - sliced[3] = Math.Round(mark.TotalSeconds).ToString(); - } - } - version = Boo.Lang.Builtins.join(sliced, "."); - } - return new Version(version); - } - - string GetAssemblyAttributeValue(string name) - { - Attribute attribute = GetAssemblyAttribute(name); - if (null != attribute) - { - return ((StringLiteralExpression)attribute.Arguments[0]).Value; - } - return null; - } - - Attribute GetAssemblyAttribute(string name) - { - Attribute[] attributes = _assemblyAttributes.Get(name); - if (attributes.Length > 0) - { - Debug.Assert(1 == attributes.Length); - return attributes[0]; - } - return null; - } - - protected override IType GetExpressionType(Expression node) - { - IType type = base.GetExpressionType(node); - if (TypeSystemServices.IsUnknown(type)) throw CompilerErrorFactory.InvalidNode(node); - return type; - } - } -} +#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 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 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(); + } + + /// + /// Ensures that all types are created in the correct order. + /// + 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) + { + AbstractInternalType tag = _emitter.GetType(baseTypeRef) as AbstractInternalType; + if (null != tag) + { + CreateType(tag.TypeDefinition); + } + } + } + + ((AbstractInternalType)type.Entity).GeneratedType = _emitter.GetTypeBuilder(type).CreateType(); + + Trace("type '{0}' successfully created", type); + + _current = saved; + } + } + + 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) +