Example #1
0
    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
Example #2
0
    def visit_letrec(self, ast, vars, env_structure):
        assert isinstance(ast, Letrec)
        local_muts = self.body_muts(ast)
        for b in ast.rhss:
            local_muts.update(b.mutated_vars(self.mutated_vars_cache))
        for v in ast.args.elems:
            lv = LexicalVar(v)
            local_muts[lv] = None
        new_vars = vars.copy()
        new_vars.update(local_muts)
        sub_env_structure = SymList(ast.args.elems, env_structure)
        new_rhss = [
            rhs.visit(self, new_vars, sub_env_structure) for rhs in ast.rhss
        ]

        body_env_structures, body_remove_num_envs = self._visit_sequenced_body(
            ast, new_vars, sub_env_structure)

        new_body = [
            b.visit(self, new_vars, body_env_structures[i])
            for i, b in enumerate(ast.body)
        ]
        letrec = Letrec(sub_env_structure, ast.counts, new_rhss, new_body)
        letrec.init_body_pruning(sub_env_structure, body_remove_num_envs)
        return letrec
Example #3
0
    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
Example #4
0
    def _copy_live_vars(self, ast, free_vars_not_from_let):
        # there is unneeded local env storage that we will never need
        # in the body. thus, make a copy of all local variables into
        # the current let, at the point where the variable is not longer
        # referenced in any of the right-hand-sides.
        vars_to_copy = free_vars_not_from_let

        # Find the last right hand side in which each variable to be
        # copied is referenced
        dead_after_sets = [[] for _ in ast.rhss]
        rhss = ast.rhss
        for var in free_vars_not_from_let:
            i = len(ast.rhss) - 1
            while i != 0 and not rhss[i].free_vars(
                    self.free_vars_cache).haskey(var):
                i -= 1
            dead_after_sets[i].append(var)

        # Build the new args and rhss by interleaving the bindings with
        # the new copy operations
        new_lhs_vars = []
        new_rhss = []
        counts = []
        args = ast._rebuild_args()
        for i, rhs in enumerate(ast.rhss):
            new_lhs_vars.extend(dead_after_sets[i])
            new_lhs_vars.extend(args[i])

            new_rhss.extend([LexicalVar(v) for v in dead_after_sets[i]])
            new_rhss.append(rhs)

            counts.extend([1] * len(dead_after_sets[i]))
            counts.append(ast.counts[i])

        new_lhs_vars = new_lhs_vars[:]
        new_rhss = new_rhss[:]
        counts = counts[:]
        return counts, new_lhs_vars, new_rhss
Example #5
0
    def visit_lambda(self, ast, vars, env_structure):
        assert isinstance(ast, Lambda)
        local_muts = self.body_muts(ast)
        need_cell_flags = [False] * len(ast.args.elems)
        new_vars = vars.copy()
        for i, var in enumerate(ast.args.elems):
            li = LexicalVar(var)
            self.remove_var(new_vars, li)
            need_cell_flags[i] = li in local_muts
        new_vars.update(local_muts)

        sub_env_structure = ast.args
        body_env_structures, body_remove_num_envs = self._visit_sequenced_body(
            ast, new_vars, sub_env_structure)
        new_body = [
            b.visit(self, new_vars, body_env_structures[i])
            for i, b in enumerate(ast.body)
        ]

        result = Lambda(ast.formals, ast.rest, ast.args, ast.frees, new_body,
                        ast.sourceinfo, env_structure, sub_env_structure)
        result.init_body_pruning(sub_env_structure, body_remove_num_envs)
        result.init_mutable_var_flags(need_cell_flags)
        return result
Example #6
0
 def visit_lexical_var(self, ast):
     assert isinstance(ast, LexicalVar)
     return LexicalVar(ast.sym, ast.env_structure)
Example #7
0
 def visit_lexical_var(self, ast, vars, env_structure):
     assert isinstance(ast, LexicalVar)
     if ast in vars:
         return CellRef(ast.sym, env_structure)
     else:
         return LexicalVar(ast.sym, env_structure)