|
|
@@ -1,10 +1,7 @@
|
|
|
import modelverse_kernel.primitives as primitive_functions
|
|
|
import modelverse_kernel.compiled as compiled_functions
|
|
|
from modelverse_kernel.request_handler import RequestHandler
|
|
|
-import modelverse_jit.jit as jit
|
|
|
-import modelverse_jit.intrinsics as jit_intrinsics
|
|
|
-import modelverse_jit.jit_primitives as jit_primitives
|
|
|
-import modelverse_jit.runtime as jit_runtime
|
|
|
+import modelverse_kernel.jit as jit
|
|
|
from collections import defaultdict
|
|
|
import sys
|
|
|
import time
|
|
|
@@ -15,6 +12,9 @@ else:
|
|
|
string_types = (str, unicode)
|
|
|
|
|
|
class ModelverseKernel(object):
|
|
|
+
|
|
|
+ counter = 0
|
|
|
+
|
|
|
def __init__(self, root):
|
|
|
self.root = root
|
|
|
self.returnvalue = None
|
|
|
@@ -29,76 +29,72 @@ class ModelverseKernel(object):
|
|
|
#
|
|
|
self.request_handlers = {}
|
|
|
self.allow_compiled = True
|
|
|
- #self.allow_compiled = False
|
|
|
-
|
|
|
- # Set `self.suggest_function_names` to True to associate global function names
|
|
|
- # with their function bodies.
|
|
|
- self.suggest_function_names = True
|
|
|
|
|
|
# `self.jit` handles most JIT-related functionality.
|
|
|
self.jit = jit.ModelverseJit()
|
|
|
- if self.allow_compiled:
|
|
|
- self.jit.compiled_function_lookup = lambda func_name: \
|
|
|
- getattr(compiled_functions, func_name, None)
|
|
|
-
|
|
|
- jit_intrinsics.register_intrinsics(self.jit)
|
|
|
-
|
|
|
- # To disable the JIT, uncomment the line below:
|
|
|
- #
|
|
|
- # self.jit.set_jit_enabled(False)
|
|
|
- #
|
|
|
- # To disable direct calls in the JIT, uncomment the line below:
|
|
|
- #
|
|
|
- # self.jit.allow_direct_calls(False)
|
|
|
- #
|
|
|
- # To disable thunks in the JIT, uncomment the line below:
|
|
|
- #
|
|
|
- # self.jit.enable_thunks(False)
|
|
|
- #
|
|
|
- # To make the JIT compile 'input' instructions as calls to
|
|
|
- # modelverse_jit.runtime.get_input, uncomment the line below:
|
|
|
- #
|
|
|
- # self.jit.use_input_function()
|
|
|
- #
|
|
|
- # To disable source maps in the JIT, uncomment the line below:
|
|
|
- #
|
|
|
- # self.jit.enable_source_maps(False)
|
|
|
- #
|
|
|
- # To enable tracing in the JIT (for debugging purposes), uncomment
|
|
|
- # the line below:
|
|
|
- #
|
|
|
- # self.jit.enable_tracing()
|
|
|
- #
|
|
|
- # To make the JIT print JIT successes and errors to the command-line,
|
|
|
- # uncomment the line below:
|
|
|
- #
|
|
|
- # self.jit.set_jit_success_log()
|
|
|
- #
|
|
|
- # If you want, you can use a custom logging function:
|
|
|
- #
|
|
|
- # self.jit.set_jit_success_log(logging_function)
|
|
|
- #
|
|
|
- # To make the JIT print jitted code to the command-line, uncomment the
|
|
|
- # line below:
|
|
|
- #
|
|
|
- # self.jit.set_jit_code_log()
|
|
|
- #
|
|
|
- # If you want, you can use a custom logging function:
|
|
|
- #
|
|
|
- # self.jit.set_jit_code_log(logging_function)
|
|
|
- #
|
|
|
+ self.jit.compiled_function_lookup = lambda func_name : getattr(compiled_functions, func_name, None)
|
|
|
+ self.jit.body_cache = {}
|
|
|
|
|
|
self.debug_info = defaultdict(list)
|
|
|
|
|
|
+ def try_to_protect(self, var):
|
|
|
+ if isinstance(var, dict) and "id" in var and var['id'] is not None:
|
|
|
+ return set([var['id']])
|
|
|
+ elif type(var) == int:
|
|
|
+ return set([var])
|
|
|
+ elif isinstance(var, dict):
|
|
|
+ protect = set()
|
|
|
+ for v in var.values():
|
|
|
+ protect |= self.try_to_protect(v)
|
|
|
+ return protect
|
|
|
+ elif isinstance(var, list):
|
|
|
+ protect = set()
|
|
|
+ for v in var:
|
|
|
+ protect |= self.try_to_protect(v)
|
|
|
+ return protect
|
|
|
+ elif isinstance(var, set):
|
|
|
+ protect = set()
|
|
|
+ for v in var:
|
|
|
+ protect |= self.try_to_protect(v)
|
|
|
+ return protect
|
|
|
+ return set()
|
|
|
+
|
|
|
+ def protect_temporary_variables(self, taskname):
|
|
|
+ generators = []
|
|
|
+ for h in self.request_handlers.values():
|
|
|
+ for handler in h.values():
|
|
|
+ for generator in handler.generator_stack:
|
|
|
+ generators.append(generator)
|
|
|
+
|
|
|
+ to_protect = set()
|
|
|
+ for gen in generators:
|
|
|
+ try:
|
|
|
+ variables = gen.gi_frame.f_locals
|
|
|
+ for var in variables.values():
|
|
|
+ to_protect |= self.try_to_protect(var)
|
|
|
+ except:
|
|
|
+ pass
|
|
|
+
|
|
|
+ # Create the node to which everything is attached
|
|
|
+ self.fixed_node, = yield [("CN", [])]
|
|
|
+ yield [("CE", [self.root, self.fixed_node])]
|
|
|
+ yield [("CE", [self.fixed_node, node]) for node in to_protect]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
+
|
|
|
+ def unprotect_temporary_variables(self, taskname):
|
|
|
+ yield [("DN", [self.fixed_node])]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
+
|
|
|
def execute_yields(self, taskname, operation, params, reply):
|
|
|
self.taskname = taskname
|
|
|
if taskname not in self.request_handlers:
|
|
|
self.request_handlers[taskname] = {}
|
|
|
+ self.jit.cache.setdefault(taskname, {})
|
|
|
if operation not in self.request_handlers[taskname]:
|
|
|
# Create the generator for the function to execute
|
|
|
self.request_handlers[taskname][operation] = RequestHandler()
|
|
|
handler = self.request_handlers[taskname][operation]
|
|
|
- if not handler.is_active():
|
|
|
+ if len(handler.generator_stack) == 0:
|
|
|
handler.push_generator(getattr(self, operation)(taskname, *params))
|
|
|
|
|
|
return handler.handle_request(reply)
|
|
|
@@ -124,15 +120,11 @@ class ModelverseKernel(object):
|
|
|
if self.phase_v == "finish":
|
|
|
gen = self.helper_init(task_root)
|
|
|
elif self.inst is None:
|
|
|
- print("No instruction pointer found...")
|
|
|
- print(locals())
|
|
|
- print("Phase: " + str(self.phase_v))
|
|
|
- print("Debug: " + str(self.debug_info[taskname]))
|
|
|
raise Exception("Instruction pointer could not be found!")
|
|
|
elif isinstance(self.phase_v, string_types):
|
|
|
if self.phase_v == "init" and self.jit.is_jittable_entry_point(self.inst):
|
|
|
#print("%-30s(%s)" % ("COMPILED " + str(self.jit.jitted_entry_points[self.inst]), phase_v))
|
|
|
- gen = self.execute_jit(task_root, self.inst, taskname)
|
|
|
+ gen = self.execute_jit(task_root, self.inst, taskname, store=True, resolve=False)
|
|
|
elif inst_v is None:
|
|
|
raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info[taskname], inst_v, self.phase_v))
|
|
|
else:
|
|
|
@@ -146,15 +138,9 @@ class ModelverseKernel(object):
|
|
|
else:
|
|
|
raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info[taskname], inst_v, self.phase_v))
|
|
|
|
|
|
- def handle_jit_failed(exception):
|
|
|
- # Try again, but this time without the JIT.
|
|
|
- gen = self.get_inst_phase_generator(inst_v, self.phase_v, task_root)
|
|
|
- yield [("TAIL_CALL", [gen])]
|
|
|
-
|
|
|
- yield [("TRY", [])]
|
|
|
- yield [("CATCH", [jit.JitCompilationFailedException, handle_jit_failed])]
|
|
|
yield [("CALL", [gen])]
|
|
|
- yield [("END_TRY", [])]
|
|
|
+
|
|
|
+ yield [("FINISH", [])]
|
|
|
|
|
|
def get_inst_phase_generator(self, inst_v, phase_v, task_root):
|
|
|
"""Gets a generator for the given instruction in the given phase,
|
|
|
@@ -166,10 +152,8 @@ class ModelverseKernel(object):
|
|
|
### Process primitives ###
|
|
|
##########################
|
|
|
def load_primitives(self, taskname):
|
|
|
- yield [("CALL_ARGS",
|
|
|
- [self.load_primitives_from, (taskname, 'primitives', primitive_functions)])]
|
|
|
- yield [("CALL_ARGS",
|
|
|
- [self.load_primitives_from, (taskname, 'jit', jit_primitives)])]
|
|
|
+ yield [("CALL_ARGS", [self.load_primitives_from, (taskname, 'primitives', primitive_functions)])]
|
|
|
+ yield [("FINISH", [])]
|
|
|
|
|
|
def load_primitives_from(self, taskname, source_name, source):
|
|
|
hierarchy, = yield [("RD", [self.root, "__hierarchy"])]
|
|
|
@@ -179,66 +163,339 @@ class ModelverseKernel(object):
|
|
|
signatures = yield [("RDN", [primitives, f]) for f in keys]
|
|
|
bodies = yield [("RD", [f, "body"]) for f in signatures]
|
|
|
for i in range(len(keys)):
|
|
|
- self.jit.register_compiled(
|
|
|
- bodies[i],
|
|
|
- getattr(source, function_names[i]),
|
|
|
- function_names[i])
|
|
|
-
|
|
|
- def jit_compile(self, task_root, inst):
|
|
|
- # Try to retrieve the suggested name.
|
|
|
- suggested_name = self.jit.get_global_name(inst)
|
|
|
- # Have the JIT compile the function.
|
|
|
- return self.jit.jit_compile(task_root, inst, suggested_name)
|
|
|
+ self.jit.register_compiled(bodies[i], getattr(source, function_names[i]), function_names[i])
|
|
|
+ yield [("RETURN", [None])]
|
|
|
+
|
|
|
+ def print_instruction(self, inst, indent, nested_indent=None):
|
|
|
+ """
|
|
|
+ intrinsics = {"integer_addition": (lambda x, y: "(%s + %s)" % (x, y)),
|
|
|
+ "string_join": (lambda x, y: "(str(%s) + str(%s))" % (x, y)),
|
|
|
+ }
|
|
|
+ """
|
|
|
+ intrinsics = {}
|
|
|
+
|
|
|
+ if nested_indent is None:
|
|
|
+ nested_indent = indent
|
|
|
+
|
|
|
+ inst_type, = yield [("RV", [inst])]
|
|
|
+ instruction = "(no_printer_for_%s)" % inst_type["value"]
|
|
|
+ prev = ""
|
|
|
+
|
|
|
+ if inst_type["value"] == "if":
|
|
|
+ cond, true, false = yield [("RD", [inst, "cond"]),
|
|
|
+ ("RD", [inst, "then"]),
|
|
|
+ ("RD", [inst, "else"])]
|
|
|
+ (prev_cond, instruction_cond), = yield [("CALL_ARGS", [self.print_instruction, (cond, 0, indent)])]
|
|
|
+ (prev_true, instruction_true), = yield [("CALL_ARGS", [self.print_instruction, (true, indent+1)])]
|
|
|
+ if false:
|
|
|
+ (prev_false, instruction_false), = yield [("CALL_ARGS", [self.print_instruction, (false, indent+1)])]
|
|
|
+ false = (" " * indent + "else:\n%s%s") % (prev_false, instruction_false)
|
|
|
+ else:
|
|
|
+ false = ""
|
|
|
+
|
|
|
+ instruction = prev_cond + \
|
|
|
+ " " * indent + "if 'value' not in %s:\n" % instruction_cond + \
|
|
|
+ " " * (indent + 1) + "%s['value'], = yield [('RV', [%s['id']])]\n" % (instruction_cond, instruction_cond) + \
|
|
|
+ " " * indent + "if (%s['value']):\n" % instruction_cond + \
|
|
|
+ prev_true + \
|
|
|
+ instruction_true + \
|
|
|
+ false
|
|
|
+
|
|
|
+ elif inst_type["value"] == "constant":
|
|
|
+ node, = yield [("RD", [inst, "node"])]
|
|
|
+ node_value, = yield [("RV", [node])]
|
|
|
+ if node_value is not None:
|
|
|
+ # There is a value to the node, so replicate the value
|
|
|
+ if isinstance(node_value, string_types):
|
|
|
+ value = '"%s"' % node_value.replace('"', '\\"').replace("'", "\\'").replace('\t', '\\t').replace('\n', '\\n')
|
|
|
+ else:
|
|
|
+ value = str(node_value)
|
|
|
+ instruction = "constant_" + str(ModelverseKernel.counter)
|
|
|
+ ModelverseKernel.counter += 1
|
|
|
+ prev = " " * nested_indent + instruction + " = {'value': " + value + "}\n"
|
|
|
+ else:
|
|
|
+ # Node is None, meaning that it was not about the value, but the node itself...
|
|
|
+ instruction = "{'id': %s}" % str(node)
|
|
|
+
|
|
|
+ elif inst_type["value"] == "return":
|
|
|
+ value, = yield [("RD", [inst, "value"])]
|
|
|
+ if value:
|
|
|
+ (prev_value, instruction_value), = yield [("CALL_ARGS", [self.print_instruction, (value, 0, indent)])]
|
|
|
+ instruction = prev_value + " " * indent + "yield [('RETURN', [%s])]\n" % instruction_value
|
|
|
+ else:
|
|
|
+ instruction = " " * indent + "yield [('RETURN', [None])]\n"
|
|
|
+
|
|
|
+ elif inst_type["value"] == "declare":
|
|
|
+ instruction = ""
|
|
|
+
|
|
|
+ elif inst_type["value"] == "global":
|
|
|
+ instruction = ""
|
|
|
+
|
|
|
+ elif inst_type["value"] == "break":
|
|
|
+ instruction = " " * indent + "break\n"
|
|
|
+
|
|
|
+ elif inst_type["value"] == "continue":
|
|
|
+ instruction = " " * indent + "continue\n"
|
|
|
+
|
|
|
+ elif inst_type["value"] == "input":
|
|
|
+ prev = " " * nested_indent + "_inputs, = yield [('RD', [_root, 'input'])]\n" + \
|
|
|
+ " " * nested_indent + "val, val_e, nxt = yield [('RD', [_inputs, 'value']), ('RDE', [_inputs, 'value']), ('RD', [_inputs, 'next'])]\n" + \
|
|
|
+ " " * nested_indent + "_, val_e = yield [('DE', [val_e]), ('RDE', [_root, 'input'])]\n" + \
|
|
|
+ " " * nested_indent + "yield [('CD', [_root, 'input', nxt]), ('DE', [val_e])]\n" + \
|
|
|
+ " " * nested_indent + "_result = {'id': val}\n"
|
|
|
+
|
|
|
+ instruction = "_result"
|
|
|
+
|
|
|
+ elif inst_type["value"] == "output":
|
|
|
+ value, = yield [("RD", [inst, "value"])]
|
|
|
+ (prev, instruction), = yield [("CALL_ARGS", [self.print_instruction, (value, 0, indent)])]
|
|
|
+ instruction = prev + \
|
|
|
+ " " * indent + "if 'id' not in %s:\n" % instruction + \
|
|
|
+ " " * (indent + 1) + "%s['id'], = yield [('CNV', [%s['value']])]\n" % (instruction, instruction) + \
|
|
|
+ " " * indent + "_outputs, _outputs_e = yield [('RD', [_root, 'last_output']), ('RDE', [_root, 'last_output'])]\n" + \
|
|
|
+ " " * indent + "_, _new = yield [('CD', [_outputs, 'value', %s['id']]), ('CN', [])]\n" % instruction + \
|
|
|
+ " " * indent + "yield [('CD', [_outputs, 'next', _new]), ('DE', [_outputs_e]), ('CD', [_root, 'last_output', _new])]\n"
|
|
|
+
|
|
|
+ elif inst_type["value"] == "resolve":
|
|
|
+ value, = yield [("RD", [inst, "var"])]
|
|
|
+ str_value, = yield [("RV", [value])]
|
|
|
+ if str_value:
|
|
|
+ # Is a global
|
|
|
+ prev = \
|
|
|
+ " " * nested_indent + "%s = _mvk.jit.cache[_taskname].get('%s', None)\n" % (str_value, str_value) + \
|
|
|
+ " " * nested_indent + "if %s is None:\n" % str_value + \
|
|
|
+ " " * (nested_indent + 1) + "%s, = yield [('RD', [_globs, '%s'])]\n" % (str_value, str_value) + \
|
|
|
+ " " * (nested_indent + 1) + "%s, = yield [('RD', [%s, 'value'])]\n" % (str_value, str_value) + \
|
|
|
+ " " * (nested_indent + 1) + "%s = {'id': %s}\n" % (str_value, str_value) + \
|
|
|
+ " " * (nested_indent + 1) + "_mvk.jit.cache[_taskname]['%s'] = %s\n" % (str_value, str_value)
|
|
|
+ instruction = str_value
|
|
|
+
|
|
|
+ if self.jit.get_global_body_id(str_value) is None:
|
|
|
+ val, = yield [("RD", [self.root, self.taskname])]
|
|
|
+ val, = yield [("RD", [val, 'globals'])]
|
|
|
+ val, = yield [("RD", [val, str_value])]
|
|
|
+ val, = yield [("RD", [val, 'value'])]
|
|
|
+ val, = yield [("RD", [val, 'body'])]
|
|
|
+
|
|
|
+ self.jit.register_global(val, str_value)
|
|
|
+ else:
|
|
|
+ # Is a local
|
|
|
+ instruction = "var_%s" % value
|
|
|
+
|
|
|
+ elif inst_type["value"] == "assign":
|
|
|
+ var, val = yield [("RD", [inst, "var"]),
|
|
|
+ ("RD", [inst, "value"])]
|
|
|
+ (prev_var, instruction_var), = yield [("CALL_ARGS", [self.print_instruction, (var, 0, indent)])]
|
|
|
+ (prev_val, instruction_val), = yield [("CALL_ARGS", [self.print_instruction, (val, 0, indent)])]
|
|
|
+
|
|
|
+ instruction = prev_val + " " * indent + instruction_var + " = " + instruction_val + "\n"
|
|
|
+
|
|
|
+ if prev_var:
|
|
|
+ # Got something to do before the variable is usable, so this is a global!
|
|
|
+ # Therefore we actually do the operation in the Modelverse as well!
|
|
|
+ instruction += \
|
|
|
+ " " * nested_indent + "_var, = yield [('RD', [_globs, '%s'])]\n" % instruction_var + \
|
|
|
+ " " * nested_indent + "if _var is None:\n" + \
|
|
|
+ " " * (nested_indent + 1) + "_var, = yield [('CN', [])]\n" + \
|
|
|
+ " " * (nested_indent + 1) + "yield [('CD', [_globs, '%s', _var])]\n" % instruction_var + \
|
|
|
+ " " * nested_indent + "_old_edge, = yield [('RDE', [_var, 'value'])]\n" + \
|
|
|
+ " " * nested_indent + "if 'id' not in %s:\n" % instruction_var + \
|
|
|
+ " " * (nested_indent + 1) + "%s['id'], = yield [('CNV', [%s['value']])]\n" % (instruction_var, instruction_var) + \
|
|
|
+ " " * nested_indent + "yield [('CD', [_var, 'value', %s['id']]), ('DE', [_old_edge])]\n" % instruction_var + \
|
|
|
+ " " * nested_indent + "_mvk.jit.cache[_taskname]['%s'] = %s\n" % (instruction_var, instruction_var)
|
|
|
+
|
|
|
+ elif inst_type["value"] == "call":
|
|
|
+ func_name, = yield [("RD", [inst, "func"])]
|
|
|
+ (prev_func_name, func_name), = yield [("CALL_ARGS", [self.print_instruction, (func_name, nested_indent, nested_indent)])]
|
|
|
+ param_list = {}
|
|
|
+
|
|
|
+ param, = yield [("RD", [inst, "params"])]
|
|
|
+ computation = ""
|
|
|
+ while param:
|
|
|
+ value, name = yield [("RD", [param, "value"]), ("RD", [param, "name"])]
|
|
|
+ name, = yield [("RV", [name])]
|
|
|
+ (prev_res, instruction_res), = yield [("CALL_ARGS", [self.print_instruction, (value, 0, nested_indent)])]
|
|
|
+ param, = yield [("RD", [param, "next_param"])]
|
|
|
+ computation += prev_res
|
|
|
+ param_list[name] = instruction_res
|
|
|
+
|
|
|
+ value = "func_result_" + str(ModelverseKernel.counter)
|
|
|
+ ModelverseKernel.counter += 1
|
|
|
+
|
|
|
+ param_list = "{" + ", ".join(["'%s': %s" % (k, v) for k, v in param_list.items()]) + "}"
|
|
|
+ actual_computation = "$$INDENT$$%s, = yield [('CALL_ARGS', [_mvk.execute_jit, (_root, %s['id'], _taskname, %s)])]\n" % (value, func_name, param_list)
|
|
|
+
|
|
|
+ if indent == 0:
|
|
|
+ # No indent, meaning that we use it inline
|
|
|
+ # Therefore, we output the prev and value individually
|
|
|
+ prev, instruction = prev_func_name + computation + actual_computation.replace("$$INDENT$$", " " * nested_indent), value
|
|
|
+ else:
|
|
|
+ # Some indentation, meaning that we don't even use the return value
|
|
|
+ # Therefore, we only do the yield
|
|
|
+ prev, instruction = prev_func_name + computation, actual_computation.replace("$$INDENT$$", " " * indent)
|
|
|
+
|
|
|
+ elif inst_type["value"] == "access":
|
|
|
+ value, = yield [("RD", [inst, "var"])]
|
|
|
+ (prev, instruction), = yield [("CALL_ARGS", [self.print_instruction, (value, 0, nested_indent)])]
|
|
|
+
|
|
|
+ elif inst_type["value"] == "while":
|
|
|
+ cond, body = yield [("RD", [inst, "cond"]),
|
|
|
+ ("RD", [inst, "body"])]
|
|
|
+ (prev_cond, instruction_cond), = yield [("CALL_ARGS", [self.print_instruction, (cond, 0, indent+1)])]
|
|
|
+ (prev_body, instruction_body), = yield [("CALL_ARGS", [self.print_instruction, (body, indent+1)])]
|
|
|
+ instruction = " " * indent + "__counter_%s = 0\n" % inst + \
|
|
|
+ " " * indent + "while 1:\n" + prev_cond + \
|
|
|
+ " " * (indent + 1) + "if 'value' not in %s:\n" % instruction_cond + \
|
|
|
+ " " * (indent + 2) + "%s['value'], = yield [('RV', [%s['id']])]\n" % (instruction_cond, instruction_cond) + \
|
|
|
+ " " * (indent + 1) + "if not (%s['value']):\n" % instruction_cond + \
|
|
|
+ " " * (indent + 2) + "break\n" + \
|
|
|
+ " " * (indent + 1) + "else:\n" + \
|
|
|
+ " " * (indent + 2) + "__counter_%s += 1\n" % inst + \
|
|
|
+ " " * (indent + 2) + "if __counter_%s > 20:\n" % inst + \
|
|
|
+ " " * (indent + 3) + "yield None\n" + \
|
|
|
+ " " * (indent + 3) + "__counter_%s = 0\n" % inst + \
|
|
|
+ prev_body + instruction_body
|
|
|
+
|
|
|
+
|
|
|
+ next_inst, = yield [("RD", [inst, "next"])]
|
|
|
+ if next_inst:
|
|
|
+ (prev_next, inst_next), = yield [("CALL_ARGS", [self.print_instruction, (next_inst, indent)])]
|
|
|
+ next_inst = prev_next + inst_next
|
|
|
+ else:
|
|
|
+ next_inst = ""
|
|
|
+
|
|
|
+ yield [('RETURN', [(prev, instruction + next_inst)])]
|
|
|
+
|
|
|
+ def read_function(self, inst, suggested_name):
|
|
|
+ initial_instruction = inst
|
|
|
+
|
|
|
+ (params, _, is_mutable), = yield [("CALL_ARGS", [self.jit.jit_signature, (inst,)])]
|
|
|
+ if is_mutable:
|
|
|
+ print("Ignoring mutable or unreadable: %s" % suggested_name)
|
|
|
+ raise jit.JitCompilationFailedException("FAIL")
|
|
|
+
|
|
|
+ #print("Reading function: %s" % suggested_name)
|
|
|
+ (prev, printed), = yield [("CALL_ARGS", [self.print_instruction, (inst, 1)])]
|
|
|
+ preamble = " _mvk = kwargs['mvk']\n" + \
|
|
|
+ " _root = kwargs['task_root']\n" + \
|
|
|
+ " _taskname = kwargs['taskname']\n" + \
|
|
|
+ " _globs = _mvk.jit.cache[_taskname].get('_globs', None)\n" + \
|
|
|
+ " if _globs is None:\n" + \
|
|
|
+ " _globs, = yield [('RD', [kwargs['task_root'], 'globals'])]\n" + \
|
|
|
+ " _mvk.jit.cache[_taskname]['_globs'] = _globs\n"
|
|
|
+ printed = preamble + prev + printed
|
|
|
+ #print("Total printed function: ")
|
|
|
+ if params:
|
|
|
+ func = "def " + suggested_name + "(" + ", ".join([chr(ord('a') + i) for i in range(len(params))]) + ", **kwargs):\n" + "".join([" var_%s = %s\n" % (param, chr(ord('a') + i)) for i, param in enumerate(params)]) + printed
|
|
|
+ else:
|
|
|
+ func = "def " + suggested_name + "(**kwargs):\n" + printed
|
|
|
+
|
|
|
+ #print(func)
|
|
|
|
|
|
- def execute_jit(self, task_root, inst, taskname):
|
|
|
- # execute_jit
|
|
|
- task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
- symbols, = yield [("RD", [task_frame, "symbols"])]
|
|
|
- dict_keys_ref, = yield [("RDK", [symbols])]
|
|
|
- dict_keys_ref_n = yield [("RD", [i, "name"]) for i in dict_keys_ref]
|
|
|
- dict_keys = yield [("RV", [i]) for i in dict_keys_ref_n]
|
|
|
- dict_values_elem = yield [("RDN", [symbols, i]) for i in dict_keys_ref]
|
|
|
- dict_values = yield [("RD", [i, "value"]) for i in dict_values_elem]
|
|
|
+ # To write out all generated functions
|
|
|
+ #with open('/tmp/junk/%s' % suggested_name, 'w') as f:
|
|
|
+ # f.write(func)
|
|
|
|
|
|
- parameters = dict(list(zip(dict_keys, dict_values)))
|
|
|
+ yield [("RETURN", [func])]
|
|
|
|
|
|
- parameters["root"] = self.root
|
|
|
- parameters["task_root"] = task_root
|
|
|
- parameters["taskname"] = taskname
|
|
|
- parameters["mvk"] = self
|
|
|
+ def execute_jit(self, task_root, inst, taskname, params = {}, store=False, resolve=True):
|
|
|
+ # execute_jit
|
|
|
+ if resolve:
|
|
|
+ try:
|
|
|
+ inst = self.jit.body_cache[inst]
|
|
|
+ except KeyError:
|
|
|
+ body, = yield [("RD", [inst, "body"])]
|
|
|
+ self.jit.body_cache[inst] = body
|
|
|
+ inst = body
|
|
|
+
|
|
|
+ if store:
|
|
|
+ task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
+ symbols, = yield [("RD", [task_frame, "symbols"])]
|
|
|
+ dict_keys_ref, = yield [("RDK", [symbols])]
|
|
|
+ if dict_keys_ref:
|
|
|
+ dict_keys_ref_n = yield [("RD", [i, "name"]) for i in dict_keys_ref]
|
|
|
+ dict_keys = yield [("RV", [i]) for i in dict_keys_ref_n]
|
|
|
+ dict_values_elem = yield [("RDN", [symbols, i]) for i in dict_keys_ref]
|
|
|
+ dict_values = yield [("RD", [i, "value"]) for i in dict_values_elem]
|
|
|
+
|
|
|
+ parameters = dict(zip(dict_keys, dict_values))
|
|
|
+ parameters.update(params)
|
|
|
+
|
|
|
+ for p in parameters.keys():
|
|
|
+ if not isinstance(parameters[p], dict):
|
|
|
+ parameters[p] = {'id': parameters[p]}
|
|
|
+ params = parameters
|
|
|
+
|
|
|
+ params["root"] = self.root
|
|
|
+ params["task_root"] = task_root
|
|
|
+ params["taskname"] = taskname
|
|
|
+ params["mvk"] = self
|
|
|
|
|
|
# Have the JIT compile the function.
|
|
|
- compiled_func, = yield [("CALL_ARGS", [self.jit_compile, (task_root, inst)])]
|
|
|
+ if inst is None:
|
|
|
+ suggested_name = self.jit.get_global_name(inst)
|
|
|
+ if suggested_name is None:
|
|
|
+ suggested_name = "func_%s" % str(inst)
|
|
|
+ raise ValueError('body_id cannot be None: ' + str(suggested_name))
|
|
|
+
|
|
|
+ elif inst in self.jit.jitted_entry_points:
|
|
|
+ compiled_func = self.jit.jit_globals[self.jit.jitted_entry_points[inst]]
|
|
|
+ else:
|
|
|
+ compiled_func = self.jit.lookup_compiled_body(inst)
|
|
|
+
|
|
|
+ if compiled_func is None:
|
|
|
+ suggested_name = self.jit.get_global_name(inst)
|
|
|
+ if suggested_name is None:
|
|
|
+ suggested_name = "func_%s" % str(inst)
|
|
|
+ compiled_func, = yield [("CALL_ARGS", [self.read_function, (inst, suggested_name)])]
|
|
|
+ compiled_func = self.merge_function(compiled_func, suggested_name)
|
|
|
+ self.jit.register_compiled(inst, compiled_func, suggested_name)
|
|
|
+
|
|
|
# Run the compiled function.
|
|
|
- results = yield [("CALL_KWARGS", [compiled_func, parameters])]
|
|
|
+ results = yield [("CALL_KWARGS", [compiled_func, params])]
|
|
|
if results is None:
|
|
|
- raise Exception(
|
|
|
- "%s: primitive finished without returning a value!" % (self.debug_info[taskname]))
|
|
|
+ raise Exception("%s: primitive finished without returning a value!" % (self.debug_info[taskname]))
|
|
|
else:
|
|
|
result, = results
|
|
|
|
|
|
- # Clean up the current stack, as if a return happened
|
|
|
- old_frame, exception_return = yield [
|
|
|
- ("RD", [task_frame, "prev"]),
|
|
|
- ("RD", [task_frame, primitive_functions.EXCEPTION_RETURN_KEY])]
|
|
|
+ #print("Got result: " + str(result))
|
|
|
+ if result is None:
|
|
|
+ result = {'id': None, 'value': None}
|
|
|
|
|
|
- if self.debug_info[self.taskname]:
|
|
|
- self.debug_info[self.taskname].pop()
|
|
|
+ if store:
|
|
|
+ # Clean up the current stack, as if a return happened
|
|
|
+ old_frame, exception_return = yield [
|
|
|
+ ("RD", [task_frame, "prev"]),
|
|
|
+ ("RD", [task_frame, primitive_functions.EXCEPTION_RETURN_KEY])]
|
|
|
+
|
|
|
+ #if self.debug_info[self.taskname]:
|
|
|
+ # self.debug_info[self.taskname].pop()
|
|
|
+
|
|
|
+ if "id" not in result:
|
|
|
+ result['id'], = yield [("CNV", [result['value']])]
|
|
|
+
|
|
|
+ if exception_return is not None:
|
|
|
+ # The caller has requested that we throw an exception instead of injecting
|
|
|
+ # the return value into the caller's frame. Read the comment at
|
|
|
+ # primitive_functions.EXCEPTION_RETURN_KEY for the rationale behind this design.
|
|
|
+ yield [("CD", [task_root, "frame", old_frame]),
|
|
|
+ ("DN", [task_frame])]
|
|
|
+ raise primitive_functions.InterpretedFunctionFinished(result)
|
|
|
+ else:
|
|
|
+ lnk, = yield [("RDE", [old_frame, "returnvalue"])]
|
|
|
+ _, _, _, _ = yield [("CD", [old_frame, "returnvalue", result['id']]),
|
|
|
+ ("CD", [task_root, "frame", old_frame]),
|
|
|
+ ("DE", [lnk]),
|
|
|
+ ("DN", [task_frame]),
|
|
|
+ ]
|
|
|
|
|
|
- if exception_return is not None:
|
|
|
- # The caller has requested that we throw an exception instead of injecting
|
|
|
- # the return value into the caller's frame. Read the comment at
|
|
|
- # primitive_functions.EXCEPTION_RETURN_KEY for the rationale behind this design.
|
|
|
- yield [("CD", [task_root, "frame", old_frame]),
|
|
|
- ("DN", [task_frame])]
|
|
|
- raise primitive_functions.InterpretedFunctionFinished(result)
|
|
|
else:
|
|
|
- lnk, = yield [("RDE", [old_frame, "returnvalue"])]
|
|
|
- _, _, _, _ = yield [("CD", [old_frame, "returnvalue", result]),
|
|
|
- ("CD", [task_root, "frame", old_frame]),
|
|
|
- ("DE", [lnk]),
|
|
|
- ("DN", [task_frame]),
|
|
|
- ]
|
|
|
+ yield [("RETURN", [result])]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
+
|
|
|
+ def merge_function(self, func, name):
|
|
|
+ exec(func, self.jit.jit_globals)
|
|
|
+ return self.jit.jit_globals[name]
|
|
|
|
|
|
########################################
|
|
|
### Execute input and output methods ###
|
|
|
@@ -261,6 +518,8 @@ class ModelverseKernel(object):
|
|
|
|
|
|
self.returnvalue = rv_value
|
|
|
self.success = True
|
|
|
+ #print("OUTPUT: (%s, %s)" % (taskname, self.returnvalue))
|
|
|
+ yield [("FINISH", [])]
|
|
|
|
|
|
def set_input(self, taskname, value):
|
|
|
task_root, = yield [("RD", [self.root, taskname])]
|
|
|
@@ -275,7 +534,9 @@ class ModelverseKernel(object):
|
|
|
("CD", [old_input, "value", new_value]),
|
|
|
("DE", [link])
|
|
|
]
|
|
|
+ #print("INPUT: (%s, %s)" % (taskname, value))
|
|
|
self.returnvalue = {"id": 100, "value": "success"}
|
|
|
+ yield [("FINISH", [])]
|
|
|
|
|
|
#############################################
|
|
|
### Transformation rules for instructions ###
|
|
|
@@ -323,6 +584,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [old_phase_link]),
|
|
|
("DE", [old_evalstack_phase_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def break_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -366,6 +628,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [old_phase_link]),
|
|
|
("DE", [old_evalstack_phase_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def if_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -390,6 +653,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [evalstack_link]),
|
|
|
("DE", [ip_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def if_cond(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -452,6 +716,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [ip_link]),
|
|
|
("DE", [phase_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def while_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -475,6 +740,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [evalstack_link]),
|
|
|
("DE", [ip_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def while_cond(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -519,6 +785,7 @@ class ModelverseKernel(object):
|
|
|
_, _ = yield [("CD", [task_frame, "phase", new_phase]),
|
|
|
("DE", [phase_link])
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def access_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -542,6 +809,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [evalstack_link]),
|
|
|
("DE", [ip_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def access_eval(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -558,6 +826,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [phase_link]),
|
|
|
("DE", [returnvalue_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def resolve_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -587,7 +856,7 @@ class ModelverseKernel(object):
|
|
|
print("Globals: " + str(globs))
|
|
|
globs = yield [("RV", [i]) for i in globs]
|
|
|
print("Resolved globals: " + str(globs))
|
|
|
- raise Exception(jit_runtime.GLOBAL_NOT_FOUND_MESSAGE_FORMAT % var_name)
|
|
|
+ raise Exception(jit.GLOBAL_NOT_FOUND_MESSAGE_FORMAT % var_name)
|
|
|
|
|
|
# Resolved a global, so this is a string
|
|
|
# Potentially, this might even be a function that we have precompiled already!
|
|
|
@@ -604,7 +873,7 @@ class ModelverseKernel(object):
|
|
|
|
|
|
# If we're dealing with a function, then we might want to figure out what its body id
|
|
|
# is now so we can suggest a name to the JIT later.
|
|
|
- if self.suggest_function_names and self.jit.get_global_body_id(var_name) is None:
|
|
|
+ if self.jit.get_global_body_id(var_name) is None:
|
|
|
compiler_val, = yield [("RD", [variable, "value"])]
|
|
|
if compiler_val is not None:
|
|
|
compiler_body, = yield [("RD", [compiler_val, "body"])]
|
|
|
@@ -622,6 +891,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [phase_link]),
|
|
|
("DE", [returnvalue_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def assign_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -645,6 +915,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [evalstack_link]),
|
|
|
("DE", [ip_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def assign_value(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -675,6 +946,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [phase_link]),
|
|
|
("DE", [ip_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def assign_assign(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -694,6 +966,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [value_link]),
|
|
|
("DE", [phase_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def return_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -736,6 +1009,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [evalstack_link]),
|
|
|
("DE", [ip_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def return_eval(self, task_root):
|
|
|
if self.debug_info[self.taskname]:
|
|
|
@@ -765,6 +1039,7 @@ class ModelverseKernel(object):
|
|
|
("CD", [prev_frame, "returnvalue", returnvalue]),
|
|
|
("DE", [old_returnvalue_link]),
|
|
|
("DN", [task_frame])]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def constant_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -781,6 +1056,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [returnvalue_link]),
|
|
|
("DE", [phase_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def helper_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -821,6 +1097,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [ip_link]),
|
|
|
("DE", [phase_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def call_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -860,6 +1137,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [evalstack_link]),
|
|
|
("DE", [ip_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def call_call(self, task_root):
|
|
|
self.debug_info[self.taskname].append("None")
|
|
|
@@ -933,6 +1211,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [frame_link]),
|
|
|
("DE", [phase_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def find_overlapping(self, a, b):
|
|
|
newer_frames = set(a)
|
|
|
@@ -1071,6 +1350,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [ip_link]),
|
|
|
("DE", [evalstack_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def input_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -1103,6 +1383,7 @@ class ModelverseKernel(object):
|
|
|
self.input_value = None
|
|
|
ex = primitive_functions.SleepKernel(0.1, True)
|
|
|
raise ex
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def output_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -1126,6 +1407,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [evalstack_link]),
|
|
|
("DE", [ip_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def output_output(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -1146,6 +1428,7 @@ class ModelverseKernel(object):
|
|
|
("DE", [last_output_link]),
|
|
|
("DE", [phase_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def declare_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -1166,6 +1449,7 @@ class ModelverseKernel(object):
|
|
|
_, _ = yield [("CD", [task_frame, "phase", new_phase]),
|
|
|
("DE", [phase_link]),
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|
|
|
|
|
|
def global_init(self, task_root):
|
|
|
task_frame, = yield [("RD", [task_root, "frame"])]
|
|
|
@@ -1189,3 +1473,4 @@ class ModelverseKernel(object):
|
|
|
_, _ = yield [("CD", [task_frame, "phase", new_phase]),
|
|
|
("DE", [phase_link])
|
|
|
]
|
|
|
+ yield [("RETURN", [None])]
|