Przeglądaj źródła

Implement source maps in fast-jit

jonathanvdc 9 lat temu
rodzic
commit
f8770ef322

+ 26 - 0
kernel/modelverse_jit/bytecode_to_cfg.py

@@ -32,6 +32,13 @@ class AnalysisState(object):
         # We want to create the following definition:
         # We want to create the following definition:
         #
         #
         #     !entry_point():
         #     !entry_point():
+        #         static if self.jit.source_maps_enabled:
+        #             $function_name = literal <function map>
+        #             $source_map_name = literal <source map name>
+        #             $origin_name = literal jit_runtime.FAST_JIT_ORIGIN_NAME
+        #             $_ = direct-call ('macro-positional', void) register_debug_info(
+        #                 function_name=$functionsource_map=$source_map_name)
+        #
         #         $jit_locals = alloc-root-node
         #         $jit_locals = alloc-root-node
         #         $_ = declare-local var(...)
         #         $_ = declare-local var(...)
         #         $param_1 = resolve-local var(...)
         #         $param_1 = resolve-local var(...)
@@ -41,6 +48,22 @@ class AnalysisState(object):
         #
         #
         # We also want to store '$jit_locals' in an attribute, so we can
         # We also want to store '$jit_locals' in an attribute, so we can
         # use it to shield locals from the GC.
         # use it to shield locals from the GC.
+        if self.jit.source_maps_enabled:
+            function_name = self.current_block.append_definition(
+                cfg_ir.Literal(self.function_name))
+            source_map_name = self.current_block.append_definition(
+                cfg_ir.Literal(self.jit.get_source_map_name(self.function_name)))
+            origin_name = self.current_block.append_definition(
+                cfg_ir.Literal(jit_runtime.FAST_JIT_ORIGIN_NAME))
+            self.current_block.append_definition(
+                cfg_ir.DirectFunctionCall(
+                    cfg_ir.REGISTER_DEBUG_INFO_MACRO_NAME,
+                    [('function_name', function_name),
+                     ('source_map', source_map_name),
+                     ('origin_name', origin_name)],
+                    calling_convention=cfg_ir.MACRO_POSITIONAL_CALLING_CONVENTION,
+                    has_value=False))
+
         self.root_node = self.current_block.append_definition(cfg_ir.AllocateRootNode())
         self.root_node = self.current_block.append_definition(cfg_ir.AllocateRootNode())
         for node_id, name in param_dict.items():
         for node_id, name in param_dict.items():
             variable = bytecode_ir.VariableNode(node_id, name)
             variable = bytecode_ir.VariableNode(node_id, name)
@@ -67,6 +90,9 @@ class AnalysisState(object):
             # Analyze the instruction.
             # Analyze the instruction.
             result = self.instruction_analyzers[instruction_type](self, instruction)
             result = self.instruction_analyzers[instruction_type](self, instruction)
 
 
+            if self.jit.source_maps_enabled:
+                result.debug_information = instruction.debug_information
+
             # Check if the instruction has a 'next' instruction. If so, analyze it!
             # Check if the instruction has a 'next' instruction. If so, analyze it!
             if instruction.next_instruction is not None:
             if instruction.next_instruction is not None:
                 next_result = self.analyze(instruction.next_instruction)
                 next_result = self.analyze(instruction.next_instruction)

+ 10 - 0
kernel/modelverse_jit/cfg_ir.py

@@ -62,6 +62,9 @@ class BasicBlock(object):
         """Inserts the second definition or value before the first definition."""
         """Inserts the second definition or value before the first definition."""
         index = self.__get_def_index_for_insert(anchor)
         index = self.__get_def_index_for_insert(anchor)
         result = self.create_definition(value)
         result = self.create_definition(value)
+        if result.debug_information is None:
+            result.debug_information = anchor.debug_information
+
         self.definitions.insert(index, result)
         self.definitions.insert(index, result)
         self.renumber_definitions()
         self.renumber_definitions()
         return result
         return result
@@ -70,6 +73,9 @@ class BasicBlock(object):
         """Inserts the second definition or value after the first definition."""
         """Inserts the second definition or value after the first definition."""
         index = self.__get_def_index_for_insert(anchor)
         index = self.__get_def_index_for_insert(anchor)
         result = self.create_definition(value)
         result = self.create_definition(value)
