static void EmitDebugEpilogue(MethodDefinition wrapper, ILProcessor il, DebugVariables vars) { if (vars != null) { var disposeMethod = vars.ErrorHelperType.Methods.First( method => method.Name == "Dispose"); // Store then reload the result from the call var resultLocal = new VariableDefinition(wrapper.ReturnType); if (resultLocal.VariableType.FullName != Program.TypeVoid.FullName) { il.Body.Variables.Add(resultLocal); il.Emit(OpCodes.Stloc, resultLocal); } // Special case End to turn on error checking. if (il.Body.Method.Name == "End") { il.Emit(OpCodes.Call, vars.Get_CurrentContext); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Conv_I1); il.Emit(OpCodes.Call, vars.Set_ErrorChecking); } // We need a NOP to set up the finally handler range correctly. var nopInstruction = Instruction.Create(OpCodes.Nop); var loadInstruction = Instruction.Create(OpCodes.Ldloca, vars.ErrorHelperLocal); var disposeInstruction = Instruction.Create(OpCodes.Call, disposeMethod); var endFinallyInstruction = Instruction.Create(OpCodes.Endfinally); var endTryInstruction = Instruction.Create(OpCodes.Leave, nopInstruction); il.Append(endTryInstruction); il.Append(loadInstruction); il.Append(disposeInstruction); il.Append(endFinallyInstruction); il.Append(nopInstruction); var finallyHandler = new ExceptionHandler(ExceptionHandlerType.Finally); finallyHandler.TryStart = vars.BeginTry; finallyHandler.TryEnd = loadInstruction; finallyHandler.HandlerStart = loadInstruction; finallyHandler.HandlerEnd = nopInstruction; il.Body.ExceptionHandlers.Add(finallyHandler); if (resultLocal.VariableType.FullName != Program.TypeVoid.FullName) { il.Emit(OpCodes.Ldloc, resultLocal); } } }
public static DebugVariables GetVariables(Jint.Engine engines) { DebugVariables variables = new DebugVariables(); if (engines.ExecutionContext.LexicalEnvironment != null) { var lexicalEnvironment = engines.ExecutionContext.LexicalEnvironment; variables.Local = GetLocalVariables(lexicalEnvironment); variables.Global = GetGlobalVariables(lexicalEnvironment); } return(variables); }
private static DebugVariables EmitDebugPrologue(MethodDefinition wrapper, ILProcessor il) { DebugVariables vars = null; if (il.Body.Method.Name != "GetError") { // Pull out the namespace name, method fullname will look // something like "type namespace.class::method(type arg)" var module = il.Body.Method.FullName; module = module.Substring(module.IndexOf(' ') + 1); module = module.Substring(0, module.IndexOf("::", StringComparison.Ordinal)); module = module.Substring(0, module.LastIndexOf('.')); // Only works for Graphics modules due to hardcoded use of // OpenTK.Graphics.GraphicsContext if (module == "OpenTK.Graphics.OpenGL4" || module == "OpenTK.Graphics.OpenGL" || module == "OpenTK.Graphics.ES10" || module == "OpenTK.Graphics.ES11" || module == "OpenTK.Graphics.ES20" || module == "OpenTK.Graphics.ES30") { var errorHelperType = wrapper.Module.GetType(module, "ErrorHelper"); if (errorHelperType != null) { vars = new DebugVariables(); vars.ErrorHelperType = errorHelperType; // GraphicsContext type var graphicsContext = wrapper.Module.Types.First( type => type.FullName == "OpenTK.Graphics.GraphicsContext"); // IGraphicsContext type var iGraphicsContext = wrapper.Module.Types.First( type => type.FullName == "OpenTK.Graphics.IGraphicsContext"); // Get the constructor that takes a GraphicsContext parameter var ctor = vars.ErrorHelperType.GetConstructors().FirstOrDefault( c => c.Parameters.Count == 1 && c.Parameters[0].ParameterType.FullName == iGraphicsContext.FullName); if (ctor == null) { throw new InvalidOperationException( String.Format( "{0} does needs a constructor taking {1}", errorHelperType, graphicsContext)); } // GraphicsContext.CurrentContext property getter vars.Get_CurrentContext = graphicsContext.Methods.First( method => method.Name == "get_CurrentContext"); vars.Set_ErrorChecking = graphicsContext.Methods.First( method => method.Name == "set_ErrorChecking"); vars.ErrorHelperLocal = new VariableDefinition(vars.ErrorHelperType); // using (new ErrorHelper(GraphicsContext.CurrentContext)) { ... il.Body.Variables.Add(vars.ErrorHelperLocal); il.Emit(OpCodes.Ldloca, vars.ErrorHelperLocal); il.Emit(OpCodes.Call, vars.Get_CurrentContext); il.Emit(OpCodes.Call, ctor); vars.BeginTry = Instruction.Create(OpCodes.Nop); il.Append(vars.BeginTry); // Special case Begin to turn off error checking. if (il.Body.Method.Name == "Begin") { il.Emit(OpCodes.Call, vars.Get_CurrentContext); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Conv_I1); il.Emit(OpCodes.Call, vars.Set_ErrorChecking); } } } } return(vars); }
// Create body for method private static void ProcessMethod(MethodDefinition wrapper, MethodDefinition native, int slot, FieldDefinition entry_points) { var body = wrapper.Body; var il = body.GetILProcessor(); var instructions = body.Instructions; instructions.Clear(); // Declare pinned variables for every reference and array parameter // and push each parameter on the stack DebugVariables vars = null; if (Options.EnableDebugCalls) { vars = EmitDebugPrologue(wrapper, il); } // Patch convenience wrappers List <GeneratedVariableIdentifier> generatedVariables = new List <GeneratedVariableIdentifier>(); if (wrapper.Parameters.Count == native.Parameters.Count) { generatedVariables = EmitParameters(wrapper, native, body, il); } else { int difference = native.Parameters.Count - wrapper.Parameters.Count; generatedVariables = EmitConvenienceWrapper(wrapper, native, difference, body, il); } if (slot == -1 || Options.UseDLLImport) { // issue DllImport call EmitCall(il, native); } else { // push the entry point address on the stack EmitEntryPoint(entry_points, il, slot); // issue calli EmitCalli(il, native); } if (wrapper.ReturnType.Name != "Void") { EmitReturnTypeWrapper(wrapper, native, body, il); } EmitParameterEpilogues(wrapper, native, body, il, generatedVariables); if (Options.EnableDebugCalls) { EmitDebugEpilogue(wrapper, il, vars); } // return il.Emit(OpCodes.Ret); if (body.Variables.Count > 0) { // Required for verifiable executables // (otherwise peverify complains bitterly) body.InitLocals = true; } body.OptimizeMacros(); }
static void EmitDebugEpilogue(MethodDefinition wrapper, ILProcessor il, DebugVariables vars) { if (vars != null) { var disposeMethod = vars.ErrorHelperType.Methods.First( method => method.Name == "Dispose"); // Store then reload the result from the call var resultLocal = new VariableDefinition(wrapper.ReturnType); if (resultLocal.VariableType.FullName != Program.TypeVoid.FullName) { il.Body.Variables.Add(resultLocal); il.Emit(OpCodes.Stloc, resultLocal); } // Special case End to turn on error checking. if (il.Body.Method.Name == "End") { il.Emit(OpCodes.Call, vars.Get_CurrentContext); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Conv_I1); il.Emit(OpCodes.Call, vars.Set_ErrorChecking); } // We need a NOP to set up the finally handler range correctly. var nopInstruction = Instruction.Create(OpCodes.Nop); var loadInstruction = Instruction.Create(OpCodes.Ldloca, vars.ErrorHelperLocal); var disposeInstruction = Instruction.Create(OpCodes.Call, disposeMethod); var endFinallyInstruction = Instruction.Create(OpCodes.Endfinally); var endTryInstruction = Instruction.Create(OpCodes.Leave, nopInstruction); il.Append(endTryInstruction); il.Append(loadInstruction); il.Append(disposeInstruction); il.Append(endFinallyInstruction); il.Append(nopInstruction); var finallyHandler = new ExceptionHandler(ExceptionHandlerType.Finally); finallyHandler.TryStart = vars.BeginTry; finallyHandler.TryEnd = loadInstruction; finallyHandler.HandlerStart = loadInstruction; finallyHandler.HandlerEnd = nopInstruction; il.Body.ExceptionHandlers.Add(finallyHandler); if (resultLocal.VariableType.FullName != Program.TypeVoid.FullName) { il.Emit(OpCodes.Ldloc, resultLocal); } } }
static DebugVariables EmitDebugPrologue(MethodDefinition wrapper, ILProcessor il) { DebugVariables vars = null; if (il.Body.Method.Name != "GetError") { // Pull out the namespace name, method fullname will look // something like "type namespace.class::method(type arg)" var module = il.Body.Method.FullName; module = module.Substring(module.IndexOf(' ') + 1); module = module.Substring(0, module.IndexOf("::")); module = module.Substring(0, module.LastIndexOf('.')); // Only works for Graphics modules due to hardcoded use of // OpenTK.Graphics.GraphicsContext if (module == "OpenTK.Graphics.OpenGL4" || module == "OpenTK.Graphics.OpenGL" || module == "OpenTK.Graphics.ES10" || module == "OpenTK.Graphics.ES11" || module == "OpenTK.Graphics.ES20" || module == "OpenTK.Graphics.ES30") { var errorHelperType = wrapper.Module.GetType(module, "ErrorHelper"); if (errorHelperType != null) { vars = new DebugVariables(); vars.ErrorHelperType = errorHelperType; // GraphicsContext type var graphicsContext = wrapper.Module.Types.First( type => type.FullName == "OpenTK.Graphics.GraphicsContext"); // IGraphicsContext type var iGraphicsContext = wrapper.Module.Types.First( type => type.FullName == "OpenTK.Graphics.IGraphicsContext"); // Get the constructor that takes a GraphicsContext parameter var ctor = vars.ErrorHelperType.GetConstructors().FirstOrDefault( c => c.Parameters.Count == 1 && c.Parameters[0].ParameterType.FullName == iGraphicsContext.FullName); if (ctor == null) { throw new InvalidOperationException( String.Format( "{0} does needs a constructor taking {1}", errorHelperType, graphicsContext)); } // GraphicsContext.CurrentContext property getter vars.Get_CurrentContext = graphicsContext.Methods.First( method => method.Name == "get_CurrentContext"); vars.Set_ErrorChecking = graphicsContext.Methods.First( method => method.Name == "set_ErrorChecking"); vars.ErrorHelperLocal = new VariableDefinition(vars.ErrorHelperType); // using (new ErrorHelper(GraphicsContext.CurrentContext)) { ... il.Body.Variables.Add(vars.ErrorHelperLocal); il.Emit(OpCodes.Ldloca, vars.ErrorHelperLocal); il.Emit(OpCodes.Call, vars.Get_CurrentContext); il.Emit(OpCodes.Call, ctor); vars.BeginTry = Instruction.Create(OpCodes.Nop); il.Append(vars.BeginTry); // Special case Begin to turn off error checking. if (il.Body.Method.Name == "Begin") { il.Emit(OpCodes.Call, vars.Get_CurrentContext); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Conv_I1); il.Emit(OpCodes.Call, vars.Set_ErrorChecking); } } } } return vars; }
// Create body for method static void ProcessMethod(MethodDefinition wrapper, MethodDefinition native, int slot, FieldDefinition entry_points, IEnumerable <string> options) { var body = wrapper.Body; var il = body.GetILProcessor(); var instructions = body.Instructions; instructions.Clear(); // Declare pinned variables for every reference and array parameter // and push each parameter on the stack DebugVariables vars = null; if (options.Contains("-debug")) { vars = EmitDebugPrologue(wrapper, il); } // Patch convenience wrappers if (wrapper.Parameters.Count == native.Parameters.Count) { EmitParameters(wrapper, body, il); } else { int difference = native.Parameters.Count - wrapper.Parameters.Count; EmitConvenienceWrapper(wrapper, native, difference, body, il); } if (slot != -1) { // push the entry point address on the stack EmitEntryPoint(entry_points, il, slot); // issue calli EmitCalli(il, native); } else { // issue DllImport call EmitCall(il, native); } if (wrapper.ReturnType.Name != "Void") { EmitReturnTypeWrapper(wrapper, native, body, il); } if (wrapper.Parameters.Any(p => p.ParameterType.Name == "StringBuilder")) { EmitStringBuilderEpilogue(wrapper, native, body, il); } if (wrapper.Parameters.Any(p => p.ParameterType.Name == "String" && p.ParameterType.IsArray)) { EmitStringArrayEpilogue(wrapper, body, il); } if (wrapper.Parameters.Any(p => p.ParameterType.Name == "String" && !p.ParameterType.IsArray)) { EmitStringEpilogue(wrapper, body, il); } if (options.Contains("-debug")) { EmitDebugEpilogue(wrapper, il, vars); } // return il.Emit(OpCodes.Ret); if (body.Variables.Count > 0) { // Required for verifiable executables // (otherwise peverify complains bitterly) body.InitLocals = true; } body.OptimizeMacros(); }
void ToWorkshop(Func <VarCollection, Rule[]> addRules) { // Set up the variable collection. VarCollection.Setup(); // Set up initial global and player rules. InitialGlobal = new TranslateRule(this, "Initial Global", RuleEvent.OngoingGlobal); InitialPlayer = new TranslateRule(this, "Initial Player", RuleEvent.OngoingPlayer); WorkshopRules = new List <Rule>(); // Init called types. foreach (var type in Types.CalledTypes.Distinct()) { type.WorkshopInit(this); } // Assign variables at the rule-set level. foreach (var variable in rulesetVariables) { // Assign the variable an index. var assigner = DefaultIndexAssigner.Add(VarCollection, variable, true, null) as IndexReference; // Assigner will be non-null if it is an IndexReference. if (assigner != null) { DebugVariables.Add(variable, assigner); // Initial value. if (variable.InitialValue != null) { var addToInitialRule = GetInitialRule(variable.VariableType == VariableType.Global); addToInitialRule.ActionSet.AddAction(assigner.SetVariable( (Element)variable.InitialValue.Parse(addToInitialRule.ActionSet) )); } } } // Setup single-instance methods. foreach (var method in subroutines) { method.SetupSubroutine(); } // Parse the rules. foreach (var rule in rules) { var translate = new TranslateRule(this, rule); Rule newRule = translate.GetRule(); WorkshopRules.Add(newRule); rule.ElementCountLens.RuleParsed(newRule); } // Add built-in rules. // Initial player if (InitialPlayer.Actions.Count > 0) { WorkshopRules.Insert(0, InitialPlayer.GetRule()); } // Initial global if (InitialGlobal.Actions.Count > 0) { WorkshopRules.Insert(0, InitialGlobal.GetRule()); } // Additional if (addRules != null) { WorkshopRules.AddRange(addRules.Invoke(VarCollection).Where(rule => rule != null)); } // Order the workshop rules by priority. WorkshopRules = WorkshopRules.OrderBy(wr => wr.Priority).ToList(); // Get the final workshop string. WorkshopBuilder result = new WorkshopBuilder(Language); LanguageInfo.I18nWarningMessage(result, Language); // Get the custom game settings. if (Importer.MergedLobbySettings != null) { Ruleset settings = Ruleset.Parse(Importer.MergedLobbySettings); settings.ToWorkshop(result); result.AppendLine(); } // Get the variables. VarCollection.ToWorkshop(result); result.AppendLine(); // Print class identifiers. Types.PrintClassIdentifiers(result); // Get the subroutines. SubroutineCollection.ToWorkshop(result); // Get the rules. for (int i = 0; i < WorkshopRules.Count; i++) { WorkshopRules[i].ToWorkshop(result, OptimizeOutput); ElementCount += WorkshopRules[i].ElementCount(OptimizeOutput); if (i != WorkshopRules.Count - 1) { result.AppendLine(); } } WorkshopCode = result.ToString(); }
void ToWorkshop(Func <VarCollection, Rule[]> addRules) { // Set up the variable collection. VarCollection.Setup(); WorkshopConverter = new ToWorkshop(this); // Set up initial global and player rules. InitialGlobal = new TranslateRule(this, "Initial Global", RuleEvent.OngoingGlobal); InitialPlayer = new TranslateRule(this, "Initial Player", RuleEvent.OngoingPlayer); WorkshopRules = new List <Rule>(); WorkshopConverter.InitStatic(); // Init called types. foreach (var workshopInit in _workshopInit) { workshopInit.WorkshopInit(this); } // Assign variables at the rule-set level. foreach (var variable in rulesetVariables) { var addToInitialRule = GetInitialRule(variable.VariableType == VariableType.Global); // Assign the variable an index. IGettable value = variable .GetDefaultInstance(null) .GetAssigner(new(addToInitialRule.ActionSet)) .GetValue(new GettableAssignerValueInfo(addToInitialRule.ActionSet) { SetInitialValue = SetInitialValue.SetIfExists }); DefaultIndexAssigner.Add(variable, value); if (value is IndexReference indexReference) { DebugVariables.Add(variable, indexReference); } } // Parse the rules. foreach (var rule in rules) { var translate = new TranslateRule(this, rule); Rule newRule = GetRule(translate.GetRule()); WorkshopRules.Add(newRule); rule.ElementCountLens.RuleParsed(newRule); } // Add built-in rules. // Initial player if (InitialPlayer.Actions.Count > 0) { WorkshopRules.Insert(0, GetRule(InitialPlayer.GetRule())); } // Initial global if (InitialGlobal.Actions.Count > 0) { WorkshopRules.Insert(0, GetRule(InitialGlobal.GetRule())); } // Additional if (addRules != null) { WorkshopRules.AddRange(addRules.Invoke(VarCollection).Where(rule => rule != null)); } // Complete portable functions WorkshopConverter.LambdaBuilder.Complete(); // Order the workshop rules by priority. WorkshopRules = WorkshopRules.OrderBy(wr => wr.Priority).ToList(); // Get the final workshop string. WorkshopBuilder result = new WorkshopBuilder(Language); LanguageInfo.I18nWarningMessage(result, Language); // Get the custom game settings. if (Importer.MergedLobbySettings != null) { Ruleset settings = Ruleset.Parse(Importer.MergedLobbySettings); settings.ToWorkshop(result); result.AppendLine(); } // Get the variables. VarCollection.ToWorkshop(result); result.AppendLine(); // Get the subroutines. SubroutineCollection.ToWorkshop(result); // Get the rules. for (int i = 0; i < WorkshopRules.Count; i++) { WorkshopRules[i].ToWorkshop(result); ElementCount += WorkshopRules[i].ElementCount(); if (i != WorkshopRules.Count - 1) { result.AppendLine(); } } WorkshopCode = result.GetResult(); }