📄 emitcodegen.cs
字号:
/***************************************************************************\
*
* File: EmitCodeGen.cs
*
* Description:
* EmitCodeGen.cs defines the "System.Reflection.Emit" CodeGen for the
* compiler.
*
*
* History:
* 8/14/2001: JStall: Created
*
* Copyright (C) 2001. All rights reserved.
*
\***************************************************************************/
//-----------------------------------------------------------------------------
// @todo - Split EmitCodeGen into 2 parts.
//-----------------------------------------------------------------------------
// ...
// There is a bug in the enum builder (10/12/2001) that won't let us
// set the enum fields to the proper type.
// We can workaround by directly using a typebuilder. When the bug is fixed,
// we should switch back over to EnumBuilders.
// This only affects CodeGen.
#define Bug_In_EnumBuilder
using System;
using System.Collections;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
using System.Diagnostics.SymbolStore;
using Blue.Public;
using Utilities = Blue.Utilities;
using ErrorLog = Blue.Utilities.ErrorLog;
using Log = Blue.Log;
namespace Blue.CodeGen
{
/***************************************************************************\
*****************************************************************************
*
* class EmitCodeGen
*
* EmitCodeGen implements the CodeGen interface for using
* System.Reflection.Emit.
*
*****************************************************************************
\***************************************************************************/
public class EmitCodeGen :
ICLRtypeProvider,
ICodeGenDriver
{
#region Enums
//
// Enums
//
/*
[FlagsAttribute()]
internal enum ClassAttributes
{
Public = 0x00000001,
}
*/
private enum TargetType
{
Console,
Windows,
Dll
}
#endregion Enums
#region Construction
/***************************************************************************\
*
* EmitCodeGen.EmitCodeGen
*
* EmitCodeGen() initializes a new CodeGen object.
*
\***************************************************************************/
internal
EmitCodeGen(
Blue.Public.IOptions opt) // Options
{
// Set default target type. An option handler may change it on us.
m_TargetType = TargetType.Console;
//
// Register OptionHandlers.
//
opt.AddHandler("target", "t", new OptionHandler(this.Option_Target),
"Target module format (windows, console, library)",
"Select what type of executable to produce\n"+
"/target:library - produce a dll\n"+
"/target:windows - produce a windows executable.\n"+
"/target:console - (default) produce a console executable\n");
#if false
Option_DebugInfo(""); // force debugging info in all cases
#endif
opt.AddHandler("debug", null, new OptionHandler(this.Option_DebugInfo),
"Generate .PDB symbols file for debugging",
"Generate a .pdb file for debugging purposes. Default is off.\n"+
"ex:\n"+
"/debug");
opt.AddHandler("main", "m", new OptionHandler(this.Option_SetMain),
"Specify class containing Main method",
"Explicitly specify which class has the Main method.\n"+
"ex:\n"+
"/main:MyClass");
opt.AddHandler("out", null, new OptionHandler(this.Option_Out),
"Specify the output name to generate",
"ex:\n"+
"/out:Dogfood.exe"
);
}
#endregion Construction
#region Print Errors
internal enum ErrorCodes
{
cDuplicateMain,
cNoMain,
cIOException,
cEntryClassNotFound,
}
private class CodeGenErrorException : ErrorException
{
// Codegen errors aren't associated with a particular file range, so we omit location
internal CodeGenErrorException(ErrorCodes c, string s) :
base (c, null, s)
{
// All Codegen errors will come through this body.
}
}
private void PrintError(CodeGenErrorException e)
{
Blue.Driver.StdErrorLog.PrintError(e);
}
void PrintError_DuplicateMain()
{
PrintError(
new CodeGenErrorException(ErrorCodes.cDuplicateMain, "Duplicate Main entry points. Use /m switch to specify which class to use.")
);
}
void PrintError_NoMain()
{
PrintError(
new CodeGenErrorException(ErrorCodes.cNoMain, "No Main function found")
);
}
void PrintError_IOException(string stHint)
{
PrintError(
new CodeGenErrorException(ErrorCodes.cIOException, stHint)
);
}
void PrintError_EntryClassNotFound(string stClass)
{
PrintError(
new CodeGenErrorException(
ErrorCodes.cEntryClassNotFound,
"The class '" + stClass+"' specified by the /m switch does not exist."
)
);
}
#endregion
#region Implementation for SymbolEngine.ICLRtypeProvider
// ...
// There's a bug in ModuleBuilder.GetType(), so we have to use our own
// version for now.
System.Type ModuleBuilder_GetType(ModuleBuilder m, string stType)
{
#if false
// This should work, but is broken for nested types.
return m.GetType(stType);
#else
// Here's our hack to use in the meantime
// Note, we have to deal with appended characters like [], and &
// This is a hack that will work for now. When reflection-emit fixes the
// bug, we can get rid of this.
Type [] al = m.GetTypes();
foreach(Type t in al)
{
if (t.FullName == stType)
return t;
}
return null;
#endif
}
// Must let the Type provider know what assemblies are imported so that
// we can search them for types.
void SetImportedAssemblies(Assembly [] asmImports)
{
Debug.Assert(asmImports != null);
m_asmImports = asmImports;
m_MscorLib = Assembly.Load("MsCorLib.dll");
}
Assembly m_MscorLib;
Assembly [] m_asmImports;
// Find a compound type (like T&, T[], T[][]&, T[,] ..)
// May be in either the module we're building or an imported assembly.
protected System.Type FindType(string stFullName)
{
System.Type tRef = null;
System.Type tNatural = m_MscorLib.GetType(stFullName);
// Look in the module we're building.
//tRef = ModuleBuilder_GetType(m_bldModule, stFullName);
tRef = m_bldModule.GetType(stFullName);
Debug.Assert((tNatural == null) || (tRef == null), "type can only be baked or unbaked, not both");
if (tNatural != null)
return tNatural;
if (tRef != null)
return tRef;
// Look in an imported modules
Assembly[] alist = m_asmImports;
foreach(Assembly a in alist)
{
Type t = a.GetType(stFullName);
if (t != null)
return t;
}
// Not found, there's an error:
// - we have an illegal compound type?
// - the elem type of the compound type doesn't exist?
// Or perhaps we require Resolution to catch this, if so the assert is ok.
Debug.Assert(tRef != null); // @legit
return null;
}
/***************************************************************************\
*
* EmitCodeGen.GetReferenceType
* - Returns a CLR type that is a reference to the type we pas in.
\***************************************************************************/
public virtual System.Type CreateCLRReferenceType(System.Type tElem)
{
Debug.Assert(!tElem.IsByRef, "Can't create a reference to a reference");
string st = tElem.FullName + "&";
System.Type tRef = this.FindType(st);
Debug.Assert(tRef != null);
return tRef;
}
/***************************************************************************\
*
* EmitCodeGen.CreateCLRArrayType
*
\***************************************************************************/
public virtual System.Type
CreateCLRArrayType(
SymbolEngine.ArrayTypeEntry symBlueType
)
{
// Get name of an array, like T[], T[,,][,][]
string st = symBlueType.ToString();
System.Type t = this.FindType(st);
// Semantic checking should have caught this.
Debug.Assert(t != null);
return t;
}
/***************************************************************************\
*
* EmitCodeGen.SetCLRClassType
*
\***************************************************************************/
public virtual System.Reflection.FieldInfo
CreateCLRField(
SymbolEngine.FieldExpEntry symBlueField
)
{
FieldAttributes attr = (FieldAttributes) 0;
AST.Modifiers mods = symBlueField.Node.Mods;
if (mods.IsPublic)
attr |= FieldAttributes.Public;
else if (mods.IsProtected)
attr |= FieldAttributes.Family;
else if (mods.IsPrivate)
attr |= FieldAttributes.Private;
else if (mods.IsInternal)
attr |= FieldAttributes.Assembly;
if (mods.IsReadOnly)
attr |= FieldAttributes.InitOnly;
if (mods.IsStatic)
attr |= FieldAttributes.Static;
// Get class that we're defined in
TypeBuilder bldClass = symBlueField.SymbolClass.CLRType as TypeBuilder;
Debug.Assert(bldClass != null);
// Create the field
FieldInfo f = bldClass.DefineField(symBlueField.Name, symBlueField.FieldType.CLRType, attr);
Debug.Assert(f != null);
return f;
}
//
public virtual System.Reflection.FieldInfo
CreateCLRLiteralField(
SymbolEngine.LiteralFieldExpEntry sym)
{
Type t = sym.SymbolClass.CLRType;
#if Bug_In_EnumBuilder
TypeBuilder bld = t as TypeBuilder;
Debug.Assert(bld != null);
FieldAttributes mods = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
FieldBuilder f = bld.DefineField(sym.Name, bld, mods);
f.SetConstant(sym.Data);
#else
if (t is EnumBuilder)
{
EnumBuilder bld = t as EnumBuilder;
f = bld.DefineLiteral(sym.Name, sym.Data);
}
else if (t is TypeBuilder)
{
Debug.Assert(false, "Literals not supported on non-enum Types");
}
#endif
// The new field should have the following properties:
Debug.Assert(f.IsStatic);
Debug.Assert(f.IsPublic);
Debug.Assert(f.IsLiteral);
Debug.Assert(f.FieldType == bld); // this is where the EnumBuilder breaks
return f;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -