Пример #1
0
/*
** Returns `block` on success or NULL on failure
**
** If the given block is used, returns NULL and does nothing.
*/
t_block         *egc_defrag_block(t_heap *heap, t_block *block, int clr_left)
{
  t_block       *last_free_block;

  last_free_block = egc_get_last_free_block(heap, block);
  if (!last_free_block || block == last_free_block)
    return (NULL);
  join_blocks(block, last_free_block, clr_left);
  LOG("egc_defrag_block()");
  LOG_POINTER(block);
  LOG("");
  return (block);
}
Пример #2
0
static void generate_control(code_block *parent, control_statement *control) {
  loop_statement *target = control->target;
  if (target->type == S_DO_WHILE) {
    block_node **root = control->type == S_BREAK
      ? &target->break_node
      : &target->continue_node;

    block_node *node = xmalloc(sizeof(*node));
    node->block = parent;
    node->next = *root;
    *root = node;
  } else {
    join_blocks(parent, control->type == S_BREAK
      ? target->post_block
      : target->condition_block);
  }
}
Пример #3
0
static code_block *generate_do_while(code_block *parent, loop_statement *loop) {
  size_t body_block = parent->system->block_count;
  code_block *body = fork_block(parent), *context = body;

  if (loop->body) {
    struct generate_loop_trigger_data data = {
      .loop = loop,
      .done = false,
      .prev_block = body,
      .context_block = &context
    };
    body = generate_block(body, loop->body, loop_trigger, &data);
  }

  // if the body ends, it implicitly continues
  if (body) {
    block_node *node = xmalloc(sizeof(*node));
    node->block = body;
    node->next = loop->continue_node;
    loop->continue_node = node;
  }

  // if we ever continue the loop, we'll want to include the available variables
  // these variables:
  // - need to be in the outermost scope in the loop
  // - need to be available from all continue statements (including the final
  //   implicit continue)
  if (loop->continue_node) {
    code_block *condition = tangle_blocks(context, loop->continue_node);

    condition = generate_expression(condition, loop->condition);

    code_block *body_replay, *post;
    weave_blocks(parent, loop->break_node, condition, &body_replay, &post);

    join_blocks(body_replay, body_block);

    return post;
  }

  // loop only breaks, never continues (effectively not a loop)
  if (loop->break_node) {
    fprintf(stderr, "do-while condition not reachable\n");
    return tangle_blocks(parent, loop->break_node);
  }

  fprintf(stderr, "infinite loop, do-while condition not reachable\n");
  return NULL;
}

static code_block *generate_while(code_block *parent, loop_statement *loop) {
  if (loop->condition->operation.type == O_LITERAL &&
      loop->condition->type->type == T_BOOL && loop->condition->value_bool) {
    loop->type = S_DO_WHILE;
    return generate_do_while(parent, loop);
  }

  size_t condition_block = parent->system->block_count;
  code_block *condition = fork_block(parent);

  condition = generate_expression(condition, loop->condition);

  code_block *body, *post;
  branch_into(condition, &body, &post);

  // TODO: this is using undocumented behavior
  size_t /*body_block = parent->system->block_count - 2,
    */post_block = parent->system->block_count - 1;

  loop->condition_block = condition_block;
  loop->post_block = post_block;

  if (loop->body) {
    body = generate_block(body, loop->body, NULL, NULL);
  }

  if (body) {
    join_blocks(body, condition_block);
  }

  return post;
}

static code_block *generate_loop(code_block *parent, loop_statement *loop) {
  return loop->type == S_DO_WHILE
    ? generate_do_while(parent, loop)
    : generate_while(parent, loop);
}

static code_block *generate_if(code_block *parent, if_statement *branch) {
  parent = generate_expression(parent, branch->condition);

  code_block *first, *second;
  branch_into(parent, &first, &second);

  first = branch->first ? generate_block(first, branch->first, NULL, NULL)
    : first;
  second = branch->second ? generate_block(second, branch->second, NULL, NULL)
    : second;

  switch (((!first) << 1) | (!second)) {
  case 0: // both exist
    return merge_blocks(parent, first, second);
  case 1: // the first block exists
    return rejoin_block(parent, first);
  case 2: // the second block exists
    return rejoin_block(parent, second);
  case 3:
    return NULL;
  }

  fprintf(stderr, "if statement generation logical failure\n");
  abort();
}