// 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"); }
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(); }
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); } }
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(); }