Exemplo n.º 1
0
// Copies one term 't' to 'dstheap' returns new clone term located in new heap
Term copy_one_term(VM& vm, Heap* dstheap, Term t) {
    // Immediate values go immediately out
    if (t.is_non_value() || t.is_nil() || t.is_small() || t.is_atom() ||
            t.is_short_pid() || t.is_short_port()) {
        return t;
    }
    if (t.is_tuple()) {
        Word arity = t.tuple_get_arity();
        Term* new_t =
            (Term*)dstheap->allocate<Word>(layout::Tuple::box_size(arity));
        Term* this_t = t.boxed_get_ptr<Term>();
        layout::Tuple::arity(new_t) = layout::Tuple::arity(this_t);
        // Deep clone
        for (Word i = 0; i < arity; ++i) {
            layout::Tuple::element(new_t, i) =
                copy_one_term(vm, dstheap, layout::Tuple::element(this_t, i));
        }
        return Term::make_tuple_prepared(new_t);
    }
    if (t.is_boxed()) {
        if (t.is_boxed_fun()) {
            BoxedFun* bf = t.boxed_get_ptr<BoxedFun>();
            return fun::box_fun(dstheap, bf->fun_entry, bf->pid, bf->frozen);
        }
    }
    t.println(vm);
    G_TODO("notimpl copy_one_term for some type of term");
}
Exemplo n.º 2
0
static Term spawn_mfargs(Process* proc, Term m, Term f, Term args, bool link) {
  if (!m.is_atom()) {
    return proc->error_badarg(m);
  }
  if (!f.is_atom()) {
    return proc->error_badarg(f);
  }
  if (!args.is_list()) {
    return proc->error_badarg(args);
  }

  // TODO: on process control blocks' heap
  Process* new_proc = new Process(proc->vm(), proc->get_group_leader());
  MFArity mfa(m, f, bif::length(args).length);

  // A process (proc) spawning another process, and gives args from its heap
  // We should clone args to new process' registers
  Term old_heap_args[erts::max_fun_arity];
  Term new_heap_args[erts::max_fun_arity];  // clone of array_args in new heap

  args.cons_to_array(old_heap_args, sizeof(old_heap_args));

  proc::copy_terms(proc->vm(), new_proc->get_heap(), old_heap_args,
                   old_heap_args + mfa.arity, new_heap_args);

  try {
    mfa.println(proc->vm());
    new_proc->spawn(mfa, new_heap_args);
  } catch (std::runtime_error& e) {
    return proc->error(atom::ERROR, e.what());
  }

  if (link) {
    // TODO: Establish link in both directions
    // TODO: on error - destroy result
  }

  return new_proc->get_pid();
}
Exemplo n.º 3
0
Term bif_register_2(Process* p, Term name, Term pid_port) {
  if (!name.is_atom() || name == atom::UNDEFINED) {
    return p->error_badarg(name);
  }
  if (!pid_port.is_pid() && !pid_port.is_port()) {
    return p->error_badarg(pid_port);
  }
  switch (p->vm().register_name(name, pid_port)) {
    case RegisterResult::Ok:
      return atom::TRUE;
    case RegisterResult::RegistrationExists:  // fall through
    case RegisterResult::ProcessNotFound:
      return p->error_badarg(pid_port);
  }
}
Exemplo n.º 4
0
Either<Word*, Term> Process::apply(Term m,
                                   Term f,
                                   Term args) {
  // Check the arguments which should be of the form apply(M,F,Args) where
  // F is an atom and Args is an arity long list of terms
  if (!f.is_atom()) {
    error_badarg(f);  // fail right here
    return nullptr;
  }

  // The module argument may be either an atom or an abstract module
  // (currently implemented using tuples, but this might change)
  Term _this = the_non_value;
  if (!m.is_atom()) {
    if (!m.is_tuple() || m.tuple_get_arity() < 1) {
      error_badarg(m);
      return nullptr;
    }
    // TODO: can optimize here by accessing tuple internals via pointer and
    // checking arity and then taking 2nd element
    _this = m;
    m = m.tuple_get_element(1);
    if (!m.is_atom()) {
      error_badarg(m);
      return nullptr;
    }
  }

  ctx_.assert_swapped_out_partial();
  Word arity = 0;
  if (args.is_small()) {
    // Small unsigned in args means args already are loaded in regs
    arity = args.small_word();
  } else {
    // Walk down the 3rd parameter of apply (the argument list) and copy
    // the parameters to the x registers (regs[]). If the module argument
    // was an abstract module, add 1 to the function arity and put the
    // module argument in the n+1st x register as a THIS reference.
    Term tmp = args;
    while (tmp.is_cons()) {
      if (arity < erts::max_regs - 1) {
        tmp.cons_head_tail(ctx_.regs_[arity++], tmp);
      } else {
        error(atom::SYSTEM_LIMIT);
        return nullptr;
      }
    }
    if (tmp.is_not_nil()) {  // Must be well-formed list
      error_badarg();
      return nullptr;
    }
    if (_this != the_non_value) {
      ctx_.regs_[arity++] = _this;
    }
  }
  ctx_.live = arity;

  // Get the index into the export table, or failing that the export
  // entry for the error handler.
  MFArity mfa(m, f, arity);

  auto maybe_bif = vm_.find_bif(mfa);
  if (maybe_bif) {
    return vm_.apply_bif(this, mfa.arity, maybe_bif, ctx_.regs_);
  }

  Export* ep = vm_.codeserver().find_mfa(mfa);
  if (!ep) {
    // if ((ep = apply_setup_error_handler(proc, m, f, arity, regs)) == NULL)
    // goto error;
    error(atom::UNDEF);
    return nullptr;
  }
  if (ep->is_bif()) {
    return vm_.apply_bif(this, ep->mfa.arity, ep->bif_fn(), ctx_.regs_);
  }
  //  else if (ERTS_PROC_GET_SAVED_CALLS_BUF(proc)) {
  //      save_calls(proc, ep);
  //  }
  //  DTRACE_GLOBAL_CALL_FROM_EXPORT(proc, ep);
  //  return ep->addressv[erts_active_code_ix()];
  return ep->code();
}