예제 #1
0
 def makeAssemblyDebuggable(self, assembly_builder):
     '''
     Make the assembly debuggable by adding specific attributes.
     '''
     # http://blogs.msdn.com/rmbyers/archive/2005/06/26/432922.aspx
     da_type = typeof(DebuggableAttribute)
     da_ctor = da_type.GetConstructor(System.Array[System.Type]([typeof(DebuggableAttribute.DebuggingModes)]))
     da_builder = CustomAttributeBuilder(da_ctor, System.Array[System.Object]([DebuggableAttribute.DebuggingModes.DisableOptimizations | 
         DebuggableAttribute.DebuggingModes.Default]))
     assembly_builder.SetCustomAttribute(da_builder)
예제 #2
0
 def generateStaticDataInitialization(self, data_visitor, type_builder):
     """
     Generate a type constructor to setup static data for DATA statements
     """
     # static (type) constructor - initialise static DATA
     
     
     # TODO: Replace this with Dictionary<int, int>
     
     self.data_field = type_builder.DefineField('data', cts.string_array_type,
                                                   FieldAttributes.Private | FieldAttributes.Static)
     self.data_line_number_map_field = type_builder.DefineField('dataLineNumbers', cts.int_int_dictionary_type,
                                                   FieldAttributes.Private | FieldAttributes.Static)
     self.data_index_field = type_builder.DefineField('dataIndex', typeof(System.Int32),
                                                             FieldAttributes.Private | FieldAttributes.Static)
     
     type_constructor_builder = type_builder.DefineTypeInitializer()
     generator = type_constructor_builder.GetILGenerator()
     data_local = generator.DeclareLocal(cts.string_array_type)
     data_index_local = generator.DeclareLocal(cts.int_int_dictionary_type)
     
     # Initialise the data field
     emitLdc_I4(generator, len(data_visitor.data)) # Load the array length onto the stack
     generator.Emit(OpCodes.Newarr, System.String) # New array with type information
     generator.Emit(OpCodes.Stloc, data_local) # Store array reference in local 0
     for index, item in enumerate(data_visitor.data):
         generator.Emit(OpCodes.Ldloc, data_local)       # Load the array onto the stack
         emitLdc_I4(generator, index)          # Load the index onto the stack
         generator.Emit(OpCodes.Ldstr, item)   # Load the string onto the stack
         generator.Emit(OpCodes.Stelem_Ref)    # Assign to array element
     generator.Emit(OpCodes.Ldloc, data_local)            # Load the array onto the stack
     generator.Emit(OpCodes.Stsfld, self.data_field) # Store it in the static field
     
     # Initialise the data index field -
     # this needs to be initialized with a Dictionary
     #generic_dictionary_type = typeof(System.Collections.Generic.Dictionary)
     #int_int_dictionary_type = generic_dictionary_type.MakeGenericType(
     #                       System.Array[System.Type]((typeof(System.Int32), typeof(System.Int32))))
 
     int_int_dictionary_ctor_info = cts.int_int_dictionary_type.GetConstructor(System.Type.EmptyTypes) # Get the default constructor
     generator.Emit(OpCodes.Newobj, int_int_dictionary_ctor_info)
     generator.Emit(OpCodes.Stloc, data_index_local) # Store dictionary reference in local 1
     
     add_method_info = cts.int_int_dictionary_type.GetMethod('Add')
     
     for line_number, index in data_visitor.index.items():
         generator.Emit(OpCodes.Ldloc, data_index_local)   # Load the dictionary onto the stack
         emitLdc_I4(generator, line_number)                # Load the line_number onto the stack
         emitLdc_I4(generator, index)                      # Load the index onto the stack
         generator.Emit(OpCodes.Call, add_method_info)     # Call Dictionary<int,int>.Add()
         
     generator.Emit(OpCodes.Ldloc, data_index_local)       # Load the dictionary onto the stack
     generator.Emit(OpCodes.Stsfld, self.data_line_number_map_field)  # Store it in the static field
     generator.Emit(OpCodes.Ret)
예제 #3
0
 def generateAssembly(self, source_file, name, global_symbols, data_visitor, ordered_basic_blocks):
     """
     :param source_file: The BASIC source file - for debugging information
     :param name: The name given to the assembly to be generated.
     :param ordered_basic_blocks: A mapping type where keys are the entry point name
                                  and values are a sequence of BasicBlocks for that method/program.
     """
     # Generate an assembly
     # Generate a namespace
     # Generate a static class
     # Create global variables as members
     # For each entry point
     #  - create a method
     # Mark the entry point to the assembly
     
     # We build the assembly in the current AppDomain
     domain = Thread.GetDomain()
     assembly_name = AssemblyName(name)
     assembly_builder = domain.DefineDynamicAssembly(assembly_name, AssemblyBuilderAccess.RunAndSave)
     
     self.makeAssemblyDebuggable(assembly_builder)
     
     module_builder = assembly_builder.DefineDynamicModule(name + ".exe", True) # pass True to track debug info
     owl_module = typeof(OwlRuntime.OwlModule)
     
     # Set the source file that we want to associate with this module
     self.doc = module_builder.DefineDocument(source_file, System.Guid.Empty, System.Guid.Empty, System.Guid.Empty)
     
     type_builder = module_builder.DefineType(name,
                                              TypeAttributes.Class | TypeAttributes.Public,
                                              object().GetType())
     
     self.createAndAttachStaticEmitters(owl_module)
     self.createAndAttachGlobalEmitters(global_symbols, type_builder) 
     
     if len(data_visitor.data) > 0:
         self.generateStaticDataInitialization(data_visitor, type_builder)
     
     # Generate all the unique method names
     # TODO: This would be sooo much easier if the entry_point.name
     # property had been set useful, and PROC and FN retained in identifier names everywhere!
     # TODO: Should also wrap the main program in DEF PROCMain - safely!
     for entry_name, basic_blocks in ordered_basic_blocks.items():
         entry_point = basic_blocks[0].entryPoint
         if isinstance(entry_point, DefinitionStatement):
             self.createCtsMethodName(entry_point.name)   
         else: # Main
             assert entry_name == '__owl__main'
             assert iter(entry_point.entryPoints).next().startswith('MAIN')
             self.createCtsMethodName('FNMain')    
     
     #for owl_name, clr_name in self.owl_to_clr_method_names.items():
     #    print owl_name, " ==> ", clr_name
         
     # Generate all the empty methods, so we can retrieve them from the type builder    
     for basic_blocks in ordered_basic_blocks.values():
         self.generateMethod(type_builder, basic_blocks)
             
     # Generate the body of each method
     stop_on_error = False    
     for basic_blocks in ordered_basic_blocks.values():
         try:
             self.generateMethodBody(type_builder, basic_blocks)
         except CodeGenerationError, e:
             logging.critical("STOPPING %s\n\n\n", e)
             if stop_on_error:
                 break