public ParameterVariable DefineParameter(string name, TypeDefinition type) { ParameterVariable p = new ParameterVariable(name) { Offset = this.parameterOffset, Type = type }; parameterOffset += ((p.Type.Size + 3) / 4) * 4; symbols.Add(name, p); return p; }
public LocalVariable DefineLocalVariable(string name, TypeDefinition type) { int alignFix = localOffset % type.Size; if (alignFix > 0) { localOffset += type.Size - alignFix; } localOffset += type.Size; LocalVariable l = new LocalVariable(name) { Offset = this.localOffset, Type = type }; symbols.Add(name, l); return l; }
public TypeDefinition GetPointerType(TypeDefinition elementType) { TypeDefinition result = null; string fullName = "^" + elementType.FullName; if (!this.types.TryGetValue(fullName, out result)) { result = new TypeDefinition { FullName = fullName, IsPointer = true, Size = 4, InnerType = elementType }; this.types.Add(fullName, result); } return result; }
public void DefineVTable(TypeDefinition type) { string label = "$Vtbl_" + type.MangledName; if (this.DataSegment.Any(e => string.CompareOrdinal(e.Label, label) == 0)) { return; } string[] entries = new string[0]; Stack<TypeDefinition> typeStack = new Stack<TypeDefinition>(); TypeDefinition t = type; while (t != null) { typeStack.Push(t); t = t.BaseClass; } while (typeStack.Count > 0) { t = typeStack.Pop(); foreach (MethodInfo m in t.Methods) { if (m.IsVirtual) { if (entries.Length <= m.VTableIndex) { string[] newEntries = new string[m.VTableIndex + 1]; Array.Copy(entries, newEntries, entries.Length); entries = newEntries; } if (!m.IsAbstract) { this.AddProto(m); entries[m.VTableIndex] = m.MangledName; } else { entries[m.VTableIndex] = "0"; } } } } this.DataSegment.Add(new DataEntry { Label = label, Value = entries }); }
private bool TryEmitCopy( string sourceLocation, string targetLocation, TypeDefinition type, CompilerContext context, Scope scope, MethodImpl method) { if (string.CompareOrdinal("[ebx]", sourceLocation) != 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("lea ebx,{0}", sourceLocation) }); } if (string.CompareOrdinal("[edx]", targetLocation) != 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("lea edx,{0}", targetLocation) }); } int size = type.Size; while (size >= 4) { method.Statements.Add(new AsmStatement { Instruction = "mov eax, dword ptr [ebx]" }); method.Statements.Add(new AsmStatement { Instruction = "mov dword ptr [edx],eax" }); method.Statements.Add(new AsmStatement { Instruction = "add ebx,4" }); method.Statements.Add(new AsmStatement { Instruction = "add edx,4" }); size -= 4; } if (size >= 2) { method.Statements.Add(new AsmStatement { Instruction = "mov ax, word ptr [ebx]" }); method.Statements.Add(new AsmStatement { Instruction = "mov word ptr [edx],ax" }); method.Statements.Add(new AsmStatement { Instruction = "add ebx,2" }); method.Statements.Add(new AsmStatement { Instruction = "add edx,2" }); size -= 2; } if (size >= 1) { method.Statements.Add(new AsmStatement { Instruction = "mov al, byte ptr [ebx]" }); method.Statements.Add(new AsmStatement { Instruction = "mov byte ptr [edx],al" }); } return true; }
private bool TryCreateMethod( CompilerContext context, TypeDefinition type, MethodDeclaration methodDecl, out MethodInfo methodInfo) { methodInfo = new MethodInfo(type) { Name = methodDecl.MethodName, IsStatic = methodDecl.IsStatic, IsVirtual = methodDecl.IsVirtual || methodDecl.IsAbstract, IsAbstract = methodDecl.IsAbstract }; TypeDefinition returnType = null; if (methodDecl.ReturnType != null) { if (!this.TryResolveTypeReference(context, methodDecl.ReturnType, out returnType)) { return false; } methodInfo.ReturnType = returnType; } foreach (ParameterDeclaration paramDecl in methodDecl.Parameters) { TypeDefinition paramDef = null; if (!this.TryResolveTypeReference(context, paramDecl.Type, out paramDef)) { return false; } foreach (string name in paramDecl.ParameterNames) { ParameterInfo paramInfo = new ParameterInfo { Name = name, Type = paramDef }; methodInfo.Parameters.Add(paramInfo); } } if (methodInfo.IsVirtual) { methodInfo.AssignVTableIndex(); } return true; }
private bool ValidateConditionType(Expression condition, TypeDefinition conditionType) { string message = Properties.Resources.CodeGenerator_BooleanConditionExpected; if (string.CompareOrdinal(conditionType.MangledName, "f") != 0) { this.log.Write(new Message( condition.Start.Path, condition.Start.Line, condition.Start.Column, Severity.Error, message)); return false; } return true; }
private bool TryResolveTypeReference( CompilerContext context, TypeReference typeRef, out TypeDefinition typeDef) { NamedTypeReference namedType = typeRef as NamedTypeReference; if (namedType != null) { if (!context.TryFindTypeByName(namedType.TypeName, out typeDef)) { string message = string.Format( Properties.Resources.CodeGenerator_UndefinedType, namedType.TypeName); this.log.Write(new Message( namedType.Start.Path, namedType.Start.Line, namedType.Start.Column, Severity.Error, message)); return false; } return true; } PointerTypeReference pointerType = typeRef as PointerTypeReference; if (pointerType != null) { TypeDefinition innerType = null; if (!this.TryResolveTypeReference(context, pointerType.ElementType, out innerType)) { typeDef = null; return false; } typeDef = context.GetPointerType(innerType); return true; } ArrayTypeReference arrayType = typeRef as ArrayTypeReference; if (arrayType != null) { TypeDefinition innerType = null; if (!this.TryResolveTypeReference(context, arrayType.ElementType, out innerType)) { typeDef = null; return false; } int elementCount = 0; if (arrayType.ElementCount != null) { LiteralExpression litElementCount = arrayType.ElementCount as LiteralExpression; if (litElementCount == null || !(litElementCount.Value is int)) { log.Write(new Message( arrayType.ElementCount.Start.Path, arrayType.ElementCount.Start.Line, arrayType.ElementCount.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_ArrayTypeIntElementExpected)); typeDef = null; return false; } elementCount = (int)(litElementCount.Value); } typeDef = context.GetArrayType(innerType, elementCount); return true; } typeDef = null; return false; }
private bool TryFindSystemMemory(Token start, CompilerContext context, out TypeDefinition memoryType) { if (!context.TryFindTypeByName("System.Memory", out memoryType)) { log.Write(new Message( start.Path, start.Line, start.Column, Severity.Error, Properties.Resources.CodeGenerator_SystemMemoryNotDeclared)); return false; } return true; }
public bool TryFindMethodAndType( string methodNameRef, IList<TypeDefinition> parameterTypes, out TypeDefinition type, out MethodInfo methodInfo) { type = null; methodInfo = null; int methodStart = methodNameRef.LastIndexOf('.'); if (methodStart < 0) { return false; } string methodName = methodNameRef.Substring(methodStart + 1); string typeName = methodNameRef.Substring(0, methodStart); if (!TryFindTypeByName(typeName, out type)) { return false; } foreach (var test in type.Methods) { if (string.CompareOrdinal(test.Name, methodName) == 0) { bool match = true; if (test.Parameters.Count != parameterTypes.Count) { continue; } for (int i = 0; i < test.Parameters.Count; i++) { if (string.CompareOrdinal(test.Parameters[i].Type.FullName, parameterTypes[i].FullName) != 0) { match = false; break; } } if (!match) { continue; } methodInfo = test; return true; } } return false; }
public bool TryFindTypeByName(string nameRef, out TypeDefinition type) { if (types.TryGetValue(nameRef, out type)) { return true; } if (types.TryGetValue(this.Namespace + "." + nameRef, out type)) { return true; } foreach (string ns in this.uses) { if (types.TryGetValue(ns + "." + nameRef, out type)) { return true; } } type = null; return false; }
public bool TryFindConstructor( TypeDefinition objectType, IList<TypeDefinition> parameterTypes, out MethodInfo methodInfo) { methodInfo = null; foreach (MethodInfo constructor in objectType.Methods.Where(e => string.CompareOrdinal("constructor", e.Name) == 0)) { if (constructor.Parameters.Count != parameterTypes.Count) { continue; } bool match = true; for (int i = 0; i < parameterTypes.Count; i++) { if (string.CompareOrdinal(constructor.Parameters[i].Type.FullName, parameterTypes[i].FullName) != 0) { match = false; break; } } if (match) { methodInfo = constructor; return true; } } return false; }
public bool TryDeclareType(string name, out TypeDefinition typeDef) { string fullName = this.Namespace + "." + name; TypeDefinition existing = null; if (this.types.TryGetValue(fullName, out existing)) { typeDef = existing; return existing.Size == 0; } typeDef = new TypeDefinition { FullName = fullName }; this.types.Add(fullName, typeDef); return true; }
public CompilerContext() { TypeDefinition intType = new TypeDefinition { FullName = "integer", Size = 4, SpecialMangledName = "i" }; TypeDefinition shortType = new TypeDefinition { FullName = "short", Size = 2, SpecialMangledName = "i2" }; TypeDefinition longType = new TypeDefinition { FullName = "long", Size = 8, SpecialMangledName = "i8" }; TypeDefinition charType = new TypeDefinition { FullName = "character", Size = 2, SpecialMangledName = "c" }; TypeDefinition boolType = new TypeDefinition { FullName = "boolean", Size = 1, SpecialMangledName = "f" }; TypeDefinition byteType = new TypeDefinition { FullName = "byte", Size = 1, SpecialMangledName = "b" }; TypeDefinition singleType = new TypeDefinition { FullName = "single", Size = 4, SpecialMangledName = "s", IsFloatingPoint = true }; TypeDefinition doubleType = new TypeDefinition { FullName = "double", Size = 8, SpecialMangledName = "d", IsFloatingPoint = true }; TypeDefinition extendedType = new TypeDefinition { FullName = "extended", Size = 10, SpecialMangledName = "e", IsFloatingPoint = true }; TypeDefinition genericPointerType = new TypeDefinition { FullName = "^", Size = 4, SpecialMangledName = "p", IsPointer = true }; types.Add(intType.FullName, intType); types.Add(shortType.FullName, shortType); types.Add(longType.FullName, longType); types.Add(charType.FullName, charType); types.Add(singleType.FullName, singleType); types.Add(doubleType.FullName, doubleType); types.Add(extendedType.FullName, extendedType); types.Add(boolType.FullName, boolType); types.Add(byteType.FullName, byteType); types.Add(genericPointerType.FullName, genericPointerType); }
private bool TryEmitSimpleExpression( SimpleExpression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { TypeDefinition rightSideType = null; if (!this.TryEmitExpression(expression.Right, context, scope, method, out rightSideType)) { valueType = null; return false; } this.PushResult(method, rightSideType); TypeDefinition leftSideType = null; if (!this.TryEmitExpression(expression.Left, context, scope, method, out leftSideType)) { valueType = null; return false; } if (leftSideType.IsFloatingPoint) { if (rightSideType.IsFloatingPoint) { if (rightSideType.Size == 8) { method.Statements.Add(new AsmStatement { Instruction = "fld qword ptr [esp]" }); } else { method.Statements.Add(new AsmStatement { Instruction = "fld dword ptr [esp]" }); } method.Statements.Add(new AsmStatement { Instruction = "add esp," + rightSideType.Size }); } else if (rightSideType.Size <= 4) { method.Statements.Add(new AsmStatement { Instruction = "fild [esp]" }); method.Statements.Add(new AsmStatement { Instruction = "add esp," + rightSideType.Size }); } switch (expression.Operator) { case Keyword.Plus: { method.Statements.Add(new AsmStatement { Instruction = "faddp" }); } break; case Keyword.Minus: { method.Statements.Add(new AsmStatement { Instruction = "fsubp" }); } break; } } else if (leftSideType.Size <= 4) { if (rightSideType.Size <= 4 && !rightSideType.IsFloatingPoint) { method.Statements.Add(new AsmStatement { Instruction = "pop ecx" }); switch (expression.Operator) { case Keyword.Plus: { method.Statements.Add(new AsmStatement { Instruction = "add eax,ecx" }); } break; case Keyword.Minus: { method.Statements.Add(new AsmStatement { Instruction = "sub eax,ecx" }); } break; case Keyword.Or: { method.Statements.Add(new AsmStatement { Instruction = "or eax,ecx" }); } break; } } } valueType = leftSideType; return true; }
public LocalVariable DefineTempVariable(TypeDefinition type) { string name = "$temp" + (this.tempVariableIndex++).ToString(); this.DefineLocalVariable(name, type); return (LocalVariable)symbols[name]; }
private bool TryEmitTermExpression( TermExpression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { TypeDefinition rightSideType = null; if (!this.TryEmitExpression(expression.Right, context, scope, method, out rightSideType)) { valueType = null; return false; } this.PushResult(method, rightSideType); TypeDefinition leftSideType = null; if (!this.TryEmitExpression(expression.Left, context, scope, method, out leftSideType)) { valueType = null; return false; } if (leftSideType.IsFloatingPoint) { if (rightSideType.IsFloatingPoint) { if (rightSideType.Size == 8) { method.Statements.Add(new AsmStatement { Instruction = "fld qword ptr [esp]" }); } else { method.Statements.Add(new AsmStatement { Instruction = "fld dword ptr [esp]" }); } method.Statements.Add(new AsmStatement { Instruction = "add esp," + rightSideType.Size }); } else if (rightSideType.Size <= 4) { method.Statements.Add(new AsmStatement { Instruction = "fild [esp]" }); method.Statements.Add(new AsmStatement { Instruction = "add esp," + rightSideType.Size }); } switch (expression.Operator) { case Keyword.Star: { method.Statements.Add(new AsmStatement { Instruction = "fmulp" }); } break; case Keyword.Slash: { method.Statements.Add(new AsmStatement { Instruction = "fdivp" }); } break; } } else if (leftSideType.Size <= 4) { if (rightSideType.Size <= 4 && !rightSideType.IsFloatingPoint) { method.Statements.Add(new AsmStatement { Instruction = "pop ecx" }); switch (expression.Operator) { case Keyword.Star: { method.Statements.Add(new AsmStatement { Instruction = "imul eax,ecx" }); } break; case Keyword.Mod: { method.Statements.Add(new AsmStatement { Instruction = "xor edx,edx" }); method.Statements.Add(new AsmStatement { Instruction = "idiv ecx" }); method.Statements.Add(new AsmStatement { Instruction = "mov eax,edx" }); } break; case Keyword.And: { method.Statements.Add(new AsmStatement { Instruction = "and eax,ecx" }); } break; case Keyword.Div: { method.Statements.Add(new AsmStatement { Instruction = "xor edx,edx" }); method.Statements.Add(new AsmStatement { Instruction = "idiv ecx" }); } break; } } } valueType = leftSideType; return true; }
private bool TryEmitLiteralExpression( LiteralExpression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { if (expression.Value == null) { method.Statements.Add(new AsmStatement { Instruction = "xor eax,eax" }); return context.TryFindTypeByName("^", out valueType); } if (expression.Value is int) { if ((int)expression.Value == 0) { method.Statements.Add(new AsmStatement { Instruction = "xor eax,eax" }); } else { method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax,{0}", expression.Value) }); } return context.TryFindTypeByName("integer", out valueType); } if (expression.Value is char) { method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax,{0}", (int)expression.Value) }); return context.TryFindTypeByName("character", out valueType); } if (expression.Value is string) { string label = method.Module.DefineLiteralString((string)expression.Value); method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,[offset {0}]", label) }); return context.TryFindTypeByName("#0character", out valueType); } if (expression.Value is decimal) { decimal exprValue = (decimal)expression.Value; if (exprValue == 0.0M) { method.Statements.Add(new AsmStatement { Instruction = "fldz" }); } else if (exprValue == 1.0M) { method.Statements.Add(new AsmStatement { Instruction = "fld1" }); } else { string label = method.Module.DefineConstant((double)exprValue); method.Statements.Add(new AsmStatement { Instruction = string.Format("fld qword ptr [{0}]", label) }); } return context.TryFindTypeByName("double", out valueType); } if (expression.Value is bool) { bool boolVal = (bool)expression.Value; if (boolVal) { method.Statements.Add(new AsmStatement { Instruction = "mov eax,1" }); } else { method.Statements.Add(new AsmStatement { Instruction = "xor eax,eax" }); } return context.TryFindTypeByName("boolean", out valueType); } valueType = null; return false; }
private bool TryImplementMethod( MethodImpl method, CompilerContext context, MethodDefinition methodDef, TypeDefinition typeDef) { bool failed = false; if (method.Method.Type.GetVTablePointer() != null) { method.Module.DefineVTable(method.Method.Type); } if (!string.IsNullOrEmpty(methodDef.ExternImpl)) { method.Module.AddExtern(methodDef.ExternImpl); method.Statements.Add(new AsmStatement { Instruction = "jmp " + methodDef.ExternImpl }); return true; } Stack<LocalVariable> destructables = new Stack<LocalVariable>(); Scope scope = context.BeginScope(method.Method); if (string.CompareOrdinal(method.Method.Name, "constructor") == 0) { if (method.Method.Type.BaseClass != null) { MethodInfo baseInit = null; int argSize = 0; if (methodDef.BaseConstructorArguments.Count > 0) { List<TypeDefinition> argTypes = new List<TypeDefinition>(); foreach (Expression arg in methodDef.BaseConstructorArguments.Reverse()) { TypeDefinition valueType = null; if (!this.TryEmitExpression(arg, context, scope, method, out valueType)) { return false; } PushResult(method, valueType); argSize += ((valueType.Size + 3) / 4) * 4; argTypes.Insert(0, valueType); } baseInit = method.Method.Type.BaseClass.FindConstructor(argTypes); if (baseInit == null) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_CannotFindConstructor, method.Method.Type.BaseClass); log.Write(new Message( methodDef.Start.Path, methodDef.Start.Line, methodDef.Start.Column, Severity.Error, message)); return false; } } else { baseInit = method.Method.Type.BaseClass.GetDefaultConstructor(); } if (baseInit != null) { method.Module.AddProto(baseInit); method.Statements.Add(new AsmStatement { Instruction = "mov ecx,_this$[ebp]" }); method.Statements.Add(new AsmStatement { Instruction = "push ecx" }); argSize += 4; method.Statements.Add(new AsmStatement { Instruction = "call " + baseInit.MangledName }); method.Statements.Add(new AsmStatement { Instruction = "add esp," + argSize }); } } FieldInfo vtable = method.Method.Type.GetVTablePointer(); if (vtable != null) { // method.Module.ExternList.Add("$Vtbl_" + method.Method.Type.MangledName); method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,[$Vtbl_{0}]", method.Method.Type.MangledName) }); method.Statements.Add(new AsmStatement { Instruction = "mov ecx,_this$[ebp]" }); if (vtable.Offset > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", vtable.Offset) }); } method.Statements.Add(new AsmStatement { Instruction = "mov [ecx],eax" }); } // init member vars foreach (FieldInfo field in method.Method.Type.Fields) { if (field.IsStatic || !field.Type.IsClass) { continue; } MethodInfo memberConstructor = field.Type.GetDefaultConstructor(); if (memberConstructor != null) { method.Statements.Add(new AsmStatement { Instruction = "mov ecx,_this$[ebp]" }); if (field.Offset > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", field.Offset) }); } method.Statements.Add(new AsmStatement { Instruction = "push ecx" }); method.Module.AddProto(memberConstructor); method.Statements.Add(new AsmStatement { Instruction = "call " + memberConstructor.MangledName }); method.Statements.Add(new AsmStatement { Instruction = "add esp,4" }); } } } if (methodDef.LocalVariables != null) { foreach (VariableDeclaration varDecl in methodDef.LocalVariables.Variables) { TypeDefinition varType = null; if (!this.TryResolveTypeReference(context, varDecl.Type, out varType)) { failed = true; continue; } MethodInfo defaultConstructor = varType.GetDefaultConstructor(); MethodInfo destructor = varType.GetDestructor(); foreach (string varName in varDecl.VariableNames) { LocalVariable localVar = scope.DefineLocalVariable(varName, varType); if (destructor != null) { destructables.Push(localVar); } if (varDecl.InitExpression != null) { TypeDefinition initValueType = null; if (!this.TryEmitExpression(varDecl.InitExpression, context, scope, method, out initValueType)) { failed = true; continue; } if (varType.IsPointer || varType.IsArray && varType.ArrayElementCount == 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("mov _{0}$[ebp],eax", localVar.Name) }); } else if (varType.IsFloatingPoint) { if (varType.Size == 4) { method.Statements.Add(new AsmStatement { Instruction = string.Format("fstp dword ptr _{0}$[ebp]", localVar.Name) }); } else { method.Statements.Add(new AsmStatement { Instruction = string.Format("fstp qword ptr _{0}$[ebp]", localVar.Name) }); } } else if (!varType.IsClass) { switch (varType.Size) { case 1: method.Statements.Add(new AsmStatement { Instruction = string.Format("mov byte ptr _{0}$[ebp],al", localVar.Name) }); break; case 2: method.Statements.Add(new AsmStatement { Instruction = string.Format("mov word ptr _{0}$[ebp],ax", localVar.Name) }); break; case 4: method.Statements.Add(new AsmStatement { Instruction = string.Format("mov _{0}$[ebp],eax", localVar.Name) }); break; } } } else if (defaultConstructor != null) { method.Module.AddProto(defaultConstructor); method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,_{0}$[ebp]", localVar.Name) }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); method.Statements.Add(new AsmStatement { Instruction = "call " + defaultConstructor.MangledName }); method.Statements.Add(new AsmStatement { Instruction = "add esp,4" }); } } } } // statements alloc temp variables, so the frame setup code has to be last. if (!this.TryEmitBlockStatement(methodDef.Body, context, scope, method)) { failed = true; } List<AsmStatement> frame = new List<AsmStatement>(); frame.Add(new AsmStatement { Instruction = "push ebp" }); frame.Add(new AsmStatement { Instruction = "mov ebp,esp" }); if (scope.LocalOffset != 0) { int localOffset = scope.LocalOffset; int alignFix = localOffset % 4; if (alignFix != 0) { localOffset += 4 - alignFix; } frame.Add(new AsmStatement { Instruction = "sub esp," + localOffset }); } method.Statements.InsertRange(0, frame); while (destructables.Count > 0) { LocalVariable destructable = destructables.Pop(); MethodInfo destructor = destructable.Type.GetDestructor(); method.Module.AddProto(destructor); method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,_{0}$[ebp]", destructable.Name) }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); method.Statements.Add(new AsmStatement { Instruction = "call " + destructor.MangledName }); method.Statements.Add(new AsmStatement { Instruction = "add esp,4" }); } if (method.Method.ReturnType != null) { SymbolEntry returnVar = scope.ReturnVariable; if (method.Method.ReturnType.IsFloatingPoint) { if (method.Method.ReturnType.Size == 8) { method.Statements.Add(new AsmStatement { Instruction = string.Format("fld qword ptr _{0}$[ebp]", returnVar.Name) }); } else { method.Statements.Add(new AsmStatement { Instruction = string.Format("fld dword ptr _{0}$[ebp]", returnVar.Name) }); } } else if (method.Method.ReturnType.Size <= 8 && !method.Method.ReturnType.IsClass) { if (method.Method.ReturnType.Size > 4) { method.Statements.Add(new AsmStatement { Instruction = string.Format("lea ecx,dword ptr _{0}$[ebp]", returnVar.Name) }); method.Statements.Add(new AsmStatement { Instruction = "mov eax,dword ptr [ecx]" }); method.Statements.Add(new AsmStatement { Instruction = "add ecx,4" }); switch (method.Method.ReturnType.Size) { case 8: method.Statements.Add(new AsmStatement { Instruction = "mov edx,dword ptr [ecx]" }); break; case 7: method.Statements.Add(new AsmStatement { Instruction = "mov edx,dword ptr [ecx]" }); break; case 6: method.Statements.Add(new AsmStatement { Instruction = "mov dx,word ptr [ecx]" }); break; case 5: method.Statements.Add(new AsmStatement { Instruction = "mov dl,byte ptr [ecx]" }); break; } } else { switch (method.Method.ReturnType.Size) { case 4: method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax, dword ptr _{0}$[ebp]", returnVar.Name) }); break; case 3: method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax, dword ptr _{0}$[ebp]", returnVar.Name) }); break; case 2: method.Statements.Add(new AsmStatement { Instruction = string.Format("mov ax, word ptr _{0}$[ebp]", returnVar.Name) }); break; case 1: method.Statements.Add(new AsmStatement { Instruction = string.Format("mov al, byte ptr _{0}$[ebp]", returnVar.Name) }); if (string.CompareOrdinal(returnVar.Type.MangledName, "f") == 0) { method.Statements.Add(new AsmStatement { Instruction = "and eax,1" }); } break; } } } else { method.Statements.Add( new AsmStatement { Instruction = string.Format("mov edx, _{0}$[ebp]", scope.LargeReturnVariable.Name) }); if (!TryEmitCopy( string.Format("_{0}$[ebp]", returnVar.Name), "[edx]", returnVar.Type, context, scope, method)) { failed = true; } } } if (string.CompareOrdinal("destructor", method.Method.Name) == 0) { // call destructors on all fields. foreach (FieldInfo field in method.Method.Type.Fields) { if (!field.IsStatic) { if (field.Type.IsClass) { MethodInfo memberDestructor = field.Type.GetDestructor(); if (memberDestructor != null) { method.Statements.Add(new AsmStatement { Instruction = "mov ecx,_this$[ebp]" }); if (field.Offset > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", field.Offset) }); } method.Statements.Add(new AsmStatement { Instruction = "push ecx" }); if (memberDestructor.IsVirtual) { FieldInfo memberVTable = field.Type.GetVTablePointer(); if (memberVTable.Offset > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", memberVTable.Offset) }); } method.Statements.Add(new AsmStatement { Instruction = "mov eax,[ecx]" }); if (memberDestructor.VTableIndex > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add eax,{0}", memberDestructor.VTableIndex * 4) }); } method.Statements.Add(new AsmStatement { Instruction = "call dword ptr [eax]" }); } else { method.Module.AddProto(memberDestructor); method.Statements.Add(new AsmStatement { Instruction = "call " + memberDestructor.MangledName }); } method.Statements.Add(new AsmStatement { Instruction = "add esp,4" }); } } } } // call base class destructor at the end. TypeDefinition baseClass = method.Method.Type.BaseClass; if (baseClass != null) { MethodInfo baseDestructor = baseClass.GetDestructor(); if (baseDestructor != null) { method.Module.AddProto(baseDestructor); method.Statements.Add(new AsmStatement { Instruction = "mov eax,_this$[ebp]" }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); method.Statements.Add(new AsmStatement { Instruction = "call " + baseDestructor.MangledName }); method.Statements.Add(new AsmStatement { Instruction = "add esp,4" }); } } } method.Statements.Add(new AsmStatement { Instruction = "mov esp,ebp" }); method.Statements.Add(new AsmStatement { Instruction = "pop ebp" }); method.Statements.Add(new AsmStatement { Instruction = "ret" }); scope.SaveSymbols(method.Symbols); return !failed; }
private bool TryEmitNegativeExpression( NegativeExpression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { if (!this.TryEmitExpression(expression.Inner, context, scope, method, out valueType)) { return false; } if (valueType.IsFloatingPoint) { method.Statements.Add(new AsmStatement { Instruction = "fchs" }); } else if (valueType.IsPointer || valueType.IsClass || valueType.IsArray || valueType.IsInterface) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_NegativeNotSupported, valueType.FullName); this.log.Write(new Message( expression.Start.Path, expression.Start.Line, expression.Start.Column, Severity.Error, message)); return false; } else { method.Statements.Add(new AsmStatement { Instruction = "neg eax" }); } return true; }
private bool ValidateCanCast( ParseNode node, TypeDefinition storageType, TypeDefinition valueType) { if (string.CompareOrdinal(storageType.MangledName, valueType.MangledName) == 0) { return true; } bool canCast = false; if (valueType.IsArray && storageType.IsPointer) { if (valueType.ArrayElementCount == 0) { canCast = storageType.InnerType == null || string.CompareOrdinal(storageType.InnerType.MangledName, "b") == 0 || string.CompareOrdinal(valueType.InnerType.MangledName, "b") == 0 || this.ValidateCanCast(node, storageType.InnerType, valueType.InnerType); } } else if (valueType.IsPointer && storageType.IsArray) { if (storageType.ArrayElementCount == 0) { canCast = valueType.InnerType == null || string.CompareOrdinal(storageType.InnerType.MangledName, "b") == 0 || string.CompareOrdinal(valueType.InnerType.MangledName, "b") == 0 || this.ValidateCanCast(node, storageType.InnerType, valueType.InnerType); } } else if (valueType.IsPointer && storageType.IsPointer) { canCast = storageType.InnerType == null || valueType.InnerType == null; if (!canCast) { if (valueType.InnerType.IsClass && storageType.InnerType.IsClass) { TypeDefinition testClass = valueType.InnerType; while (!canCast && testClass != null) { if (string.CompareOrdinal(testClass.MangledName, storageType.InnerType.MangledName) == 0) { canCast = true; } else { testClass = testClass.BaseClass; } } } else { canCast = string.CompareOrdinal(storageType.InnerType.MangledName, "b") == 0 || string.CompareOrdinal(valueType.InnerType.MangledName, "b") == 0 || this.ValidateCanCast(node, storageType.InnerType, valueType.InnerType); } } } else if (valueType.IsArray && storageType.IsArray) { if (storageType.ArrayElementCount == 0) { canCast = this.ValidateCanCast(node, storageType.InnerType, valueType.InnerType); } } if (!canCast) { string message = string.Format( System.Globalization.CultureInfo.InvariantCulture, Properties.Resources.CodeGenerator_NoAutomaticConversion, storageType.FullName, valueType.FullName); this.log.Write(new Message( node.Start.Path, node.Start.Line, node.Start.Column, Severity.Error, message)); } return canCast; }
private bool TryEmitNewExpression( NewExpression newExpr, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { valueType = null; TypeDefinition objectType = null; if (!this.TryResolveTypeReference(context, newExpr.Type, out objectType)) { valueType = null; return false; } if (!objectType.IsClass && newExpr.ConstructorArguments.Count() > 0) { log.Write(new Message( newExpr.Start.Path, newExpr.Start.Line, newExpr.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_ConstructorArgumentsAreOnlySupportedOnClassTypes)); return false; } valueType = context.GetPointerType(objectType); if (!this.TryEmitAllocCall(newExpr.Start, context, scope, method, objectType.Size)) { return false; } MethodInfo constructor = null; int argSize = 0; if (objectType.IsClass) { int nullTestStart = method.Statements.Count; List<TypeDefinition> argTypes = new List<TypeDefinition>(); foreach (Expression arg in newExpr.ConstructorArguments.Reverse()) { TypeDefinition argType = null; if (!this.TryEmitExpression(arg, context, scope, method, out argType)) { return false; } this.PushResult(method, argType); argSize += ((argType.Size + 3) / 4) * 4; argTypes.Insert(0, argType); } if (!context.TryFindConstructor(objectType, argTypes, out constructor)) { // ok to have no default constructor if (argTypes.Count > 0) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_CannotFindConstructor, objectType.FullName); log.Write(new Message( newExpr.Start.Path, newExpr.Start.Line, newExpr.Start.Column, Severity.Error, message)); return false; } } if (constructor != null) { LocalVariable tempPtr = scope.DefineTempVariable(valueType); string jumpLabel = method.Module.GetNextJumpLabel(); List<AsmStatement> saveAlloc = new List<AsmStatement>(); saveAlloc.Add(new AsmStatement { Instruction = string.Format("mov _{0}$[ebp],eax", tempPtr.Name) }); saveAlloc.Add(new AsmStatement { Instruction = "test eax,eax" }); saveAlloc.Add(new AsmStatement { Instruction = "jz " + jumpLabel }); method.Statements.InsertRange(nullTestStart, saveAlloc); method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax,_{0}$[ebp]", tempPtr.Name) }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); method.Module.AddProto(constructor); method.Statements.Add(new AsmStatement { Instruction = "call " + constructor.MangledName }); method.Statements.Add(new AsmStatement { Instruction = string.Format("add esp,{0}", argSize + 4) }); method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax,_{0}$[ebp]", tempPtr.Name), Label = jumpLabel }); } } return true; }
private void PushResult( MethodImpl method, TypeDefinition type) { if (type.IsFloatingPoint) { if (type.Size == 4) { method.Statements.Add(new AsmStatement { Instruction = "sub esp,4" }); method.Statements.Add(new AsmStatement { Instruction = "fstp dword ptr [esp]" }); } else if (type.Size == 8) { method.Statements.Add(new AsmStatement { Instruction = "sub esp,8" }); method.Statements.Add(new AsmStatement { Instruction = "fstp qword ptr [esp]" }); } else { method.Statements.Add(new AsmStatement { Instruction = "sub esp,10" }); method.Statements.Add(new AsmStatement { Instruction = "fstp tword ptr [esp]" }); } } else if (type.IsArray) { method.Statements.Add(new AsmStatement { Instruction = "push eax" }); } else if (!type.IsClass) { if (type.Size <= 4) { method.Statements.Add(new AsmStatement { Instruction = "push eax" }); } else if(type.Size == 8) { method.Statements.Add(new AsmStatement { Instruction = "push edx" }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); } } }
private bool TryEmitNotExpression( NotExpression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { if (!this.TryEmitExpression(expression.Inner, context, scope, method, out valueType)) { return false; } if (valueType.IsPointer || valueType.IsClass || valueType.IsArray || valueType.IsInterface || valueType.IsFloatingPoint || valueType.Size > 4) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_NotNotSupported, valueType.FullName); this.log.Write(new Message( expression.Start.Path, expression.Start.Line, expression.Start.Column, Severity.Error, message)); return false; } else { switch (valueType.Size) { case 4: method.Statements.Add(new AsmStatement { Instruction = "not eax" }); break; case 2: method.Statements.Add(new AsmStatement { Instruction = "not ax" }); break; case 1: method.Statements.Add(new AsmStatement { Instruction = "not al" }); break; } if (string.CompareOrdinal(valueType.MangledName, "f") == 0) { method.Statements.Add(new AsmStatement { Instruction = "and al,1" }); } } return true; }
private bool TryEmitAddressExpression( AddressExpression addrExpr, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { string innerLoc = null; TypeDefinition storageType = null; MethodInfo calleeMethod = null; if (!this.TryEmitReference(addrExpr.Inner, context, scope, method, out innerLoc, out storageType, out calleeMethod)) { valueType = null; return false; } method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", innerLoc) }); valueType = context.GetPointerType(storageType); return true; }
private bool TryEmitReference( ReferenceExpression referenceExpression, CompilerContext context, Scope scope, MethodImpl method, out string location, out TypeDefinition storageType, out MethodInfo calleeMethod) { calleeMethod = null; NamedReferenceExpression namedRef = referenceExpression as NamedReferenceExpression; if (namedRef != null) { SymbolEntry symbol = null; if (scope.TryLookup(namedRef.Identifier, out symbol)) { storageType = symbol.Type; LocalVariable localVar = symbol as LocalVariable; if (localVar != null) { location = string.Format("_{0}$[ebp]", localVar.Name); return true; } else { ParameterVariable parVar = symbol as ParameterVariable; if (parVar != null) { location = string.Format("_{0}$[ebp]", parVar.Name); return true; } } } foreach (var field in method.Method.Type.Fields) { if (string.CompareOrdinal(field.Name, namedRef.Identifier) == 0) { SymbolEntry symThis = null; if(!scope.TryLookup("this", out symThis)) { storageType = null; location = null; return false; } method.Statements.Add( new AsmStatement { Instruction = "mov ecx,_this$[ebp]" }); if (field.Offset > 0) { method.Statements.Add( new AsmStatement { Instruction = "add ecx," + field.Offset }); } storageType = field.Type; location = "[ecx]"; return true; } } foreach (var memberMethod in method.Method.Type.Methods) { if (string.CompareOrdinal(memberMethod.Name, namedRef.Identifier) == 0) { method.Module.AddProto(memberMethod); if (!memberMethod.IsStatic) { SymbolEntry symThis = null; if (!scope.TryLookup("this", out symThis)) { storageType = null; location = null; return false; } method.Statements.Add( new AsmStatement { Instruction = "mov ecx,_this$[ebp]" }); method.Statements.Add(new AsmStatement { Instruction = "push ecx" }); } if (memberMethod.IsVirtual) { location = "[ecx]"; } else { location = memberMethod.MangledName; } storageType = memberMethod.ReturnType; calleeMethod = memberMethod; return true; } } if (context.TryFindTypeByName(namedRef.Identifier, out storageType)) { location = null; return true; } string message = string.Format( Properties.Resources.CodeGenerator_UndeclaredIdentifier, namedRef.Identifier); log.Write(new Message( namedRef.Start.Path, namedRef.Start.Line, namedRef.Start.Column, Severity.Error, message)); } MemberReferenceExpression memberRef = referenceExpression as MemberReferenceExpression; if (memberRef != null) { string innerLoc = null; TypeDefinition innerType = null; MethodInfo innerCalleeMethod = null; if (this.TryEmitReference(memberRef.Inner, context, scope, method, out innerLoc, out innerType, out innerCalleeMethod)) { foreach (var field in innerType.Fields) { if (string.CompareOrdinal(field.Name, memberRef.MemberName) == 0) { method.Statements.Add( new AsmStatement { Instruction = string.Format("lea ecx,{0}", innerLoc) }); if (field.Offset > 0) { method.Statements.Add( new AsmStatement { Instruction = "add ecx," + field.Offset }); } storageType = field.Type; location = "[ecx]"; return true; } } foreach (var memberMethod in innerType.Methods) { if (string.CompareOrdinal(memberMethod.Name, memberRef.MemberName) == 0) { method.Module.AddProto(memberMethod); if (!memberMethod.IsStatic) { method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", innerLoc) }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); } if (memberMethod.IsVirtual && memberRef.UseVirtualDispatch) { location = "[eax]"; } else { location = memberMethod.MangledName; } storageType = memberMethod.ReturnType; calleeMethod = memberMethod; return true; } } string message = string.Format( Properties.Resources.CodeGenerator_UndeclaredMember, memberRef.MemberName, innerType.FullName); log.Write(new Message( memberRef.Start.Path, memberRef.Start.Line, memberRef.Start.Column, Severity.Error, message)); } } CallReferenceExpression callExpr = referenceExpression as CallReferenceExpression; if (callExpr != null) { location = null; return this.TryEmitExpression(callExpr, context, scope, method, out storageType); } ArrayIndexReferenceExpression arrayIndexExpr = referenceExpression as ArrayIndexReferenceExpression; if (arrayIndexExpr != null) { TypeDefinition indexType = null; if (!this.TryEmitExpression( arrayIndexExpr.Index, context, scope, method, out indexType)) { location = null; storageType = null; return false; } if (indexType.IsFloatingPoint || indexType.IsArray || indexType.IsClass || indexType.IsPointer) { this.log.Write(new Message( arrayIndexExpr.Index.Start.Path, arrayIndexExpr.Index.Start.Line, arrayIndexExpr.Index.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_ArrayIndexIntExpected)); location = null; storageType = null; return false; } method.Statements.Add(new AsmStatement { Instruction = "push eax" }); string innerLoc = null; TypeDefinition innerType = null; MethodInfo arrayCalleeMethod = null; if (!this.TryEmitReference( arrayIndexExpr.Inner, context, scope, method, out innerLoc, out innerType, out arrayCalleeMethod)) { location = null; storageType = null; return false; } if (!innerType.IsArray) { log.Write(new Message( arrayIndexExpr.Inner.Start.Path, arrayIndexExpr.Inner.Start.Line, arrayIndexExpr.Inner.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_ArrayTypeExpected)); location = null; storageType = null; return false; } if (innerType.Size > 4) { method.Statements.Add(new AsmStatement { Instruction = "lea ecx," + innerLoc }); } else { method.Statements.Add(new AsmStatement { Instruction = "mov ecx," + innerLoc }); } method.Statements.Add(new AsmStatement { Instruction = "pop eax" }); int elementSize = innerType.InnerType.Size; if(elementSize > 1) { int shiftSize = 0; switch(elementSize) { case 2: shiftSize = 1; break; case 4: shiftSize = 2; break; case 8: shiftSize = 3; break; case 16: shiftSize = 4; break; case 32: shiftSize = 5; break; case 64: shiftSize = 6; break; default: method.Statements.Add(new AsmStatement { Instruction = string.Format("imul eax,{0}", elementSize) }); break; } if (shiftSize != 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("shl eax,{0}", shiftSize) }); } } method.Statements.Add(new AsmStatement { Instruction = "add ecx,eax" }); location = "[ecx]"; storageType = innerType.InnerType; return true; } DereferenceExpression derefExpr = referenceExpression as DereferenceExpression; if (derefExpr != null) { string innerLoc = null; TypeDefinition innerType = null; MethodInfo innerCall = null; if (!this.TryEmitReference( derefExpr.Inner, context, scope, method, out innerLoc, out innerType, out innerCall)) { location = null; storageType = null; return false; } if (!innerType.IsPointer) { log.Write(new Message( derefExpr.Start.Path, derefExpr.Start.Line, derefExpr.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_CannotDerefNonPointer)); location = null; storageType = null; return false; } method.Statements.Add(new AsmStatement { Instruction = "mov ecx," + innerLoc }); location = "[ecx]"; storageType = innerType.InnerType; return true; } InheritedReferenceExpression inhRefExpr = referenceExpression as InheritedReferenceExpression; if (inhRefExpr != null) { storageType = method.Method.Type.BaseClass; if (storageType == null) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_NoBaseTypeForInherited, method.Method.Type.FullName); this.log.Write(new Message( inhRefExpr.Start.Path, inhRefExpr.Start.Line, inhRefExpr.Start.Column, Severity.Error, message)); location = null; return false; } SymbolEntry thisSymbol = null; if (!scope.TryLookup("this", out thisSymbol)) { // reference a static on the base class. location = null; } else { location = "_this$[ebp]"; } return true; } location = null; storageType = null; return false; }
private bool TryEmitExpression( Expression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { LiteralExpression literalExpr = expression as LiteralExpression; if (literalExpr != null) { return this.TryEmitLiteralExpression(literalExpr, context, scope, method, out valueType); } CallReferenceExpression callExpr = expression as CallReferenceExpression; if (callExpr != null) { int argSize = 0; int argStatementStart = method.Statements.Count; Expression[] arguments = callExpr.Arguments.ToArray(); List<TypeDefinition> argTypes = new List<TypeDefinition>(); for (int i = arguments.Length - 1; i >= 0; i--) { TypeDefinition argType = null; if (!this.TryEmitExpression(arguments[i], context, scope, method, out argType)) { valueType = null; return false; } argTypes.Insert(0, argType); argSize += ((argType.Size + 3) / 4) * 4; this.PushResult(method, argType); } string callLoc = null; TypeDefinition storageType = null; MethodInfo calleeMethod = null; if (!this.TryEmitReference(callExpr.Inner, context, scope, method, out callLoc, out storageType, out calleeMethod)) { valueType = null; return false; } // fix up calling overloads here vs. inside TryEmitReference. if (calleeMethod != null) { MethodInfo overload = calleeMethod.Type.FindMethod(calleeMethod.Name, argTypes); if (overload != null) { if (string.CompareOrdinal(calleeMethod.MangledName, callLoc) == 0) { callLoc = overload.MangledName; } method.Module.AddProto(overload); calleeMethod = overload; storageType = overload.ReturnType; } } if (storageType != null) { if (callLoc == null) { // must be a constructor call. MethodInfo constructor = storageType.FindConstructor(argTypes); if (constructor == null) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_CannotFindConstructor, storageType.FullName); log.Write(new Message( callExpr.Start.Path, callExpr.Start.Line, callExpr.Start.Column, Severity.Error, message)); valueType = null; return false; } calleeMethod = constructor; callLoc = constructor.MangledName; method.Module.AddProto(constructor); // create room on the stack for the result. AsmStatement resultPush = new AsmStatement { Instruction = string.Format("sub esp,{0}", storageType.Size) }; method.Statements.Insert(argStatementStart, resultPush); // push the ref to the storage for the class on the stack. method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,[esp+{0}]", argSize) }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); } else if (storageType.IsClass || !storageType.IsFloatingPoint && storageType.Size > 8) { // create room on the stack for the result. AsmStatement resultPush = new AsmStatement { Instruction = string.Format("sub esp,{0}", storageType.Size) }; method.Statements.Insert(argStatementStart, resultPush); // push the ref to the storage for the class on the stack. method.Statements.Add(new AsmStatement { Instruction = string.Format( "lea ebx,[esp+{0}]", calleeMethod.IsStatic ? argSize : argSize + 4) }); method.Statements.Add(new AsmStatement { Instruction = "push ebx" }); argSize += 4; } } if (calleeMethod.IsVirtual && callExpr.Inner.UseVirtualDispatch) { FieldInfo vtablePtr = calleeMethod.Type.GetVTablePointer(); if (string.CompareOrdinal(callLoc, "[eax]") != 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", callLoc) }); } if (vtablePtr.Offset > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add eax,{0}", vtablePtr.Offset) }); } method.Statements.Add(new AsmStatement { Instruction = "mov ecx,[eax]" }); if (calleeMethod.VTableIndex > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", calleeMethod.VTableIndex * 4) }); } method.Statements.Add(new AsmStatement { Instruction = "call dword ptr [ecx]" }); } else { method.Statements.Add(new AsmStatement { Instruction = "call " + callLoc }); } if (!calleeMethod.IsStatic) { argSize += 4; } if (argSize > 0) { method.Statements.Add(new AsmStatement { Instruction = "add esp," + argSize.ToString() }); } if (calleeMethod.Parameters.Count != argTypes.Count) { string message = string.Format( System.Globalization.CultureInfo.InvariantCulture, Properties.Resources.CodeGenerator_UnexpectedArgumentCount, calleeMethod.Name, calleeMethod.Parameters.Count, argTypes.Count); this.log.Write(new Message( expression.Start.Path, expression.Start.Line, expression.Start.Column, Severity.Error, message)); valueType = null; return false; } bool argsValid = true; for (int i = 0; i < calleeMethod.Parameters.Count; i++) { if (!this.ValidateCanCast(expression, calleeMethod.Parameters[i].Type, argTypes[i])) { argsValid = false; } } valueType = storageType; return argsValid; } ReferenceExpression refExpr = expression as ReferenceExpression; if (refExpr != null) { string location = null; TypeDefinition storageType = null; MethodInfo calleeMethod = null; if (!this.TryEmitReference(refExpr, context, scope, method, out location, out storageType, out calleeMethod)) { valueType = null; return false; } if (storageType.IsFloatingPoint) { if (storageType.Size == 8) { method.Statements.Add(new AsmStatement { Instruction = "fld qword ptr " + location }); } else if (storageType.Size == 4) { method.Statements.Add(new AsmStatement { Instruction = "fld dword ptr " + location }); } else { method.Statements.Add(new AsmStatement { Instruction = "fld tword ptr " + location }); } } else if (storageType.IsArray) { if (storageType.ArrayElementCount > 0) { method.Statements.Add(new AsmStatement { Instruction = "lea eax," + location }); valueType = context.GetArrayType(storageType.InnerType, 0); return true; } else { method.Statements.Add(new AsmStatement { Instruction = "mov eax," + location }); } } else if (storageType.Size <= 8 && !storageType.IsClass) { switch (storageType.Size) { case 8: method.Statements.Add(new AsmStatement { Instruction = "lea ecx, " + location }); method.Statements.Add(new AsmStatement { Instruction = "mov eax,[ecx]" }); method.Statements.Add(new AsmStatement { Instruction = "add ecx,4" }); method.Statements.Add(new AsmStatement { Instruction = "mov edx,[ecx]" }); break; case 4: method.Statements.Add(new AsmStatement { Instruction = "mov eax,dword ptr " + location }); break; case 2: method.Statements.Add(new AsmStatement { Instruction = "mov ax,word ptr " + location }); break; case 1: method.Statements.Add(new AsmStatement { Instruction = "mov al,byte ptr " + location }); break; } } else if (storageType.IsClass) { // construct a new copy on the stack. method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", location) }); method.Statements.Add(new AsmStatement { Instruction = string.Format("sub esp,{0}", storageType.Size) }); MethodInfo copyConstructor = storageType.GetCopyConstructor(context); if (copyConstructor != null) { method.Module.AddProto(copyConstructor); method.Statements.Add(new AsmStatement { Instruction = "lea ecx,[esp]" }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); method.Statements.Add(new AsmStatement { Instruction = "push ecx" }); method.Statements.Add(new AsmStatement { Instruction = "call " + copyConstructor.MangledName }); method.Statements.Add(new AsmStatement { Instruction = "add esp,8" }); } else { // raw copy. method.Statements.Add(new AsmStatement { Instruction = "mov edi,esp" }); method.Statements.Add(new AsmStatement { Instruction = "mov esi,eax" }); method.Statements.Add(new AsmStatement { Instruction = string.Format("mov ecx,{0}", storageType.Size) }); method.Statements.Add(new AsmStatement { Instruction = "cld" }); method.Statements.Add(new AsmStatement { Instruction = "rep movsb" }); } } valueType = storageType; return true; } SimpleExpression simpleExpr = expression as SimpleExpression; if (simpleExpr != null) { return this.TryEmitSimpleExpression(simpleExpr, context, scope, method, out valueType); } TermExpression termExpr = expression as TermExpression; if (termExpr != null) { return this.TryEmitTermExpression(termExpr, context, scope, method, out valueType); } RelationalExpression relExpr = expression as RelationalExpression; if (relExpr != null) { return this.TryEmitRelationExpresion(relExpr, context, scope, method, out valueType); } AddressExpression addrExpr = expression as AddressExpression; if (addrExpr != null) { return this.TryEmitAddressExpression(addrExpr, context, scope, method, out valueType); } NewExpression newExpr = expression as NewExpression; if (newExpr != null) { return this.TryEmitNewExpression(newExpr, context, scope, method, out valueType); } NotExpression notExpr = expression as NotExpression; if (notExpr != null) { return this.TryEmitNotExpression(notExpr, context, scope, method, out valueType); } NegativeExpression negExpr = expression as NegativeExpression; if (negExpr != null) { return this.TryEmitNegativeExpression(negExpr, context, scope, method, out valueType); } valueType = null; return false; }
private bool TryEmitRelationExpresion( RelationalExpression relExpr, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { context.TryFindTypeByName("boolean", out valueType); TypeDefinition rightSideType = null; if (!this.TryEmitExpression(relExpr.Right, context, scope, method, out rightSideType)) { return false; } this.PushResult(method, rightSideType); TypeDefinition leftSideType = null; if (!this.TryEmitExpression(relExpr.Left, context, scope, method, out leftSideType)) { return false; } if (rightSideType.IsFloatingPoint) { if (leftSideType.IsFloatingPoint) { switch (rightSideType.Size) { case 4: method.Statements.Add(new AsmStatement { Instruction = "fld dword ptr [esp]" }); break; case 8: method.Statements.Add(new AsmStatement { Instruction = "fld qword ptr [esp]" }); break; default: method.Statements.Add(new AsmStatement { Instruction = "fld tword ptr [esp]" }); break; } method.Statements.Add(new AsmStatement { Instruction = string.Format("add esp,{0}", rightSideType.Size) }); method.Statements.Add(new AsmStatement { Instruction = "fcompp" }); method.Statements.Add(new AsmStatement { Instruction = "fnstsw ax" }); method.Statements.Add(new AsmStatement { Instruction = "sahf" }); switch (relExpr.Operator) { case Keyword.Equals: { method.Statements.Add(new AsmStatement { Instruction = "sete al" }); } break; case Keyword.LessThan: { method.Statements.Add(new AsmStatement { Instruction = "seta al" }); } break; case Keyword.LessThanOrEquals: { method.Statements.Add(new AsmStatement { Instruction = "setae al" }); } break; case Keyword.GreaterThan: { method.Statements.Add(new AsmStatement { Instruction = "setb al" }); } break; case Keyword.GreaterThanOrEquals: { method.Statements.Add(new AsmStatement { Instruction = "setbe al" }); } break; case Keyword.NotEqual: { method.Statements.Add(new AsmStatement { Instruction = "setne al" }); } break; } } else { string message = string.Format( System.Globalization.CultureInfo.InvariantCulture, Properties.Resources.CodeGenerator_NoAutomaticConversion, leftSideType.FullName, rightSideType.FullName); this.log.Write(new Message( relExpr.Start.Path, relExpr.Start.Line, relExpr.Start.Column, Severity.Error, message)); return false; } } else if(leftSideType.IsFloatingPoint) { string message = string.Format( System.Globalization.CultureInfo.InvariantCulture, Properties.Resources.CodeGenerator_NoAutomaticConversion, leftSideType.FullName, rightSideType.FullName); this.log.Write(new Message( relExpr.Start.Path, relExpr.Start.Line, relExpr.Start.Column, Severity.Error, message)); return false; } else { if(leftSideType.Size <= 4 && rightSideType.Size <= 4) { method.Statements.Add(new AsmStatement { Instruction = "pop ecx"}); method.Statements.Add(new AsmStatement { Instruction = "cmp eax,ecx"}); switch (relExpr.Operator) { case Keyword.Equals: { method.Statements.Add(new AsmStatement { Instruction = "sete al" }); } break; case Keyword.LessThan: { method.Statements.Add(new AsmStatement { Instruction = "setl al" }); } break; case Keyword.LessThanOrEquals: { method.Statements.Add(new AsmStatement { Instruction = "setle al" }); } break; case Keyword.GreaterThan: { method.Statements.Add(new AsmStatement { Instruction = "setg al" }); } break; case Keyword.GreaterThanOrEquals: { method.Statements.Add(new AsmStatement { Instruction = "setge al" }); } break; case Keyword.NotEqual: { method.Statements.Add(new AsmStatement { Instruction = "setne al" }); } break; } } } return true; }
public MethodInfo(TypeDefinition type) { this.Type = type; }
public TypeDefinition GetArrayType(TypeDefinition elementType, int elementCount) { TypeDefinition result = null; string fullName = "#" + elementCount.ToString() + elementType.FullName; if (!this.types.TryGetValue(fullName, out result)) { result = new TypeDefinition { FullName = fullName, IsArray = true, Size = elementCount > 0 ? elementType.Size * elementCount : 4, ArrayElementCount = elementCount, InnerType = elementType }; this.types.Add(fullName, result); } return result; }