internal static bool RedefineConstructor(PERWAPI.MethodDef ctor, PERWAPI.Class perwapiClass) { PERWAPI.CILInstruction[] ctorInstructions = ctor.GetCodeBuffer().GetInstructions(); // try and find a constructor in the base class PERWAPI.Method superClassConstructor = null; for (int i = 0; i < ctorInstructions.Length; i++) { if (ctorInstructions[i] is PERWAPI.MethInstr) { PERWAPI.MethInstr inst = (PERWAPI.MethInstr)(ctorInstructions[i]); PERWAPI.Method calledCtor = inst.GetMethod(); if (calledCtor.Name() == ".ctor") { PERWAPI.Type[] calledCtorParams = calledCtor.GetParTypes(); PERWAPI.Method[] superClassConstructors = perwapiClass.GetMethodDescs(".ctor"); superClassConstructor = perwapiClass.GetMethodDesc(".ctor", calledCtorParams); int pos = i; if (superClassConstructor == null) { if (calledCtorParams.Length == 1) { string paramTypeName = calledCtorParams[0].TypeName(); foreach (PERWAPI.Method superCtor in superClassConstructors) { PERWAPI.Type[] superCtorParams = superCtor.GetParTypes(); if (superCtorParams.Length == 1) { string superParamTypeName = superCtorParams[0].TypeName(); if (paramTypeName == "Ruby.Class" && superParamTypeName == paramTypeName) superClassConstructor = superCtor; } } } if (superClassConstructor == null) { // fall back on zero-arg constructor superClassConstructor = perwapiClass.GetMethodDesc(".ctor", new Type[0]); if (superClassConstructor == null) return false; if (calledCtorParams.Length > 0) { for (int j = 0; j < calledCtorParams.Length; j++) { ctor.GetCodeBuffer().RemoveInstruction(pos - 1); pos--; } } } } ctor.GetCodeBuffer().ReplaceInstruction(pos); ctor.GetCodeBuffer().MethInst(MethodOp.call, superClassConstructor); ctor.GetCodeBuffer().EndInsert(); return true; } } } return false; }
internal CodeGenContext CreateModuleMethod(string name, PERWAPI.Type return_type, params Param[] parameters) { CodeGenContext newContext = new CodeGenContext(this); newContext.Method = Assembly.AddMethod(MethAttr.PublicStatic, ImplAttr.IL, name, return_type, parameters); newContext.CLRLocals = new List<Local>(); newContext.Method.CreateCodeBuffer(); newContext.buffer.OpenScope(); return newContext; }
////////////////////////////////////////////////////////////////////////// // Code Utils ////////////////////////////////////////////////////////////////////////// /// <summary> /// Push the specified number of arguments onto the stack. /// </summary> private void pushArgs(PERWAPI.CILInstructions code, bool self, int count) { if (self) code.Inst(PERWAPI.Op.ldarg_0); for (int i=0; i<count; i++) { FTypeRef var = emit.pod.typeRef(method.m_vars[i].type); FCodeEmit.loadVar(code, var.stackType, self ? i+1 : i); } }
internal object ExecuteInit(PERWAPI.PEFile Assembly, Ruby.Class klass, object recv, Frame caller, Frame frame) { System.Reflection.Assembly loadedAssembly = CodeGenContext.Load(Assembly); System.Type EvalType = loadedAssembly.GetType("_Internal.Eval"); ConstructorInfo constructor = EvalType.GetConstructors()[0]; if (klass != null) { FieldInfo currentClassField = EvalType.GetField("myRubyClass"); currentClassField.SetValue(null, klass); } IEval evalObj; try { if (frame.current_block != null) evalObj = (IEval)constructor.Invoke(new object[] { frame.current_block }); else evalObj = (IEval)constructor.Invoke(new object[0]); } catch (System.Reflection.TargetInvocationException exception) { throw exception.InnerException; } return evalObj.Invoke(klass, recv, caller, frame); }
internal ClassSkeletonPostPass(ClassSkeleton subClass, PERWAPI.ClassDef subClassDef, AST.Node superClassNode) { this.subClass = subClass; this.subClassDef = subClassDef; this.superClassNode = superClassNode; }
internal override void DefineClass(CodeGenContext context, PERWAPI.FieldDef singleton) { // Class.singleton_class(caller, super) context.ldloc(0); context.ldarg("super"); context.call(Runtime.Class.singleton_class); context.stsfld(singleton); }
internal static FieldRef AddField(ClassRef classRef, string name, PERWAPI.Type type) { FieldRef field = classRef.GetField(name); if (field == null) field = classRef.AddField(name, type); return field; }
internal static MethodRef AddInstanceMethod(ClassRef classRef, string name, PERWAPI.Type retType, PERWAPI.Type[] args) { MethodRef method = classRef.GetMethod(name, args); if (method == null || method.GetCallConv() != CallConv.Instance) { method = classRef.AddMethod(name, retType, args); method.AddCallConv(CallConv.Instance); } return method; }
internal void newobj(PERWAPI.Method method) { buffer.MethInst(MethodOp.newobj, method); }
internal static Field FindField(PERWAPI.Class klass, string fieldName) { if (klass is ClassDef) return ((ClassDef)klass).GetField(fieldName); else { FieldRef f = ((ClassRef)klass).GetField(fieldName); if (f == null) f = ((ClassRef)klass).AddField(fieldName, PERWAPI.PrimitiveType.Object); return f; } }
internal AST.ISimple PreCompute(AST.Node node, string name, PERWAPI.Type type, out bool created) { if (node is AST.ISimple) { created = false; return (AST.ISimple)node; } else { created = true; node.GenCode(this); return StoreInLocal(name, type, node.location); } }
internal AST.LOCAL StoreInLocal(string name, PERWAPI.Type type, YYLTYPE location) { int local = CreateLocal(name, type); stloc(local); return new AST.LOCAL(local, location); }
internal int StoreInTemp(string name, PERWAPI.Type type, YYLTYPE location) { return StoreInLocal(name, type, location).local; }
internal int CreateLocal(string name, PERWAPI.Type type) { int local; if (unused_locals.ContainsKey(type) && unused_locals[type].Count > 0) { local = unused_locals[type].Pop(); } else { Local loc = new Local(name, type); CLRLocals.Add(loc); local = CLRLocals.Count - 1; } locals_inuse.Add(local); return local; }
internal static FieldDef AddField(ClassDef ParentClass, FieldAttr attr, string fieldName, PERWAPI.Type fieldType) { return ParentClass.AddField(attr, fieldName, fieldType); }
internal static void ExecuteMain(PERWAPI.PEFile Assembly, string[] args) { ExecuteMain(CodeGenContext.Load(Assembly), args); }
internal void newarr(PERWAPI.Type type) { buffer.TypeInst(TypeOp.newarr, type); }
internal void call(PERWAPI.Method method) { buffer.MethInst(MethodOp.call, method); }
internal static MethodRef AddStaticMethod(ClassRef classRef, string name, PERWAPI.Type retType, PERWAPI.Type[] args) { MethodRef method = classRef.GetMethod(name, args); if (method == null) method = classRef.AddMethod(name, retType, args); return method; }
private void CatchRetryException(CodeGenContext context, PERWAPI.CILLabel retryLabel) { // catch (Exception exception) int exception = context.StoreInTemp("exception", Runtime.RetryExceptionRef, location); PERWAPI.CILLabel reThrowLabel = context.NewLabel(); // if (exception.scope != current_frame) goto reThrowLabel; context.ldloc(0); context.ldloc(exception); context.ldfld(Runtime.RetryException.scope); context.bne( reThrowLabel); // goto retryLabel context.Goto(retryLabel); // reThrowLabel: context.CodeLabel(reThrowLabel); // throw exception; context.ldloc(exception); context.throwOp(); context.ReleaseLocal(exception, true); }
internal abstract void DefineClass(CodeGenContext context, PERWAPI.FieldDef singleton);
private void CatchBreakException(CodeGenContext context, int result, PERWAPI.CILLabel endLabel) { // catch (Exception exception) int exception = context.StoreInTemp("exception", Runtime.BreakExceptionRef, location); PERWAPI.CILLabel reThrowLabel = context.NewLabel(); // if (exception.scope != current_frame) goto reThrowLabel; context.ldloc(0); context.ldloc(exception); context.ldfld(Runtime.BreakException.scope); context.bne( reThrowLabel); // result = exception.return_value; context.ldloc(exception); context.ldfld(Runtime.BreakException.return_value); context.stloc(result); // goto endLabel; context.Goto(endLabel); // reThrowLabel: context.CodeLabel(reThrowLabel); // throw exception; context.ldloc(exception); context.throwOp(); context.ReleaseLocal(exception, true); }
internal override void DefineClass(CodeGenContext context, PERWAPI.FieldDef singleton) { // Class.define_module(scope, name.vid, caller); context.ldarg("scope"); context.ldstr(name.vid.ToString()); context.ldloc(0); context.call(Runtime.Class.rb_define_module); context.stsfld(singleton); }
internal void GenRescue(CodeGenContext context, PERWAPI.CILLabel endLabel, int RescueTemp, RESCUE_CLAUSE clauses) { // catch (System.Exception e) { int e = context.StoreInTemp("e", Runtime.SystemExceptionRef, location); //if (e is Ruby.ControlException) PERWAPI.CILLabel else1 = context.NewLabel(); context.ldloc(e); context.isinst(Runtime.ControlExceptionRef); context.brfalse(else1); // throw e; context.rethrow(); context.CodeLabel(else1); // Ruby.Exception exception; int exception = context.CreateLocal("exception", Runtime.ExceptionRef); //if (!(e is Ruby.RubyException)) PERWAPI.CILLabel else2 = context.NewLabel(); PERWAPI.CILLabel end = context.NewLabel(); context.ldloc(e); context.isinst(Runtime.RubyExceptionRef); context.brtrue(else2); // exception = new Ruby.CLRException(frame, e); context.ldloc(0); context.ldloc(e); context.newobj(Runtime.CLRException.ctor); context.stloc(exception); context.br(end); //else context.CodeLabel(else2); // exception = (Ruby.RubyException)e.parent; context.ldloc(e); context.cast(Runtime.RubyExceptionRef); context.ldfld(Runtime.RubyException.parent); context.stloc(exception); context.CodeLabel(end); //Eval.ruby_errinfo.value = exception; context.ldsfld(Runtime.Eval.ruby_errinfo); context.ldloc(exception); context.stfld(Runtime.global_variable.value); if (clauses != null) clauses.GenCode(context, endLabel, RescueTemp, exception); context.rethrow(); context.ReleaseLocal(e, true); context.ReleaseLocal(exception, true); }
internal ClassSkeleton(string name, PERWAPI.Class perwapiClass) { this.name = name; this.perwapiClass = perwapiClass; }
internal void GenCode(CodeGenContext context, PERWAPI.CILLabel endLabel, int RescueTemp, int exception) { for (RESCUE_CLAUSE clause = this; clause != null; clause = clause.next) { PERWAPI.CILLabel nextClause = context.NewLabel(); PERWAPI.CILLabel thisClause = context.NewLabel(); context.ldc_i4(0); LOCAL exceptionCaught = context.StoreInLocal("caught", PERWAPI.PrimitiveType.Boolean, this.location); for (Node type = clause.types; type != null; type = type.nd_next) { PERWAPI.CILLabel label1 = context.NewLabel(); // Precompute each separately to avoid computing a list of types type.GenCode0(context); LOCAL tt = context.StoreInLocal("type", PERWAPI.PrimitiveType.Object, type.location); new METHOD_CALL(tt, ID.intern(Tokens.tEQQ), new AST.LOCAL(exception, type.location), type.location).GenCode(context); context.ReleaseLocal(tt.local, true); context.call(Runtime.Eval.Test); context.brfalse(label1); context.PushTrue(); context.stloc(exceptionCaught.local); context.CodeLabel(label1); } context.ldloc(exceptionCaught.local); context.brtrue(thisClause); context.ReleaseLocal(exceptionCaught.local, true); context.br(nextClause); context.CodeLabel(thisClause); if (clause.var != null) { clause.var.Assign(context, new AST.LOCAL(exception, clause.var.location)); context.pop(); } if (clause.body != null) clause.body.GenCode(context); else context.ldnull(); if (context.Reachable()) context.stloc(RescueTemp); // reset $! //Eval.ruby_errinfo.value = null; context.ldsfld(Runtime.Eval.ruby_errinfo); context.ldnull(); context.stfld(Runtime.global_variable.value); context.Goto(endLabel); context.CodeLabel(nextClause); } }
/// <summary> /// Emit wrapper. /// </summary> private void emitWrapper(PERWAPI.MethodDef main, int paramLen) { // use explicit param count, and clear code this.paramLen = paramLen; this.code = null; int numArgs = isStatic && !self ? paramLen : paramLen+1; // TODO - this code probably isn't quite right, since it looks // like we generate local variables even when they might not be // used. Doesn't hurt anything, but is probably more efficient // if we could determine that from the fcode. // define our locals int numLocals = method.m_paramCount - paramLen; string[] localNames = new string[numLocals]; string[] localTypes = new string[numLocals]; for (int i=paramLen; i<method.m_paramCount; i++) { localNames[i-paramLen] = method.m_vars[i].name; localTypes[i-paramLen] = emit.nname(method.m_vars[i].type); } // emit code PERWAPI.CILInstructions code = doEmit(localNames, localTypes); // push arguments passed thru pushArgs(code, !(isStatic && !self), paramLen); // emit default arguments FCodeEmit.Reg[] regs = FCodeEmit.initRegs(emit.pod, isStatic, method.m_vars); int maxLocals = method.maxLocals(); int maxStack = 16; // TODO - add additional default expr stack height for (int i=paramLen; i<method.m_paramCount; i++) { FCodeEmit ce = new FCodeEmit(emit, method.m_vars[i].def, code, regs, emit.pod.typeRef(method.m_ret)); ce.paramCount = numArgs; ce.vars = method.m_vars; ce.isStatic = isStatic; // TODO - is this correct? ce.emit(false); // don't emit debug s cope for wrappers maxStack = System.Math.Max(maxStack, 2+i+8); } // TODO //code.maxLocals = maxLocals; //code.maxStack = maxStack; // call master implementation if (isStatic) code.MethInst(PERWAPI.MethodOp.call, main); else code.MethInst(PERWAPI.MethodOp.callvirt, main); // return code.Inst(PERWAPI.Op.ret); }
internal static void Load(PERWAPI.PEFile Assembly, Frame caller, string filename) { Load(CodeGenContext.Load(Assembly), caller, filename); }
internal void CatchReturnException(CodeGenContext context, PERWAPI.TryBlock tryBlock) { // catch (Ruby.ReturnException exception) { ... } context.StartBlock(Clause.Catch); { PERWAPI.CILLabel falseLabel = context.NewLabel(); int exception = context.StoreInTemp("exception", Runtime.ReturnExceptionRef, location); // if (exception.scope == thisframe) context.ldloc(exception); context.ldfld(Runtime.ReturnException.scope); context.ldloc(0); context.bne(falseLabel); // returnTemp = exception.return_value; context.ldloc(exception); context.ldfld(Runtime.ReturnException.return_value); context.stloc(returnTemp); context.Goto(context.labels.Return); // falseLabel: context.CodeLabel(falseLabel); // throw exception context.rethrow(); context.ReleaseLocal(exception, true); } context.EndCatchBlock(Runtime.ReturnExceptionRef, tryBlock); }
internal CodeGenContext CreateMethod(ClassDef ParentClass, MethAttr attr, string name, PERWAPI.Type return_type, params Param[] parameters) { CodeGenContext newContext = new CodeGenContext(this); newContext.Method = ParentClass.AddMethod(attr, ImplAttr.IL, name, return_type, parameters); if ((attr & MethAttr.Static) == 0) newContext.Method.AddCallConv(CallConv.Instance); newContext.CLRLocals = new List<Local>(); newContext.Method.CreateCodeBuffer(); newContext.buffer.OpenScope(); return newContext; }