1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2016-2018. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #define ERTS_WANT_NFUNC_SCHED_INTERNALS__
26
27 #include "global.h"
28 #include "erl_process.h"
29 #include "bif.h"
30 #include "erl_nfunc_sched.h"
31 #include "erl_trace.h"
32 #include "jit/beam_asm.h"
33
34 ErtsNativeFunc *
erts_new_proc_nfunc(Process * c_p,int argc)35 erts_new_proc_nfunc(Process *c_p, int argc)
36 {
37 ErtsNativeFunc *nep, *old_nep;
38 size_t size;
39
40 size = sizeof(ErtsNativeFunc) + (argc-1)*sizeof(Eterm);
41 nep = erts_alloc(ERTS_ALC_T_NFUNC_TRAP_WRAPPER, size);
42
43 nep->argc = -1; /* unused marker */
44 nep->argv_size = argc;
45 old_nep = ERTS_PROC_SET_NFUNC_TRAP_WRAPPER(c_p, nep);
46 if (old_nep) {
47 erts_free(ERTS_ALC_T_NFUNC_TRAP_WRAPPER, old_nep);
48 }
49 return nep;
50 }
51
52 void
erts_destroy_nfunc(Process * p)53 erts_destroy_nfunc(Process *p)
54 {
55 ErtsNativeFunc *nep = ERTS_PROC_SET_NFUNC_TRAP_WRAPPER(p, NULL);
56 if (nep) {
57 if (nep->m)
58 erts_nfunc_cleanup_nif_mod(nep);
59 erts_free(ERTS_ALC_T_NFUNC_TRAP_WRAPPER, nep);
60 }
61 }
62
63 ErtsNativeFunc *
erts_nfunc_schedule(Process * c_p,Process * dirty_shadow_proc,const ErtsCodeMFA * mfa,ErtsCodePtr pc,BeamInstr instr,void * dfunc,void * ifunc,Eterm mod,Eterm func,int argc,const Eterm * argv)64 erts_nfunc_schedule(Process *c_p, Process *dirty_shadow_proc,
65 const ErtsCodeMFA *mfa, ErtsCodePtr pc,
66 BeamInstr instr,
67 void *dfunc, void *ifunc,
68 Eterm mod, Eterm func,
69 int argc, const Eterm *argv)
70 {
71 Process *used_proc;
72 ErtsSchedulerData *esdp;
73 Eterm* reg;
74 ErtsNativeFunc* nep;
75 int i;
76
77 ERTS_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p)
78 & ERTS_PROC_LOCK_MAIN);
79
80 if (dirty_shadow_proc) {
81 esdp = erts_get_scheduler_data();
82 ASSERT(esdp && ERTS_SCHEDULER_IS_DIRTY(esdp));
83
84 used_proc = dirty_shadow_proc;
85 }
86 else {
87 esdp = erts_proc_sched_data(c_p);
88 ASSERT(esdp && !ERTS_SCHEDULER_IS_DIRTY(esdp));
89
90 used_proc = c_p;
91 ERTS_VBUMP_ALL_REDS(c_p);
92 }
93
94 reg = esdp->registers->x_reg_array.d;
95
96 if (mfa)
97 nep = erts_get_proc_nfunc(c_p, (int) mfa->arity);
98 else {
99 /* If no mfa, this is not the first schedule... */
100 nep = ERTS_PROC_GET_NFUNC_TRAP_WRAPPER(c_p);
101 ASSERT(nep && nep->argc >= 0);
102 }
103
104 if (nep->argc < 0) {
105 /*
106 * First schedule; save things that might
107 * need to be restored...
108 */
109 for (i = 0; i < (int) mfa->arity; i++)
110 nep->argv[i] = reg[i];
111 nep->pc = pc;
112 nep->mfa = mfa;
113 nep->current = c_p->current;
114 ASSERT(argc >= 0);
115 nep->argc = (int) mfa->arity;
116 nep->m = NULL;
117
118 ASSERT(!erts_check_nfunc_in_area(c_p,
119 (char *) nep,
120 (sizeof(ErtsNativeFunc)
121 + (sizeof(Eterm)
122 *(nep->argc-1)))));
123 }
124 /* Copy new arguments into register array if necessary... */
125 if (reg != argv) {
126 for (i = 0; i < argc; i++)
127 reg[i] = argv[i];
128 }
129 ASSERT(is_atom(mod) && is_atom(func));
130 nep->trampoline.info.mfa.module = mod;
131 nep->trampoline.info.mfa.function = func;
132 nep->trampoline.info.mfa.arity = (Uint) argc;
133 #ifdef BEAMASM
134 nep->trampoline.trace[0] = (BeamInstr) instr; /* call_bif || call_nif */
135 #endif
136 nep->trampoline.call_op = (BeamInstr) instr; /* call_bif || call_nif */
137 nep->trampoline.dfunc = (BeamInstr) dfunc;
138 nep->func = ifunc;
139 used_proc->arity = argc;
140 used_proc->freason = TRAP;
141 #ifndef BEAMASM
142 used_proc->i = (ErtsCodePtr)&nep->trampoline.call_op;
143 #else
144 ERTS_CT_ASSERT(sizeof(nep->trampoline.trace) == BEAM_ASM_FUNC_PROLOGUE_SIZE);
145 used_proc->i = (ErtsCodePtr)&nep->trampoline.trace;
146 ASSERT_MFA(erts_code_to_codemfa(used_proc->i));
147 #endif
148 return nep;
149 }
150