summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/erl_fun.h
blob: a67afaceeba0c8fb4cc30e7ab2a0526e64a80937 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2000-2022. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * %CopyrightEnd%
 */

#ifndef __ERLFUNTABLE_H__
#define __ERLFUNTABLE_H__

#include "erl_threads.h"

/*
 * Fun entry.
 */
typedef struct erl_fun_entry {
    /* We start with an `ErtsDispatchable`, similar to export entries, so that
     * we can mostly use the same code for both. This greatly reduces the
     * complexity of instructions like `call_fun` and `is_function2`. */
    ErtsDispatchable dispatch;

    /* These fields identify the function and must not be altered after fun
     * creation. */
    Eterm module;                   /* Tagged atom for module. */
    Uint arity;                     /* The arity of the fun. */
    int index;                      /* New style index. */
    byte uniq[16];                  /* MD5 for module. */
    int old_uniq;                   /* Unique number (old_style) */
    int old_index;                  /* Old style index */

    erts_refc_t refc;               /* Reference count: One for code + one for
                                     * each fun object in each process. */
    ErtsCodePtr pend_purge_address; /* Address during a pending purge */
} ErlFunEntry;

/* This structure represents a 'fun' (lambda), whether local or external. It is
 * stored on process heaps, and has variable size depending on the size of the
 * environment. */

typedef struct erl_fun_thing {
    Eterm thing_word;       /* Subtag FUN_SUBTAG. */

    union {
        /* Both `ErlFunEntry` and `Export` begin with an `ErtsDispatchable`, so
         * code that doesn't really care which (e.g. calls) can use this
         * pointer to improve performance. */
        ErtsDispatchable *disp;

        /* Pointer to function entry, valid iff `creator != am_external`.*/
        ErlFunEntry *fun;

        /* Pointer to export entry, valid iff `creator == am_external`.*/
        Export *exp;
    } entry;

    /* Next off-heap object, must be NULL when this is an external fun. */
    struct erl_off_heap_header *next;

    byte arity;             /* The _apparent_ arity of the fun. */
    byte num_free;          /* Number of free variables (in env). */

    /* -- The following may be compound Erlang terms ---------------------- */
    Eterm creator;          /* Pid of creator process (contains node). */
    Eterm env[];            /* Environment (free variables). */
} ErlFunThing;

#define is_local_fun(FunThing) ((FunThing)->creator != am_external)
#define is_external_fun(FunThing) ((FunThing)->creator == am_external)

/* ERL_FUN_SIZE does _not_ include space for the environment which is a
 * C99-style flexible array */
#define ERL_FUN_SIZE ((sizeof(ErlFunThing)/sizeof(Eterm)))

ErlFunThing *erts_new_export_fun_thing(Eterm **hpp, Export *exp, int arity);
ErlFunThing *erts_new_local_fun_thing(Process *p,
                                      ErlFunEntry *fe,
                                      int arity,
                                      int num_free);

void erts_init_fun_table(void);
void erts_fun_info(fmtfn_t, void *);
int erts_fun_table_sz(void);

/* Finds or inserts a fun entry that matches the given signature. */
ErlFunEntry* erts_put_fun_entry2(Eterm mod, int old_uniq, int old_index,
                                 const byte* uniq, int index, int arity);

const ErtsCodeMFA *erts_get_fun_mfa(const ErlFunEntry *fe, ErtsCodeIndex ix);

void erts_set_fun_code(ErlFunEntry *fe, ErtsCodeIndex ix, ErtsCodePtr address);

ERTS_GLB_INLINE
ErtsCodePtr erts_get_fun_code(ErlFunEntry *fe, ErtsCodeIndex ix);

int erts_is_fun_loaded(const ErlFunEntry* fe, ErtsCodeIndex ix);

void erts_erase_fun_entry(ErlFunEntry* fe);
void erts_cleanup_funs(ErlFunThing* funp);

struct erl_module_instance;
void erts_fun_purge_prepare(struct erl_module_instance* modi);
void erts_fun_purge_abort_prepare(ErlFunEntry **funs, Uint no);
void erts_fun_purge_abort_finalize(ErlFunEntry **funs, Uint no);
void erts_fun_purge_complete(ErlFunEntry **funs, Uint no);
void erts_dump_fun_entries(fmtfn_t, void *);


void erts_fun_start_staging(void);
void erts_fun_end_staging(int commit);

#if ERTS_GLB_INLINE_INCL_FUNC_DEF

ERTS_GLB_INLINE
ErtsCodePtr erts_get_fun_code(ErlFunEntry *fe, ErtsCodeIndex ix) {
    return fe->dispatch.addresses[ix];
}

#endif

#endif