فهرست منبع

Add theoretical JIT support for 'declare', 'global' and 'resolve'

jonathanvdc 8 سال پیش
والد
کامیت
4db787a096
2فایلهای تغییر یافته به همراه257 افزوده شده و 3 حذف شده
  1. 156 0
      kernel/modelverse_jit/jit.py
  2. 101 3
      kernel/modelverse_jit/tree_ir.py

+ 156 - 0
kernel/modelverse_jit/jit.py

@@ -95,6 +95,19 @@ class AnalysisState(object):
     def __init__(self):
         self.analyzed_instructions = set()
 
+    def get_local_name(self, local_id):
+        """Gets the name for a local with the given id."""
+        return 'local%d' % local_id
+
+    def retrieve_user_root(self):
+        """Creates an instruction that stores the user_root variable
+           in a local."""
+        return tree_ir.StoreLocalInstruction(
+            'user_root',
+            tree_ir.LoadIndexInstruction(
+                tree_ir.LoadLocalInstruction(KWARGS_PARAMETER_NAME),
+                tree_ir.LiteralInstruction('user_root')))
+
     def analyze(self, instruction_id):
         """Tries to build an intermediate representation from the instruction with the
         given id."""
@@ -295,11 +308,154 @@ class AnalysisState(object):
 
         raise primitive_functions.PrimitiveFinished(result)
 
+    def analyze_resolve(self, instruction_id):
+        """Tries to analyze the given 'resolve' instruction."""
+        var_id, = yield [("RD", [instruction_id, "var"])]
+
+        # To resolve a variable, we'll do something along the
+        # lines of:
+        #
+        #     if 'local_var' in locals():
+        #         tmp = local_var
+        #     else:
+        #         _globals, var_name = yield [("RD", [user_root, "globals"]),
+        #                                     ("RV", [var_id])
+        #                                    ]
+        #         global_var = yield [("RD", [_globals, var_name])]
+        #
+        #         if global_var is None:
+        #             raise Exception("Runtime error: global '%s' not found" % (var_name))
+        #
+        #         tmp = global_var
+
+        user_root = self.retrieve_user_root()
+        var_name = tree_ir.StoreLocalInstruction(
+            'var_name',
+            tree_ir.ReadValueInstruction(
+                tree_ir.LiteralInstruction(var_id)))
+
+        global_var = tree_ir.StoreLocalInstruction(
+            'global_var',
+            tree_ir.ReadDictionaryValueInstruction(
+                tree_ir.ReadDictionaryValueInstruction(
+                    user_root.create_load(),
+                    tree_ir.LiteralInstruction('globals')),
+                var_id.create_load()))
+
+        err_block = tree_ir.SelectInstruction(
+            tree_ir.BinaryInstruction(
+                global_var.create_load(),
+                'is',
+                tree_ir.LiteralInstruction(None)),
+            tree_ir.RaiseInstruction(
+                tree_ir.CallInstruction(
+                    tree_ir.LoadLocalInstruction('Exception'),
+                    [tree_ir.BinaryInstruction(
+                        tree_ir.LiteralInstruction("Runtime error: global '%s' not found"),
+                        '%',
+                        var_name.create_load())
+                    ])),
+            tree_ir.EmptyInstruction())
+
+        name = self.get_local_name(var_id)
+        raise primitive_functions.PrimitiveFinished(
+            tree_ir.SelectInstruction(
+                tree_ir.LocalExistsInstruction(name),
+                tree_ir.LoadLocalInstruction(name),
+                tree_ir.CompoundInstruction(
+                    tree_ir.create_block(
+                        user_root,
+                        var_name,
+                        global_var,
+                        err_block),
+                    global_var.create_load())))
+
+    def analyze_declare(self, instruction_id):
+        """Tries to analyze the given 'declare' function."""
+        var_id, = yield [("RD", [instruction_id, "var"])]
+
+        name = self.get_local_name(var_id)
+
+        # The following logic declares a local:
+        #
+        #     if 'local_name' not in locals():
+        #         local_name, = yield [("CN", [])]
+
+        raise primitive_functions.PrimitiveFinished(
+            tree_ir.SelectInstruction(
+                tree_ir.LocalExistsInstruction(name),
+                tree_ir.EmptyInstruction(),
+                tree_ir.StoreLocalInstruction(
+                    name,
+                    tree_ir.CreateNodeInstruction())))
+
+    def analyze_global(self, instruction_id):
+        """Tries to analyze the given 'global' (declaration) function."""
+        var_id, = yield [("RD", [instruction_id, "var"])]
+
+        # To resolve a variable, we'll do something along the
+        # lines of:
+        #
+        #     _globals, var_name = yield [("RD", [user_root, "globals"]),
+        #                                 ("RV", [var_id])
+        #                                ]
+        #     global_var = yield [("RD", [_globals, var_name])]
+        #
+        #     if global_var is None:
+        #         global_var, = yield [("CN", [])]
+        #         yield [("CD", [_globals, var_name, global_var])]
+        #
+        #     tmp = global_var
+
+        user_root = self.retrieve_user_root()
+        var_name = tree_ir.StoreLocalInstruction(
+            'var_name',
+            tree_ir.ReadValueInstruction(
+                tree_ir.LiteralInstruction(var_id)))
+
+        _globals = tree_ir.StoreLocalInstruction(
+            '_globals',
+            tree_ir.ReadDictionaryValueInstruction(
+                user_root.create_load(),
+                tree_ir.LiteralInstruction('globals')))
+
+        global_var = tree_ir.StoreLocalInstruction(
+            'global_var',
+            tree_ir.ReadDictionaryValueInstruction(
+                _globals.create_load(),
+                var_name.create_load()))
+
+        raise primitive_functions.PrimitiveFinished(
+            tree_ir.CompoundInstruction(
+                tree_ir.create_block(
+                    user_root,
+                    var_name,
+                    _globals,
+                    global_var,
+                    tree_ir.SelectInstruction(
+                        tree_ir.BinaryInstruction(
+                            global_var.create_load(),
+                            'is',
+                            tree_ir.LiteralInstruction(None)),
+                        tree_ir.create_block(
+                            global_var.create_store(
+                                tree_ir.CreateNodeInstruction()),
+                            tree_ir.CreateDictionaryEdgeInstruction(
+                                _globals.create_load(),
+                                var_name.create_load(),
+                                global_var.create_load())),
+                        tree_ir.EmptyInstruction())),
+                global_var.create_load())
+        )
+
     instruction_analyzers = {
         'if' : analyze_if,
         'while' : analyze_while,
         'return' : analyze_return,
         'constant' : analyze_constant,
+        'resolve' : analyze_resolve,
+        'declare' : analyze_declare,
+        'global' : analyze_global,
         'output' : analyze_output
     }
 

