|
@@ -1,9 +1,13 @@
|
|
|
import modelverse_kernel.primitives as primitive_functions
|
|
|
import modelverse_jit.tree_ir as tree_ir
|
|
|
+import modelverse_jit.runtime as jit_runtime
|
|
|
|
|
|
KWARGS_PARAMETER_NAME = "kwargs"
|
|
|
"""The name of the kwargs parameter in jitted functions."""
|
|
|
|
|
|
+INTERPRET_FUNCTION_NAME = "__interpret_function"
|
|
|
+"""The name of the '__interpret_function' function, in the jitted function scope."""
|
|
|
+
|
|
|
def get_parameter_names(compiled_function):
|
|
|
"""Gets the given compiled function's parameter names."""
|
|
|
if hasattr(compiled_function, '__code__'):
|
|
@@ -42,7 +46,8 @@ class ModelverseJit(object):
|
|
|
self.jitted_entry_points = {}
|
|
|
self.jitted_parameters = {}
|
|
|
self.jit_globals = {
|
|
|
- 'PrimitiveFinished' : primitive_functions.PrimitiveFinished
|
|
|
+ 'PrimitiveFinished' : primitive_functions.PrimitiveFinished,
|
|
|
+ INTERPRET_FUNCTION_NAME : jit_runtime.interpret_function
|
|
|
}
|
|
|
self.jit_count = 0
|
|
|
self.max_instructions = max_instructions
|
|
@@ -825,11 +830,40 @@ class AnalysisState(object):
|
|
|
|
|
|
raise primitive_functions.PrimitiveFinished(named_args)
|
|
|
|
|
|
- def analyze_call(self, instruction_id):
|
|
|
- """Tries to analyze the given 'call' instruction."""
|
|
|
- func_id, first_param_id, = yield [("RD", [instruction_id, "func"]),
|
|
|
- ("RD", [instruction_id, "params"])]
|
|
|
+ def analyze_indirect_call(self, func_id, first_arg_id):
|
|
|
+ """Analyzes a call to an unknown function."""
|
|
|
+
|
|
|
+ # First off, let's analyze the callee and the argument list.
|
|
|
+ try:
|
|
|
+ gen = self.analyze(func_id)
|
|
|
+ inp = None
|
|
|
+ while True:
|
|
|
+ inp = yield gen.send(inp)
|
|
|
+ except primitive_functions.PrimitiveFinished as ex:
|
|
|
+ func_val = ex.result
|
|
|
+
|
|
|
+ try:
|
|
|
+ gen = self.analyze_arguments(first_arg_id)
|
|
|
+ inp = None
|
|
|
+ while True:
|
|
|
+ inp = yield gen.send(inp)
|
|
|
+ except primitive_functions.PrimitiveFinished as ex:
|
|
|
+ named_args = ex.result
|
|
|
+
|
|
|
+ # Call the __interpret_function function to run the interpreter, like so:
|
|
|
+ #
|
|
|
+ # __interpret_function(function_id, { first_param_name : first_param_val, ... }, **kwargs)
|
|
|
+ #
|
|
|
+ dict_literal = tree_ir.DictionaryLiteralInstruction(
|
|
|
+ [(tree_ir.LiteralInstruction(key), val) for key, val in named_args])
|
|
|
+ raise primitive_functions.PrimitiveFinished(
|
|
|
+ tree_ir.JitCallInstruction(
|
|
|
+ tree_ir.LoadGlobalInstruction(INTERPRET_FUNCTION_NAME),
|
|
|
+ [('function_id', func_val), ('named_arguments', dict_literal)],
|
|
|
+ tree_ir.LoadLocalInstruction(KWARGS_PARAMETER_NAME)))
|
|
|
|
|
|
+ def try_analyze_direct_call(self, func_id, first_param_id):
|
|
|
+ """Tries to analyze the given 'call' instruction as a direct call."""
|
|
|
# Figure out what the 'func' instruction's type is.
|
|
|
func_instruction_op, = yield [("RV", [func_id])]
|
|
|
if func_instruction_op['value'] == 'access':
|
|
@@ -840,15 +874,12 @@ class AnalysisState(object):
|
|
|
resolved_var_id, = yield [("RD", [access_value_id, "var"])]
|
|
|
resolved_var_name, = yield [("RV", [resolved_var_id])]
|
|
|
|
|
|
- # Try to look the name up as a global.
|
|
|
+ # Try to look up the name as a global.
|
|
|
_globals, = yield [("RD", [self.user_root, "globals"])]
|
|
|
global_var, = yield [("RD", [_globals, resolved_var_name])]
|
|
|
global_val, = yield [("RD", [global_var, "value"])]
|
|
|
|
|
|
- if global_val is None:
|
|
|
- raise JitCompilationFailedException(
|
|
|
- "Cannot JIT function calls that target an unknown value.")
|
|
|
- else:
|
|
|
+ if global_val is not None:
|
|
|
gen = self.analyze_direct_call(
|
|
|
global_val, resolved_var_name, first_param_id)
|
|
|
inp = None
|
|
@@ -856,8 +887,28 @@ class AnalysisState(object):
|
|
|
inp = yield gen.send(inp)
|
|
|
# PrimitiveFinished exception will bubble up from here.
|
|
|
|
|
|
- raise JitCompilationFailedException("Cannot JIT indirect function calls yet.")
|
|
|
+ raise JitCompilationFailedException(
|
|
|
+ "Cannot JIT function calls that target an unknown value as direct calls.")
|
|
|
|
|
|
+ def analyze_call(self, instruction_id):
|
|
|
+ """Tries to analyze the given 'call' instruction."""
|
|
|
+ func_id, first_param_id, = yield [("RD", [instruction_id, "func"]),
|
|
|
+ ("RD", [instruction_id, "params"])]
|
|
|
+
|
|
|
+ try:
|
|
|
+ # Try to analyze the call as a direct call.
|
|
|
+ gen = self.try_analyze_direct_call(func_id, first_param_id)
|
|
|
+ inp = None
|
|
|
+ while 1:
|
|
|
+ inp = yield gen.send(inp)
|
|
|
+ # PrimitiveFinished exception will bubble up from here.
|
|
|
+ except JitCompilationFailedException:
|
|
|
+ # Looks like we'll have to compile it as an indirect call.
|
|
|
+ gen = self.analyze_indirect_call(func_id, first_param_id)
|
|
|
+ inp = None
|
|
|
+ while True:
|
|
|
+ inp = yield gen.send(inp)
|
|
|
+ # PrimitiveFinished exception will bubble up from here.
|
|
|
|
|
|
instruction_analyzers = {
|
|
|
'if' : analyze_if,
|