STATEMENT *make_assignment(EXPRESSION *n, EXPRESSION *v, int source_line) { NODE *node = create_ast_node(STMT_ASSIGN, source_line); tree_add_child(node, n); tree_add_child(node, v); return CAST_TO_STATEMENT(node); }
TYPE *make_map_type(TYPE *t1, TYPE *t2, int source_line) { TYPE *type = create_ast_node(TYPE_MAP, source_line); tree_add_child(type, t1); tree_add_child(type, t2); return type; }
EXPRESSION *make_binary_expression(NODE_TYPE type, EXPRESSION *a, EXPRESSION *b, int source_line) { EXPRESSION *expr = create_ast_node(type, source_line); tree_add_child(expr, a); tree_add_child(expr, b); expr->type = a->type; return expr; }
STATEMENT *make_for(STATEMENT *init, EXPRESSION *c, STATEMENT *step, STATEMENT *body, int source_line) { NODE *node = create_ast_node(STMT_FOR, source_line); tree_add_child(node, init); tree_add_child(node, c); tree_add_child(node, step); tree_add_child(node, body); return CAST_TO_STATEMENT(node); }
EXPRESSION *make_call(EXPRESSION *var, EXPRESSION *args, int source_line) { EXPRESSION *expr = create_ast_node(EXPR_CALL, source_line); tree_add_child(expr, var); tree_add_child(expr, args); expr->type = tree_get_child(var->type, 1); return expr; }
STATEMENT *make_while(EXPRESSION *c, STATEMENT *s1, int source_line) { if (source_line == 0 && c) source_line = CAST_TO_AST(c)->source_line; NODE *node = create_ast_node(STMT_WHILE, source_line); tree_add_child(node, c); tree_add_child(node, make_block(NULL, s1, 0)); return CAST_TO_STATEMENT(node); }
FUNCTION *make_function(TYPE *type, char *name, DECLARATION *args, int source_line) { FUNCTION *func = create_ast_node(DEF_FUNCTION, source_line); DECLARATION *decl = CAST_TO_DECLARATION(func); decl->name = name; decl->type = make_map_type(args->type, type, source_line); decl->flags |= DECL_STATIC; tree_add_child(func, NULL); tree_add_child(func, args); return func; }
STATEMENT *make_statements(STATEMENT *s1, STATEMENT *s2, int source_line) { NODE *node; if (tree_is_type(s1, STMT_SEQUENCE)) node = CAST_TO_NODE(s1); else { node = create_ast_node(STMT_SEQUENCE, source_line); tree_add_child(node, s1); } tree_add_child(node, s2); return CAST_TO_STATEMENT(node); }
TYPE *make_tuple_type(TYPE *t1, TYPE *t2, int source_line) { NODE *node; if (tree_is_type(t1, TYPE_TUPLE)) node = CAST_TO_NODE(t1); else { node = create_ast_node(TYPE_TUPLE, source_line); tree_add_child(node, t1); } tree_add_child(node, t2); return CAST_TO_TYPE(node); }
EXPRESSION *make_tuple(EXPRESSION *expr1, EXPRESSION *expr2, int source_line) { EXPRESSION *node; if (tree_is_type(expr1, EXPR_TUPLE)) node = expr1; else { node = create_ast_node(EXPR_TUPLE, source_line); tree_add_child(node, expr1); node->type = create_ast_node(TYPE_TUPLE, source_line); tree_add_child(node->type, expr1->type); } tree_add_child(node, expr2); tree_add_child(node->type, expr2->type); return node; }
EXPRESSION *atomise_expression(MODULE *module, FUNCTION *func, BLOCK *block, EXPRESSION *expr, STATEMENT *before) { if (is_atomic(expr)) return expr; if (tree_is_type(expr, EXPR_TUPLE)) { EXPRESSION *new_temp = make_empty_tuple(CAST_TO_AST(expr)->source_line); int i; for (i = 0; i < tree_num_children(expr); i++) tree_add_child(new_temp, atomise_expression(module, func, block, tree_get_child(expr, i), before)); return new_temp; } EXPRESSION *new_temp = make_new_temp(module, func, expr->type, CAST_TO_AST(expr)->source_line); STATEMENT *new_assign = make_assignment(new_temp, expr, CAST_TO_AST(expr)->source_line); if (has_graph(func)) { GRAPH *graph = func->graph; add_vertex(graph, CAST_TO_NODE(new_assign)); inject_before(graph, CAST_TO_NODE(new_assign), CAST_TO_NODE(before), 0); } else tree_add_before(CAST_TO_NODE(block), CAST_TO_NODE(new_assign), CAST_TO_NODE(before)); return new_temp; }
STATEMENT *make_test(EXPRESSION *c, int source_line) { if (source_line == 0 && c) source_line = CAST_TO_AST(c)->source_line; NODE *node = create_ast_node(STMT_TEST, source_line); tree_add_child(node, c); return CAST_TO_STATEMENT(node); }
void add_vertex(GRAPH *graph, NODE *vertex) { if (!vertex) { /* N.B. Vertex positions are sometimes important, so a NULL one still needs to occupy a position in the child list. */ tree_add_child(graph, vertex); return; } HASH_ENTRY *he = find_in_hash(graph->labels, vertex, sizeof(void *)); if (he) return; add_to_hash(graph->labels, vertex, sizeof(void *), (void *) tree_num_children(graph)); tree_add_child(graph, vertex); }
EXPRESSION *make_closure(MODULE *mod, TYPE *type, DECLARATION *args, BLOCK *body, int source_line) { static int next_id = 0; char name[100]; sprintf(name, "closure%d", next_id++); char *str = add_string(mod, name, strlen(name)); FUNCTION *func = make_function(type, str, args, source_line); tree_get_child(func, 0) = body; EXPRESSION *expr = create_ast_node(EXPR_CLOSURE, source_line); tree_add_child(expr, func); expr->type = make_map_type(args->type, type, source_line); /* Add new function to module. */ tree_add_child(mod, func); add_to_hash(mod->table, str, strlen(str), func); return expr; }
STATEMENT *make_block(HASH *table, STATEMENT *stmt, int source_line) { if (tree_is_type(stmt, STMT_BLOCK)) return stmt; if (source_line == 0 && stmt) source_line = CAST_TO_AST(stmt)->source_line; BLOCK *block = CAST_TO_BLOCK(create_ast_node(STMT_BLOCK, source_line)); block->table = table ? table : create_hash(10, key_type_copyable); if (tree_is_type(stmt, STMT_SEQUENCE)) { int i; for (i = 0; i < tree_num_children(stmt); i++) tree_add_child(block, tree_get_child(stmt, i)); } else tree_add_child(block, stmt); return CAST_TO_STATEMENT(block); }
static STATEMENT *reduce_statement(MODULE *module, FUNCTION *func, BLOCK *block, STATEMENT *stmt) { if (stmt == NULL) return stmt; if (tree_is_type(stmt, STMT_ASSIGN)) { EXPRESSION *expr = tree_get_child(stmt, 1); expr = simplify_expression(module, func, block, expr, stmt); tree_get_child(stmt, 1) = expr; } else if (tree_is_type(stmt, STMT_IF)) { EXPRESSION *cond = tree_get_child(stmt, 0); cond = simplify_expression(module, func, block, cond, stmt); tree_get_child(stmt, 0) = cond; reduce_block(module, func, tree_get_child(stmt, 1)); reduce_block(module, func, tree_get_child(stmt, 2)); } else if (tree_is_type(stmt, STMT_WHILE)) { EXPRESSION *cond = tree_get_child(stmt, 0); BLOCK *body = tree_get_child(stmt, 1); if (!is_atomic(cond)) { EXPRESSION *old_cond = cond; cond = atomise_expression(module, func, block, cond, stmt); tree_get_child(stmt, 0) = cond; STATEMENT *new_assign = make_assignment(cond, CAST_TO_EXPRESSION(tree_copy(old_cond)), CAST_TO_AST(cond)->source_line); tree_add_child(body, new_assign); } reduce_block(module, func, body); } else if (tree_is_type(stmt, STMT_RETURN)) { EXPRESSION *expr = tree_get_child(stmt, 0); expr = atomise_expression(module, func, block, expr, stmt); tree_get_child(stmt, 0) = expr; } else if (tree_is_type(stmt, STMT_RESTART)) { /* Do nothing. */ } else error("Not sure how to reduce statement of type %d\n", tree_type(stmt)); return stmt; }
EXPRESSION *get_input_tuple(FUNCTION *func) { int source_line = CAST_TO_AST(func)->source_line; EXPRESSION *tuple = create_ast_node(EXPR_TUPLE, source_line); DECLARATION *args = tree_get_child(func, 1); if (!args) return make_empty_tuple(source_line); int i; for (i = 0; i < tree_num_children(args); i++) { DECLARATION *v = tree_get_child(args, i); EXPRESSION *arg = make_variable(v->name, CAST_TO_AST(v)->source_line); arg->type = v->type; ((VARIABLE *) arg)->decl = v; tree_add_child(tuple, arg); } if (tree_num_children(tuple) == 1) return tree_get_child(tuple, 0); return tuple; }
/* * When we export a new directory we need to add a new * path segment through the pseudofs to reach the new * directory. This new path is reflected in a list of * directories added to the "visible" list. * * Here there are two lists of visible fids: one hanging off the * pseudo exportinfo, and the one we want to add. It's possible * that the two lists share a common path segment * and have some common directories. We need to combine * the lists so there's no duplicate entries. Where a common * path component is found, the vis_count field is bumped. * * This example shows that the treenode chain (tree_head) and * exp_visible chain (vis_head) can differ in length. The latter * can be shorter. The outer loop must loop over the vis_head chain. * * share /x/a * mount -F ufs /dev/dsk/... /x/y * mkdir -p /x/y/a/b * share /x/y/a/b * * When more_visible() is called during the second share, * the existing namespace is following: * exp_visible_t * treenode_t exportinfo_t v0 v1 * ns_root+---+ +------------+ +---+ +---+ * t0| / |........| E0 pseudo |->| x |->| a | * +---+ +------------+ +---+ +---+ * | / / * +---+ / / * t1| x |------------------------ / * +---+ / * | / * +---+ / * t2| a |------------------------- * +---+........+------------+ * | E1 real | * +------------+ * * This is being added: * * tree_head vis_head * +---+ +---+ * t3| x |->| x |v2 * +---+ +---+ * | | * +---+ +---+ v4 v5 * t4| y |->| y |v3 +------------+ +---+ +---+ * +---+\ +---+ | E2 pseudo |->| a |->| b | * | \....... >+------------+ +---+ +---+ * +---+ / / * t5| a |--------------------------- / * +---+ / * | / * +---+------------------------------- * t6| b | +------------+ * +---+..........>| E3 real | * +------------+ * * more_visible() will: * - kmem_free() t3 and v2 * - add t4, t5, t6 as a child of t1 (t4 will become sibling of t2) * - add v3 to the end of E0->exi_visible * * Note that v4 and v5 were already processed in pseudo_exportfs() and * added to E2. The outer loop of more_visible() will loop only over v2 * and v3. The inner loop of more_visible() always loops over v0 and v1. * * Illustration for this scenario: * * mkdir -p /v/a/b/c * share /v/a/b/c * mkdir /v/a/b/c1 * mkdir -p /v/a1 * mv /v/a/b /v/a1 * share /v/a1/b/c1 * * EXISTING * treenode * namespace: +-----------+ visibles * |exportinfo |-->v->a->b->c * connect_point->+---+--->+-----------+ * | / |T0 * +---+ * | NEW treenode chain: * child->+---+ * | v |T1 +---+<-curr * +---+ N1| v | * | +---+ * +---+ | * | a |T2 +---+<-tree_head * +---+ N2| a1| * | +---+ * +---+ | * | b |T3 +---+ * +---+ N3| b | * | +---+ * +---+ | * | c |T4 +---+ * +---+ N4| c1| * +---+ * * The picture above illustrates the position of following pointers after line * 'child = tree_find_child_by_vis(connect_point, curr->tree_vis);' * was executed for the first time in the outer 'for' loop: * * connect_point..parent treenode in the EXISTING namespace to which the 'curr' * should be connected. If 'connect_point' already has a child * with the same value of tree_vis as the curr->tree_vis is, * the 'curr' will not be added, but kmem_free()d. * child..........the result of tree_find_child_by_vis() * curr...........currently processed treenode from the NEW treenode chain * tree_head......current head of the NEW treenode chain, in this case it was * already moved down to its child - preparation for another loop * * What will happen to NEW treenodes N1, N2, N3, N4 in more_visible() later: * * N1: is merged - i.e. N1 is kmem_free()d. T0 has a child T1 with the same * tree_vis as N1 * N2: is added as a new child of T1 * Note: not just N2, but the whole chain N2->N3->N4 is added * N3: not processed separately (it was added together with N2) * Even that N3 and T3 have same tree_vis, they are NOT merged, but will * become duplicates. * N4: not processed separately */ static void more_visible(struct exportinfo *exi, treenode_t *tree_head) { struct exp_visible *vp1, *vp2, *vis_head, *tail, *next; int found; treenode_t *child, *curr, *connect_point; vis_head = tree_head->tree_vis; connect_point = exi->exi_tree; /* * If exportinfo doesn't already have a visible * list just assign the entire supplied list. */ if (exi->exi_visible == NULL) { tree_add_child(exi->exi_tree, tree_head); exi->exi_visible = vis_head; return; } /* The outer loop traverses the supplied list. */ for (vp1 = vis_head; vp1; vp1 = next) { found = 0; next = vp1->vis_next; /* The inner loop searches the exportinfo visible list. */ for (vp2 = exi->exi_visible; vp2; vp2 = vp2->vis_next) { tail = vp2; if (EQFID(&vp1->vis_fid, &vp2->vis_fid)) { found = 1; vp2->vis_count++; VN_RELE(vp1->vis_vp); /* Transfer vis_exported from vp1 to vp2. */ if (vp1->vis_exported && !vp2->vis_exported) vp2->vis_exported = 1; kmem_free(vp1, sizeof (*vp1)); tree_head->tree_vis = vp2; break; } } /* If not found - add to the end of the list */ if (! found) { tail->vis_next = vp1; vp1->vis_next = NULL; } curr = tree_head; tree_head = tree_head->tree_child_first; if (! connect_point) /* No longer merging */ continue; /* * The inner loop could set curr->tree_vis to the EXISTING * exp_visible vp2, so we can search among the children of * connect_point for the curr->tree_vis. No need for EQFID. */ child = tree_find_child_by_vis(connect_point, curr->tree_vis); /* * Merging cannot be done if a valid child->tree_exi would * be overwritten by a new curr->tree_exi. */ if (child && (child->tree_exi == NULL || curr->tree_exi == NULL)) { if (curr->tree_exi) { /* Transfer the exportinfo */ child->tree_exi = curr->tree_exi; child->tree_exi->exi_tree = child; } kmem_free(curr, sizeof (treenode_t)); connect_point = child; } else { /* Branching */ tree_add_child(connect_point, curr); connect_point = NULL; } } }
STATEMENT *make_return(EXPRESSION *c, int source_line) { NODE *node = create_ast_node(STMT_RETURN, source_line); tree_add_child(node, c); return CAST_TO_STATEMENT(node); }