+ 101 - 3
kernel/modelverse_jit/tree_ir.py

@@ -203,17 +203,98 @@ class ReturnInstruction(VoidInstruction):
 
     def simplify(self):
         """Applies basic simplification to this instruction and its children."""
-
-        return LoopInstruction(self.value.simplify())
+        return ReturnInstruction(self.value.simplify())
 
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
-
+        self.value.generate_python_def(code_generator)
         code_generator.append_line(
             'raise PrimitiveFinished(' +
             self.value.generate_python_use(code_generator) +
             ')')
 
+class RaiseInstruction(VoidInstruction):
+    """An instruction that raises an error."""
+
+    def __init__(self, value):
+        VoidInstruction.__init__(self)
+        self.value = value
+
+    def simplify(self):
+        """Applies basic simplification to this instruction and its children."""
+        return RaiseInstruction(self.value.simplify())
+
+    def generate_python_def(self, code_generator):
+        """Generates Python code for this instruction."""
+        self.value.generate_python_def(code_generator)
+        code_generator.append_line(
+            'raise ' + self.value.generate_python_use(code_generator))
+
+class CallInstruction(Instruction):
+    """An instruction that performs a simple call."""
+    def __init__(self, target, argument_list):
+        Instruction.__init__(self)
+        self.target = target
+        self.argument_list = argument_list
+
+    def simplify(self):
+        """Applies basic simplification to this instruction and its children."""
+        return CallInstruction(
+            self.target.simplify(),
+            [arg.simplify() for arg in self.argument_list])
+
+    def generate_python_def(self, code_generator):
+        """Generates Python code for this instruction."""
+        if self.target.has_definition():
+            self.target.generate_python_def(code_generator)
+
+        for arg in self.argument_list:
+            if arg.has_definition():
+                arg.generate_python_def(code_generator)
+
+        code_generator.append_line(
+            '%s = %s(%s) ' % (
+                code_generator.get_result_name(self),
+                self.target.generate_python_use(code_generator),
+                [arg.generate_python_use(code_generator) for arg in self.argument_list]))
+
+class BinaryInstruction(Instruction):
+    """An instruction that performs a binary operation."""
+    def __init__(self, lhs, operator, rhs):
+        Instruction.__init__(self)
+        self.lhs = lhs
+        self.operator = operator
+        self.rhs = rhs
+
+    def has_definition(self):
+        """Tells if this instruction requires a definition."""
+        return self.lhs.has_definition() or self.rhs.has_definition()
+
+    def simplify(self):
+        """Applies basic simplification to this instruction and its children."""
+        simple_lhs, simple_rhs = self.lhs.simplify(), self.rhs.simplify()
+        return BinaryInstruction(simple_lhs, self.operator, simple_rhs)
+
+    def generate_python_use(self, code_generator):
+        """Generates a Python expression that retrieves this instruction's
+           result. The expression is returned as a string."""
+        return '%s %s %s' % (
+            self.lhs.generate_python_use(code_generator),
+            self.operator,
+            self.rhs.generate_python_use(code_generator))
+
+    def generate_python_def(self, code_generator):
+        """Generates a Python statement that executes this instruction.
+           The statement is appended immediately to the code generator."""
+        if self.lhs.has_definition():
+            self.lhs.generate_python_def(code_generator)
+            if self.rhs.has_definition():
+                self.rhs.generate_python_def(code_generator)
+        elif self.rhs.has_definition():
+            self.rhs.generate_python_def(code_generator)
+        else:
+            code_generator.append_line('pass')
+
 class LoopInstruction(VoidInstruction):
     """Represents a loop-instruction, which loops until broken."""
 
@@ -328,6 +409,11 @@ class LocalInstruction(Instruction):
         """Creates an instruction that loads the variable referenced by this instruction."""
         return LoadLocalInstruction(self.name)
 
+    def create_store(self, value):
+        """Creates an instruction that stores the given value in the variable referenced
+           by this instruction."""
+        return StoreLocalInstruction(self.name, value)
+
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
            result. The expression is returned as a string."""
@@ -374,6 +460,18 @@ class DefineFunctionInstruction(LocalInstruction):
         self.body.generate_python_def(code_generator)
         code_generator.decrease_indentation()
 
+class LocalExistsInstruction(LocalInstruction):
+    """An instruction that checks if a local variable exists."""
+
+    def has_definition(self):
+        """Tells if this instruction requires a definition."""
+        return False
+
+    def generate_python_use(self, code_generator):
+        """Generates a Python expression that retrieves this instruction's
+           result. The expression is returned as a string."""
+        return '%s in locals()' % self.name
+
 class LoadIndexInstruction(Instruction):
     """An instruction that produces a value by indexing a specified expression with
        a given key."""