📄 emitcodegen.cs
字号:
else
m_ilGenerator.Emit(code, iSlot);
}
void Emit_Ldloc(System.Reflection.Emit.LocalBuilder l)
{
m_ilGenerator.Emit(OpCodes.Ldloc_S, l);
}
void Emit_LdlocA(System.Reflection.Emit.LocalBuilder l)
{
m_ilGenerator.Emit(OpCodes.Ldloca_S, l);
}
void Emit_Starg(int iSlot)
{
// @dogfood - handle bytes
m_ilGenerator.Emit(OpCodes.Starg_S, (int) iSlot);
}
void Emit_Stloc(System.Reflection.Emit.LocalBuilder l)
{
m_ilGenerator.Emit(OpCodes.Stloc_S, l);
}
// Emit the proper load-indirect opcode, depending on our type
void Emit_Ldi(System.Type t)
{
if (t== typeof(int) || t.IsEnum)
{
m_ilGenerator.Emit(OpCodes.Ldind_I4);
}
else if (t == typeof(char))
{
m_ilGenerator.Emit(OpCodes.Ldind_U2);
}
else if (t.IsValueType)
{
m_ilGenerator.Emit(OpCodes.Ldobj, t);
}
else
{
m_ilGenerator.Emit(OpCodes.Ldind_Ref);
}
}
// emit proper store-indirect opcode
void Emit_Sti(System.Type t)
{
if (t == typeof(int) || t.IsEnum)
{
m_ilGenerator.Emit(OpCodes.Stind_I4);
}
else if (t == typeof(char))
{
m_ilGenerator.Emit(OpCodes.Stind_I2);
}
else if (t.IsValueType)
{
m_ilGenerator.Emit(OpCodes.Stobj, t);
}
else
{
m_ilGenerator.Emit(OpCodes.Stind_Ref);
}
}
// Emit the proper Stelem flavor, depending on type
void Emit_Stelem(System.Type tElem)
{
if ((tElem == typeof(int)) || tElem.IsEnum)
{
m_ilGenerator.Emit(OpCodes.Stelem_I4);
}
else if (tElem == typeof(char))
{
m_ilGenerator.Emit(OpCodes.Stelem_I2);
}
else
{
Debug.Assert(!tElem.IsValueType, "Woah! Stelem for structs? Is that possible?");
m_ilGenerator.Emit(OpCodes.Stelem_Ref);
}
}
void Emit_Ldelem(System.Type tElem)
{
if ((tElem == typeof(int)) || tElem.IsEnum)
{
m_ilGenerator.Emit(OpCodes.Ldelem_I4);
}
else if (tElem == typeof(char))
{
m_ilGenerator.Emit(OpCodes.Ldelem_U2);
}
else if (tElem.IsValueType)
{
m_ilGenerator.Emit(OpCodes.Ldelema, tElem);
m_ilGenerator.Emit(OpCodes.Ldobj, tElem);
} else
{
Debug.Assert(!tElem.IsValueType);
m_ilGenerator.Emit(OpCodes.Ldelem_Ref);
}
}
/***************************************************************************\
*
* EmitCodeGen.GenerateBoxable
*
* If we're generating a value type and it will be assigned to an object,
* then we need to box it. This is used with RHS expressions.
\**************************************************************************/
public void
GenerateBoxable(
AST.Exp exp,
System.Type tTarget
)
{
Debug.Assert(tTarget != null);
System.Type tSource = exp.CLRType;
exp.GenerateAsRight(this);
// Check if we need to box.
// Null expressions don't have a clr type. But they're not value
// types so they don't have to be boxed.
if (tSource != null)
{
// Strip off references to look at base types
if (tSource.IsByRef)
tSource = tSource.GetElementType();
if (tTarget.IsByRef)
tTarget = tTarget.GetElementType();
if (tSource.IsValueType && !tTarget.IsValueType)
m_ilGenerator.Emit(OpCodes.Box, tSource);
}
else
{
// Make sure this really is a null and not just an unresolved type
// Note that ArgExp can be null, but can't be boxed.
Debug.Assert(AST.Exp.CanBeNullType(exp));
}
}
#endregion
#region Generate for Decls
/***************************************************************************\
*
* EmitCodeGen.Generate
*
* Generate() recursively generates the program defined by the given node.
*
\***************************************************************************/
public void
Generate(
AST.ProgramDecl nodeProgram)
{
// Generate all types.
Log.WriteLine(Log.LF.CodeGen, "***Generate bodies for all types");
AST.TypeDeclBase [] al = nodeProgram.Classes;
foreach (AST.TypeDeclBase t in al)
{
t.GenerateType(this);
}
Log.WriteLine(Log.LF.CodeGen, "***Finished generating bodies for types. About to call CreateType()");
// Now that the bodies have all been generating, the final thing we
// need to do is 'bless' all the types. Do this by calling CreateType()
// on everything.
// We have to separate the CreateType phase from the GenerateBody
// because CreateType may have to call itself recursively, and so
// we'll need all the bodies to be created.
foreach (AST.TypeDeclBase t in al)
{
TypeBuilder bld = (TypeBuilder) t.CLRType;
Debug.Assert(bld != null);
CreateType(bld);
}
}
/***************************************************************************\
*
* EmitCodeGen.Generate
*
* Generate() recursively generates the class defined by the given node.
*
\***************************************************************************/
public void
GenerateEnum(AST.EnumDecl node)
{
// Reflection-Emit requires that we 'bless' the enum via CreateType()
#if Bug_In_EnumBuilder
TypeBuilder bld = (TypeBuilder) node.Symbol.CLRType;
#else
EnumBuilder bld = (EnumBuilder) node.Symbol.CLRType;
#endif
}
// ...
// Account for another emit/loader bug. The type resolve event only give us
// the short name. So keep a stack to get the full context.
// When this bug is fixed, get rid of this variable.
System.Collections.Stack m_CreateTypeStack = new System.Collections.Stack();
//-----------------------------------------------------------------------------
// Finalize the type and return the baked instance. This should never
// return null. This can be called recursively.
// We only bake a type once.
//-----------------------------------------------------------------------------
System.Type CreateType(TypeBuilder bld)
{
string stName = bld.FullName;
// This should never throw an exception, but we catch it for debugging purposes.
System.Type typeNewClass = null;
// Since this is recursive, we may have already created the type. So check
#if true
Type tCheck = ModuleBuilder_GetType(m_bldModule, stName);
if (!(tCheck is TypeBuilder))
{
Log.WriteLine(Log.LF.CodeGen, "'{0}' already created..", stName);
return typeNewClass;
}
#endif
try
{
Log.WriteLine(Log.LF.CodeGen, "About to call CreateType() for '{0}'", stName);
// This stack is a bad hack to deal with a stupid Reflection-emit bug.
m_CreateTypeStack.Push(bld.FullName);
// This may fire a TypeResolve event which may turn around and call CreateType() again
typeNewClass = bld.CreateType();
string s = (string) m_CreateTypeStack.Pop();
Debug.Assert(s == bld.FullName);
Log.WriteLine(Log.LF.CodeGen, "Type '{0}' fully created", stName);
}
catch(System.Exception e)
{
// Should never happen.
// A very common cause for this failure is an bug in blue where
// we fail to put an implied 'virtual' modifier on a method.Then the method doesn't
// match in interface mapping and it looks like it wasn't implemented.
Log.WriteLine(Log.LF.CodeGen, "CreateType() failed on '{0}' with exception:{1}", stName, e);
throw;
}
Debug.Assert(typeNewClass != null);
Debug.Assert(!(typeNewClass is TypeBuilder));
return typeNewClass;
}
/***************************************************************************\
*
* EmitCodeGen.Generate
*
* Generate() recursively generates the class defined by the given node.
*
\***************************************************************************/
public void
GenerateClass(
AST.ClassDecl nodeClass)
{
//
// Determine information about the base class:
// - If the base-class is not already generated, need to generate it now.
// - Get the System.Type of the base class.
//
string stName = nodeClass.Symbol.FullName;
Log.WriteLine(Log.LF.CodeGen, "Begin generating class '{0}' [", stName);
//
// Begin the new class definition.
//
// Set the current class builder
TypeBuilder bldClass = nodeClass.Symbol.CLRType as TypeBuilder;
Debug.Assert(bldClass != null);
// Set the debugger document
SetCurrentDebugDocument(nodeClass.Location);
//
// Generate the member methods.
//
if (!nodeClass.IsInterface)
{
AST.MethodDecl [] al = nodeClass.Methods;
foreach (AST.MethodDecl nodeMethod in al)
{
if (!nodeMethod.Mods.IsAbstract)
{
Generate(nodeMethod);
}
}
foreach (AST.PropertyDecl nodeProp in nodeClass.Properties)
{
Generate(nodeProp);
}
}
Log.WriteLine(Log.LF.CodeGen, "] end body for '{0}'", stName);
//
// End the class definition.
//
/*
// This may catch a lot of problems (because it invokes the loader).
Type typeNewClass = null;
try
{
Log.WriteLine(Log.LF.CodeGen, "] About to call CreateType() on '{0}'", stName);
typeNewClass = bldClass.CreateType();
Log.WriteLine(Log.LF.CodeGen, "Type '{0}' fully created", stName);
}
catch(System.Exception e)
{
Log.WriteLine(Log.LF.CodeGen, "CreateType() failed on '{0}' with exception:{1}", stName, e);
throw;
}
Debug.Assert(typeNewClass != null, "Must have successfully created new class");
*/
//m_alClasses.Add(typeNewClass);
m_alClasses.Add(bldClass);
//m_bldClass = null;
}
/***************************************************************************\
*
* EmitCodeGen.Generate
*
* Generate() recursively generates the method defined by the given node.
*
\***************************************************************************/
public void
Generate(
AST.PropertyDecl nodeProp
)
{
nodeProp.Generate(this);
}
/***************************************************************************\
*
* EmitCodeGen.Generate
*
* Generate() recursively generates the method defined by the given node.
*
\***************************************************************************/
public void
Generate(
AST.MethodDecl nodeMethod)
{
// Delegate impls have no body....
if (AST.DelegateDecl.IsDelegate(nodeMethod.Symbol.SymbolClass.CLRType))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -