This commit is contained in:
jfrijters 2004-03-29 10:11:33 +00:00
Родитель 91dba9e184
Коммит bc9d509e5d
2 изменённых файлов: 165 добавлений и 51 удалений

Просмотреть файл

@ -2060,6 +2060,8 @@ class DynamicTypeWrapper : TypeWrapper
this.map = map; this.map = map;
} }
// this method doesn't work on Mono yet, so we use a Type based approach instead
#if USE_TYPEHANDLE_EXCEPTION_MAPPING
internal override void Emit(ILGenerator ilgen) internal override void Emit(ILGenerator ilgen)
{ {
ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Ldarg_0);
@ -2097,6 +2099,40 @@ class DynamicTypeWrapper : TypeWrapper
ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ret); ilgen.Emit(OpCodes.Ret);
} }
#else // USE_TYPEHANDLE_EXCEPTION_MAPPING
internal override void Emit(ILGenerator ilgen)
{
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Callvirt, typeof(Object).GetMethod("GetType"));
MethodInfo GetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");
for(int i = 0; i < map.Length; i++)
{
ilgen.Emit(OpCodes.Dup);
ilgen.Emit(OpCodes.Ldtoken, Type.GetType(map[i].src));
ilgen.Emit(OpCodes.Call, GetTypeFromHandle);
ilgen.Emit(OpCodes.Ceq);
Label label = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brfalse_S, label);
ilgen.Emit(OpCodes.Pop);
if(map[i].code != null)
{
ilgen.Emit(OpCodes.Ldarg_0);
map[i].code.Emit(ilgen);
ilgen.Emit(OpCodes.Ret);
}
else
{
TypeWrapper tw = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(map[i].dst);
tw.GetMethodWrapper(MethodDescriptor.FromNameSig(tw.GetClassLoader(), "<init>", "()V"), false).EmitNewobj.Emit(ilgen);
ilgen.Emit(OpCodes.Ret);
}
ilgen.MarkLabel(label);
}
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ret);
}
#endif // USE_TYPEHANDLE_EXCEPTION_MAPPING
} }
internal static void LoadNativeMethods(MapXml.Root map) internal static void LoadNativeMethods(MapXml.Root map)

Просмотреть файл

