Browse Source

Implement source maps in fast-jit

jonathanvdc 8 years ago
parent
commit
6be9e08ac4

+ 26 - 0
kernel/modelverse_jit/bytecode_to_cfg.py

@@ -32,6 +32,13 @@ class AnalysisState(object):
         # We want to create the following definition:
         #
         #     !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
         #         $_ = declare-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
         # 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())
         for node_id, name in param_dict.items():
             variable = bytecode_ir.VariableNode(node_id, name)
@@ -67,6 +90,9 @@ class AnalysisState(object):
             # Analyze the 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!
             if instruction.next_instruction is not None:
                 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."""
         index = self.__get_def_index_for_insert(anchor)
         result = self.create_definition(value)
+        if result.debug_information is None:
+            result.debug_information = anchor.debug_information
+
         self.definitions.insert(index, result)
         self.renumber_definitions()
         return result
@@ -70,6 +73,9 @@ class BasicBlock(object):
         """Inserts the second definition or value after the first definition."""
         index = self.__get_def_index_for_insert(anchor)
         result = self.create_definition(value)
+        if result.debug_information is None:
+            result.debug_information = anchor.debug_information
+
         self.definitions.insert(index + 1, result)
         self.renumber_definitions()
         return result
@@ -127,6 +133,7 @@ class Definition(object):
         self.value = value
         if value is not None:
             assert isinstance(value, Value) or isinstance(value, Definition)
+        self.debug_information = None
 
     def redefine(self, 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
    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):
     """A value that is the result of a direct function call."""
     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),
         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):
     """Schedules definitions within a basic block in the order they occur in."""
     def __init__(self, lowering_state, definitions, flow):
@@ -353,6 +359,11 @@ class SimpleDefinitionScheduler(object):
                 pass
             else:
                 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():
                     def_load = self.lowering_state.create_definition_load(definition)
                     statements.append(
@@ -990,7 +1001,8 @@ class LoweringState(object):
         lambda seq:
         tree_ir.ListSliceInstruction(seq, None, None, tree_ir.LiteralInstruction(-1)),
         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):