summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/erl_fun.h
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/erl_fun.h')
-rw-r--r--erts/emulator/beam/erl_fun.h95
1 files changed, 68 insertions, 27 deletions
diff --git a/erts/emulator/beam/erl_fun.h b/erts/emulator/beam/erl_fun.h
index 995fb41de2..4276e9a999 100644
--- a/erts/emulator/beam/erl_fun.h
+++ b/erts/emulator/beam/erl_fun.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2021. All Rights Reserved.
+ * 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.
@@ -26,53 +26,85 @@
/*
* Fun entry.
*/
-
typedef struct erl_fun_entry {
- HashBucket bucket; /* MUST BE LOCATED AT TOP OF STRUCT!!! */
-
- byte uniq[16]; /* MD5 for module. */
- int index; /* New style index. */
- int old_uniq; /* Unique number (old_style) */
- int old_index; /* Old style index */
- ErtsCodePtr address; /* Pointer to code for fun */
+ /* 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;
- Uint arity; /* The arity of the fun. */
+ /* 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). It is stored on
- * process heaps. It has variable size depending on the size
- * of the environment.
- */
+/* 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. */
- ErlFunEntry* fe; /* Pointer to fun entry. */
- struct erl_off_heap_header* next;
- Uint arity; /* The arity of the fun. */
- Uint 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[1]; /* Environment (free variables). */
+ 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[1]; /* 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 */
#define ERL_FUN_SIZE ((sizeof(ErlFunThing)/sizeof(Eterm))-1)
+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);
-ErlFunEntry* erts_get_fun_entry(Eterm mod, int uniq, int index);
-
+/* 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 byte* uniq, int index, int arity);
+
+const ErtsCodeMFA *erts_get_fun_mfa(const ErlFunEntry *fe);
+
+void erts_set_fun_code(ErlFunEntry *fe, ErtsCodePtr address);
-int erts_is_fun_loaded(ErlFunEntry* fe);
+ERTS_GLB_INLINE
+ErtsCodePtr erts_get_fun_code(ErlFunEntry *fe, ErtsCodeIndex ix);
+
+int erts_is_fun_loaded(const ErlFunEntry* fe);
void erts_erase_fun_entry(ErlFunEntry* fe);
void erts_cleanup_funs(ErlFunThing* funp);
@@ -84,4 +116,13 @@ 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 *);
+#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