@ -538,6 +538,7 @@ class Compiler
{ {
// NOTE Stub gets used for both the push stub (inside the exception block) as well as the pop stub (outside the block) // NOTE Stub gets used for both the push stub (inside the exception block) as well as the pop stub (outside the block)
internal Label Stub; internal Label Stub;
internal Label TargetLabel;
internal bool ContentOnStack; internal bool ContentOnStack;
internal readonly int TargetPC; internal readonly int TargetPC;
internal DupHelper dh; internal DupHelper dh;
@ -689,6 +690,7 @@ class Compiler
{ {
if(args[i].IsUnloadable) if(args[i].IsUnloadable)
{ {
Profiler.Count("EmitDynamicCast");
ilGenerator.Emit(OpCodes.Ldarg, (ushort)(i + (m.IsStatic ? 0 : 1))); ilGenerator.Emit(OpCodes.Ldarg, (ushort)(i + (m.IsStatic ? 0 : 1)));
ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD); ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD);
ilGenerator.Emit(OpCodes.Ldstr, args[i].Name); ilGenerator.Emit(OpCodes.Ldstr, args[i].Name);
@ -724,20 +726,24 @@ class Compiler
ilGenerator.Emit(OpCodes.Stloc, monitor); ilGenerator.Emit(OpCodes.Stloc, monitor);
ilGenerator.Emit(OpCodes.Call, monitorEnterMethod); ilGenerator.Emit(OpCodes.Call, monitorEnterMethod);
ilGenerator.BeginExceptionBlock(); ilGenerator.BeginExceptionBlock();
c.Compile(new Block(c, 0, int.MaxValue, -1, exits)); Block b = new Block(c, 0, int.MaxValue, -1, exits, true);
c.Compile(b);
b.Leave();
ilGenerator.BeginFinallyBlock(); ilGenerator.BeginFinallyBlock();
ilGenerator.Emit(OpCodes.Ldloc, monitor); ilGenerator.Emit(OpCodes.Ldloc, monitor);
ilGenerator.Emit(OpCodes.Call, monitorExitMethod); ilGenerator.Emit(OpCodes.Call, monitorExitMethod);
ilGenerator.EndExceptionBlock(); ilGenerator.EndExceptionBlock();
foreach(ReturnCookie rc in exits) b.LeaveStubs(new Block(c, 0, int.MaxValue, -1, null, false));
{
rc.EmitRet(ilGenerator);
}
} }
else else
{ {
c.Compile(new Block(c, 0, int.MaxValue, -1, null)); Block b = new Block(c, 0, int.MaxValue, -1, null, false);
c.Compile(b);
b.Leave();
} }
// HACK because of the bogus Leave instruction that Reflection.Emit generates, this location
// sometimes appears reachable (it isn't), so we emit a bogus branch to keep the verifier happy.
ilGenerator.Emit(OpCodes.Br_S, (sbyte)-2);
Profiler.Leave("Compile"); Profiler.Leave("Compile");
} }
@ -747,11 +753,12 @@ class Compiler
private ILGenerator ilgen; private ILGenerator ilgen;
private int begin; private int begin;
private int end; private int end;
private ArrayList exits;
private int exceptionIndex; private int exceptionIndex;
private ArrayList exits;
private bool nested;
private object[] labels; private object[] labels;
internal Block(Compiler compiler, int begin, int end, int exceptionIndex, ArrayList exits) internal Block(Compiler compiler, int begin, int end, int exceptionIndex, ArrayList exits, bool nested)
{ {
this.compiler = compiler; this.compiler = compiler;
this.ilgen = compiler.ilGenerator; this.ilgen = compiler.ilGenerator;
@ -759,6 +766,7 @@ class Compiler
this.end = end; this.end = end;
this.exceptionIndex = exceptionIndex; this.exceptionIndex = exceptionIndex;
this.exits = exits; this.exits = exits;
this.nested = nested;
labels = new object[compiler.m.Instructions.Length]; labels = new object[compiler.m.Instructions.Length];
} }
@ -778,6 +786,17 @@ class Compiler
} }
} }
internal void SetBackwardBranchLabel(int instructionIndex, BranchCookie bc)
{
// NOTE we're overwriting the label that is already there
labels[instructionIndex] = bc.Stub;
if(exits == null)
{
exits = new ArrayList();
}
exits.Add(bc);
}
internal Label GetLabel(int targetPC) internal Label GetLabel(int targetPC)
{ {
int targetIndex = compiler.FindPcIndex(targetPC); int targetIndex = compiler.FindPcIndex(targetPC);
@ -814,6 +833,11 @@ class Compiler
} }
} }
internal bool HasLabel(int instructionIndex)
{
return labels[instructionIndex] != null;
}
internal void MarkLabel(int instructionIndex) internal void MarkLabel(int instructionIndex)
{ {
object label = labels[instructionIndex]; object label = labels[instructionIndex];
@ -836,64 +860,77 @@ class Compiler
internal void Leave() internal void Leave()
{ {
for(int i = 0; i < exits.Count; i++) if(exits != null)
{ {
object exit = exits[i]; for(int i = 0; i < exits.Count; i++)
BranchCookie bc = exit as BranchCookie;
if(bc != null && bc.ContentOnStack)
{ {
bc.ContentOnStack = false; object exit = exits[i];
ilgen.MarkLabel(bc.Stub); BranchCookie bc = exit as BranchCookie;
int stack = bc.dh.Count; if(bc != null && bc.ContentOnStack)
for(int n = 0; n < stack; n++)
{ {
bc.dh.Store(n); bc.ContentOnStack = false;
ilgen.MarkLabel(bc.Stub);
int stack = bc.dh.Count;
for(int n = 0; n < stack; n++)
{
bc.dh.Store(n);
}
if(bc.TargetPC == -1)
{
ilgen.Emit(OpCodes.Br, bc.TargetLabel);
}
else
{
bc.Stub = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Leave, bc.Stub);
}
} }
bc.Stub = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Leave, bc.Stub);
} }
} }
} }
internal void LeaveStubs(Block newBlock) internal void LeaveStubs(Block newBlock)
{ {
for(int i = 0; i < exits.Count; i++) if(exits != null)
{ {
object exit = exits[i]; for(int i = 0; i < exits.Count; i++)
ReturnCookie rc = exit as ReturnCookie;
if(rc != null)
{ {
if(newBlock.exits == null) object exit = exits[i];
ReturnCookie rc = exit as ReturnCookie;
if(rc != null)
{ {
rc.EmitRet(ilgen); if(newBlock.exits == null)
}
else
{
newBlock.exits.Add(rc);
}
}
else
{
BranchCookie bc = exit as BranchCookie;
if(bc != null)
{
Debug.Assert(!bc.ContentOnStack);
// if the target is within the new block, we handle it, otherwise we
// defer the cookie to our caller
if(newBlock.IsInRange(bc.TargetPC))
{ {
bc.ContentOnStack = true; rc.EmitRet(ilgen);
ilgen.MarkLabel(bc.Stub);
int stack = bc.dh.Count;
for(int n = stack - 1; n >= 0; n--)
{
bc.dh.Load(n);
}
ilgen.Emit(OpCodes.Br, newBlock.GetLabel(bc.TargetPC));
} }
else else
{ {
newBlock.exits.Add(bc); newBlock.exits.Add(rc);
}
}
else
{
BranchCookie bc = exit as BranchCookie;
if(bc != null && bc.TargetPC != -1)
{
Debug.Assert(!bc.ContentOnStack);
// if the target is within the new block, we handle it, otherwise we
// defer the cookie to our caller
if(newBlock.IsInRange(bc.TargetPC))
{
bc.ContentOnStack = true;
ilgen.MarkLabel(bc.Stub);
int stack = bc.dh.Count;
for(int n = stack - 1; n >= 0; n--)
{
bc.dh.Load(n);
}
ilgen.Emit(OpCodes.Br, newBlock.GetLabel(bc.TargetPC));
}
else
{
newBlock.exits.Add(bc);
}
} }
} }
} }
@ -909,7 +946,7 @@ class Compiler
{ {
get get
{ {
return exits != null; return nested;
} }
} }
} }
@ -956,6 +993,7 @@ class Compiler
int exceptionIndex = 0; int exceptionIndex = 0;
Instruction[] code = m.Instructions; Instruction[] code = m.Instructions;
Stack blockStack = new Stack(); Stack blockStack = new Stack();
bool instructionIsForwardReachable = true;
for(int i = 0; i < code.Length; i++) for(int i = 0; i < code.Length; i++)
{ {
Instruction instr = code[i]; Instruction instr = code[i];
@ -1045,6 +1083,7 @@ class Compiler
{ {
if(exceptionTypeWrapper.IsUnloadable) if(exceptionTypeWrapper.IsUnloadable)
{ {
Profiler.Count("EmitDynamicGetTypeAsExceptionType");
ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD); ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD);
ilGenerator.Emit(OpCodes.Ldstr, exceptionTypeWrapper.Name); ilGenerator.Emit(OpCodes.Ldstr, exceptionTypeWrapper.Name);
ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicGetTypeAsExceptionType")); ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicGetTypeAsExceptionType"));
@ -1079,10 +1118,36 @@ class Compiler
prevBlock.LeaveStubs(block); prevBlock.LeaveStubs(block);
} }
// if there was a forward branch to this instruction, it is forward reachable
instructionIsForwardReachable |= block.HasLabel(i);
// TODO for now, every instruction has an associated label, I'm not sure it's worthwhile, // TODO for now, every instruction has an associated label, I'm not sure it's worthwhile,
// but it could be optimized // but it could be optimized
block.MarkLabel(i); block.MarkLabel(i);
// if the instruction is only backward reachable, ECMA says it must have an empty stack,
// so we move the stack to locals
if(!instructionIsForwardReachable && ma.IsReachable(i))
{
int stackHeight = ma.GetStackHeight(i);
if(stackHeight != 0)
{
BranchCookie bc = new BranchCookie(ilGenerator, stackHeight, -1);
bc.ContentOnStack = true;
bc.TargetLabel = ilGenerator.DefineLabel();
ilGenerator.MarkLabel(bc.TargetLabel);
for(int j = 0; j < stackHeight; j++)
{
bc.dh.SetType(j, ma.GetRawStackTypeWrapper(i, j));
}
for(int j = stackHeight - 1; j >= 0; j--)
{
bc.dh.Load(j);
}
block.SetBackwardBranchLabel(i, bc);
}
}
// if we're entering an exception block, we need to setup the exception block and // if we're entering an exception block, we need to setup the exception block and
// transfer the stack into it // transfer the stack into it
for(; exceptionIndex < exceptions.Length && exceptions[exceptionIndex].start_pc == instr.PC; exceptionIndex++) for(; exceptionIndex < exceptions.Length && exceptions[exceptionIndex].start_pc == instr.PC; exceptionIndex++)
@ -1107,7 +1172,7 @@ class Compiler
ilGenerator.BeginExceptionBlock(); ilGenerator.BeginExceptionBlock();
} }
blockStack.Push(block); blockStack.Push(block);
block = new Block(this, exceptions[exceptionIndex].start_pc, exceptions[exceptionIndex].end_pc, exceptionIndex, new ArrayList()); block = new Block(this, exceptions[exceptionIndex].start_pc, exceptions[exceptionIndex].end_pc, exceptionIndex, new ArrayList(), true);
block.MarkLabel(i); block.MarkLabel(i);
} }
@ -1198,6 +1263,7 @@ class Compiler
TypeWrapper tw = cf.GetConstantPoolClassType(constant, classLoader); TypeWrapper tw = cf.GetConstantPoolClassType(constant, classLoader);
if(tw.IsUnloadable) if(tw.IsUnloadable)
{ {
Profiler.Count("EmitDynamicClassLiteral");
ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD); ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD);
ilGenerator.Emit(OpCodes.Ldstr, tw.Name); ilGenerator.Emit(OpCodes.Ldstr, tw.Name);
ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicClassLiteral")); ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicClassLiteral"));
@ -1590,6 +1656,7 @@ class Compiler
TypeWrapper wrapper = instr.MethodCode.Method.ClassFile.GetConstantPoolClassType(instr.Arg1, classLoader); TypeWrapper wrapper = instr.MethodCode.Method.ClassFile.GetConstantPoolClassType(instr.Arg1, classLoader);
if(wrapper.IsUnloadable) if(wrapper.IsUnloadable)
{ {
Profiler.Count("EmitDynamicNewCheckOnly");
// this is here to make sure we throw the exception in the right location (before // this is here to make sure we throw the exception in the right location (before
// evaluating the constructor arguments) // evaluating the constructor arguments)
ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD); ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD);
@ -1625,6 +1692,7 @@ class Compiler
TypeWrapper wrapper = instr.MethodCode.Method.ClassFile.GetConstantPoolClassType(instr.Arg1, classLoader); TypeWrapper wrapper = instr.MethodCode.Method.ClassFile.GetConstantPoolClassType(instr.Arg1, classLoader);
if(wrapper.IsUnloadable) if(wrapper.IsUnloadable)
{ {
Profiler.Count("EmitDynamicMultianewarray");
ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD); ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD);
ilGenerator.Emit(OpCodes.Ldstr, wrapper.Name); ilGenerator.Emit(OpCodes.Ldstr, wrapper.Name);
ilGenerator.Emit(OpCodes.Ldloc, localArray); ilGenerator.Emit(OpCodes.Ldloc, localArray);
@ -1649,6 +1717,7 @@ class Compiler
TypeWrapper wrapper = instr.MethodCode.Method.ClassFile.GetConstantPoolClassType(instr.Arg1, classLoader); TypeWrapper wrapper = instr.MethodCode.Method.ClassFile.GetConstantPoolClassType(instr.Arg1, classLoader);
if(wrapper.IsUnloadable) if(wrapper.IsUnloadable)
{ {
Profiler.Count("EmitDynamicNewarray");
ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD); ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD);
ilGenerator.Emit(OpCodes.Ldstr, wrapper.Name); ilGenerator.Emit(OpCodes.Ldstr, wrapper.Name);
ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicNewarray")); ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicNewarray"));
@ -1730,6 +1799,7 @@ class Compiler
TypeWrapper tw = ma.GetRawStackTypeWrapper(i, 1); TypeWrapper tw = ma.GetRawStackTypeWrapper(i, 1);
if(tw.IsUnloadable) if(tw.IsUnloadable)
{ {
Profiler.Count("EmitDynamicAaload");
ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD); ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD);
ilGenerator.Emit(OpCodes.Ldstr, tw.Name); ilGenerator.Emit(OpCodes.Ldstr, tw.Name);
ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicAaload")); ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicAaload"));
@ -1799,6 +1869,7 @@ class Compiler
TypeWrapper tw = ma.GetRawStackTypeWrapper(i, 2); TypeWrapper tw = ma.GetRawStackTypeWrapper(i, 2);
if(tw.IsUnloadable) if(tw.IsUnloadable)
{ {
Profiler.Count("EmitDynamicAastore");
ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD); ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD);
ilGenerator.Emit(OpCodes.Ldstr, tw.Name); ilGenerator.Emit(OpCodes.Ldstr, tw.Name);
ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicAastore")); ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicAastore"));
@ -2458,8 +2529,10 @@ class Compiler
case NormalizedByteCode.__areturn: case NormalizedByteCode.__areturn:
case NormalizedByteCode.__return: case NormalizedByteCode.__return:
case NormalizedByteCode.__athrow: case NormalizedByteCode.__athrow:
instructionIsForwardReachable = false;
break; break;
default: default:
instructionIsForwardReachable = true;
Debug.Assert(ma.IsReachable(i + 1)); Debug.Assert(ma.IsReachable(i + 1));
// don't fall through end of try block // don't fall through end of try block
if(m.Instructions[i + 1].PC == block.End) if(m.Instructions[i + 1].PC == block.End)
@ -2658,17 +2731,21 @@ class Compiler
switch(bytecode) switch(bytecode)
{ {
case NormalizedByteCode.__getfield: case NormalizedByteCode.__getfield:
Profiler.Count("EmitDynamicGetfield");
ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicGetfield")); ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicGetfield"));
EmitReturnTypeConversion(ilGenerator, fieldTypeWrapper); EmitReturnTypeConversion(ilGenerator, fieldTypeWrapper);
break; break;
case NormalizedByteCode.__putfield: case NormalizedByteCode.__putfield:
Profiler.Count("EmitDynamicPutfield");
ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicPutfield")); ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicPutfield"));
break; break;
case NormalizedByteCode.__getstatic: case NormalizedByteCode.__getstatic:
Profiler.Count("EmitDynamicGetstatic");
ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicGetstatic")); ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicGetstatic"));
EmitReturnTypeConversion(ilGenerator, fieldTypeWrapper); EmitReturnTypeConversion(ilGenerator, fieldTypeWrapper);
break; break;
case NormalizedByteCode.__putstatic: case NormalizedByteCode.__putstatic:
Profiler.Count("EmitDynamicPutstatic");
ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicPutstatic")); ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicPutstatic"));
break; break;
} }
@ -2781,6 +2858,7 @@ class Compiler
internal override void Emit(ILGenerator ilGenerator) internal override void Emit(ILGenerator ilGenerator)
{ {
Profiler.Count("EmitDynamicInvokeEmitter");
TypeWrapper[] args = cpi.GetArgTypes(classLoader); TypeWrapper[] args = cpi.GetArgTypes(classLoader);
LocalBuilder argarray = ilGenerator.DeclareLocal(typeof(object[])); LocalBuilder argarray = ilGenerator.DeclareLocal(typeof(object[]));
LocalBuilder val = ilGenerator.DeclareLocal(typeof(object)); LocalBuilder val = ilGenerator.DeclareLocal(typeof(object));