def test_cont_fusion(): from pycket.env import SymList, ToplevelEnv from pycket.interpreter import ( LetCont, BeginCont, FusedLet0Let0Cont, FusedLet0BeginCont, ) from pycket.config import get_testing_config args = SymList([]) counts = [1] rhss = 1 letast1 = Let(args, counts, [1], [2]) letast2 = Let(args, counts, [1], [2]) env = ToplevelEnv(get_testing_config(**{"pycket.fuse_conts": True})) prev = object() let2 = LetCont.make([], letast2, 0, env, prev) let1 = LetCont.make([], letast1, 0, env, let2) assert isinstance(let1, FusedLet0Let0Cont) assert let1.prev is prev assert let1.env is env let2 = BeginCont(letast2.counting_asts[0], env, prev) let1 = LetCont.make([], letast1, 0, env, let2) assert isinstance(let1, FusedLet0BeginCont) assert let1.prev is prev assert let1.env is env
def visit_let(self, ast): assert isinstance(ast, Let) body = [b.visit(self) for b in ast.body] rhss = [r.visit(self) for r in ast.rhss] result = Let(ast.args, ast.counts, rhss, body, ast.remove_num_envs) result.copy_body_pruning(ast) return result
def visit_let(self, ast, vars, env_structure): assert isinstance(ast, Let) sub_env_structure = SymList(ast.args.elems, env_structure) local_muts = self.body_muts(ast) new_vars = vars.copy() new_vars.update(local_muts) ast, sub_env_structure, env_structures, remove_num_envs = self._compute_remove_num_envs( ast, new_vars, sub_env_structure) new_rhss = [None] * len(ast.rhss) offset = 0 variables = ast.args.elems need_cell_flags = [False] * len(ast.args.elems) for i, rhs in enumerate(ast.rhss): count = ast.counts[i] for j in range(count): var = variables[offset+j] need_cell_flags[offset+j] = LexicalVar(var) in local_muts new_rhss[i] = rhs.visit(self, vars, env_structures[i]) offset += count body_env_structure = env_structures[-1] body_env_structures, body_remove_num_envs = self._visit_sequenced_body( ast, vars, body_env_structure) new_body = [b.visit(self, new_vars, body_env_structures[i]) for i, b in enumerate(ast.body)] result = Let(sub_env_structure, ast.counts, new_rhss, new_body, remove_num_envs) result.init_body_pruning(body_env_structure, body_remove_num_envs) result.init_mutable_var_flags(need_cell_flags) return result
def _compute_remove_num_envs(self, ast, new_vars, sub_env_structure): from pycket import config if not config.prune_env: remove_num_envs = [0] * (len(ast.rhss) + 1) env_structures = [sub_env_structure.prev] * len(ast.rhss) env_structures.append(sub_env_structure) return ast, sub_env_structure, env_structures, remove_num_envs # find out whether a smaller environment is sufficient for the body free_vars_not_from_let = compute_body_frees(ast, self.free_vars_cache) free_vars_not_from_let = free_vars_not_from_let.without_many( ast.args.elems) # at most, we can remove all envs, apart from the one introduced by let curr_remove = max_depth = sub_env_structure.depth_and_size()[0] - 1 max_needed = 0 free_vars_not_mutated = True for v in free_vars_not_from_let: depth = sub_env_structure.depth_of_var(v)[1] - 1 curr_remove = min(curr_remove, depth) max_needed = max(max_needed, depth) free_vars_not_mutated &= LexicalVar(v) not in new_vars if curr_remove == 0: body_env_structure = sub_env_structure else: next_structure = sub_env_structure.prev.drop_frames(curr_remove) body_env_structure = SymList(ast.args.elems, next_structure) if (free_vars_not_mutated and max_needed == curr_remove and max_depth > max_needed): before_max_needed = sub_env_structure.drop_frames(max_needed + 2) if before_max_needed and before_max_needed.depth_and_size()[1] > 0: counts, new_lhs_vars, new_rhss = self._copy_live_vars( ast, free_vars_not_from_let) body_env_structure = SymList(new_lhs_vars) sub_env_structure = SymList(new_lhs_vars, sub_env_structure.prev) ast = Let(body_env_structure, counts, new_rhss, ast.body) return self._compute_remove_num_envs(ast, new_vars, sub_env_structure) # The loops will modify all but the last element remove_num_envs = [curr_remove] * (len(ast.rhss) + 1) env_structures = [body_env_structure] * (len(ast.rhss) + 1) for i in range(len(ast.rhss) - 1, -1, -1): free_vars = ast.rhss[i].free_vars(self.free_vars_cache) for v in free_vars: var_depth = sub_env_structure.prev.depth_of_var(v)[1] curr_remove = min(curr_remove, var_depth) env_structures[i] = sub_env_structure.drop_frames(curr_remove + 1) remove_num_envs[i] = curr_remove return ast, sub_env_structure, env_structures, remove_num_envs
def visit_let(self, ast, vars, env_structure): assert isinstance(ast, Let) sub_env_structure = SymList(ast.args.elems, env_structure) local_muts = self.body_muts(ast) new_vars = vars.copy() new_vars.update(local_muts) ast, sub_env_structure, env_structures, remove_num_envs = self._compute_remove_num_envs( ast, new_vars, sub_env_structure) new_rhss = [None] * len(ast.rhss) offset = 0 variables = ast.args.elems need_cell_flags = [False] * len(ast.args.elems) for i, rhs in enumerate(ast.rhss): count = ast.counts[i] for j in range(count): var = variables[offset + j] need_cell_flags[offset + j] = LexicalVar(var) in local_muts new_rhss[i] = rhs.visit(self, vars, env_structures[i]) offset += count body_env_structure = env_structures[-1] body_env_structures, body_remove_num_envs = self._visit_sequenced_body( ast, vars, body_env_structure) new_body = [ b.visit(self, new_vars, body_env_structures[i]) for i, b in enumerate(ast.body) ] result = Let(sub_env_structure, ast.counts, new_rhss, new_body, remove_num_envs) result.init_body_pruning(body_env_structure, body_remove_num_envs) result.init_mutable_var_flags(need_cell_flags) return result