+        if result.debug_information is None:
+            result.debug_information = anchor.debug_information
+
         self.definitions.insert(index + 1, result)
         self.definitions.insert(index + 1, result)
         self.renumber_definitions()
         self.renumber_definitions()
         return result
         return result
@@ -127,6 +133,7 @@ class Definition(object):
         self.value = value
         self.value = value
         if value is not None:
         if value is not None:
             assert isinstance(value, Value) or isinstance(value, Definition)
             assert isinstance(value, Value) or isinstance(value, Definition)
+        self.debug_information = None
 
 
     def redefine(self, new_value):
     def redefine(self, new_value):
         """Tweaks this definition to take on the given new value."""
         """Tweaks this definition to take on the given new value."""
@@ -514,6 +521,9 @@ MAYBE_GC_PROTECT_MACRO_NAME = 'maybe_gc_protect'
 """The name of the macro that protects its first argument from the GC by drawing an edge between
 """The name of the macro that protects its first argument from the GC by drawing an edge between
    it and the second argument, but only if that first argument is not None."""
    it and the second argument, but only if that first argument is not None."""
 
 
+REGISTER_DEBUG_INFO_MACRO_NAME = 'register_debug_info'
+"""The name of the macro that sets the current function's name, source map and origin."""
+
 class DirectFunctionCall(Value):
 class DirectFunctionCall(Value):
     """A value that is the result of a direct function call."""
     """A value that is the result of a direct function call."""
     def __init__(
     def __init__(

+ 13 - 1
kernel/modelverse_jit/cfg_to_tree.py

@@ -315,6 +315,12 @@ def lower_maybe_gc_protect(condition, protected_value, root):
         lower_gc_protect(protected_value, root),
         lower_gc_protect(protected_value, root),
         tree_ir.EmptyInstruction())
         tree_ir.EmptyInstruction())
 
 
+def lower_register_debug_info(function_name, source_map, origin):
+    """Lowers a REGISTER_DEBUG_INFO_MACRO_NAME call."""
+    assert isinstance(source_map, tree_ir.LiteralInstruction)
+    return tree_ir.RegisterDebugInfoInstruction(
+        function_name, tree_ir.LoadGlobalInstruction(source_map.literal), origin)
+
 class SimpleDefinitionScheduler(object):
 class SimpleDefinitionScheduler(object):
     """Schedules definitions within a basic block in the order they occur in."""
     """Schedules definitions within a basic block in the order they occur in."""
     def __init__(self, lowering_state, definitions, flow):
     def __init__(self, lowering_state, definitions, flow):
@@ -353,6 +359,11 @@ class SimpleDefinitionScheduler(object):
                 pass
                 pass
             else:
             else:
                 lowered_value = self.lowering_state.lower_value(definition_value)
                 lowered_value = self.lowering_state.lower_value(definition_value)
+                if (definition.debug_information is not None
+                        and self.lowering_state.jit.source_maps_enabled):
+                    lowered_value = tree_ir.DebugInfoInstruction(
+                        lowered_value, definition.debug_information)
+
                 if definition.has_value():
                 if definition.has_value():
                     def_load = self.lowering_state.create_definition_load(definition)
                     def_load = self.lowering_state.create_definition_load(definition)
                     statements.append(
                     statements.append(
@@ -990,7 +1001,8 @@ class LoweringState(object):
         lambda seq:
         lambda seq:
         tree_ir.ListSliceInstruction(seq, None, None, tree_ir.LiteralInstruction(-1)),
         tree_ir.ListSliceInstruction(seq, None, None, tree_ir.LiteralInstruction(-1)),
         cfg_ir.GC_PROTECT_MACRO_NAME: lower_gc_protect,
         cfg_ir.GC_PROTECT_MACRO_NAME: lower_gc_protect,
-        cfg_ir.MAYBE_GC_PROTECT_MACRO_NAME: lower_maybe_gc_protect
+        cfg_ir.MAYBE_GC_PROTECT_MACRO_NAME: lower_maybe_gc_protect,
+        cfg_ir.REGISTER_DEBUG_INFO_MACRO_NAME: lower_register_debug_info
     }
     }
 
 
 def lower_flow_graph(entry_point, jit):
 def lower_flow_graph(entry_point, jit):