1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 1998-2020. 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 #ifndef _DB_UTIL_H
22 #define _DB_UTIL_H
23
24 #include "erl_flxctr.h"
25 #include "global.h"
26 #include "erl_message.h"
27 #include "erl_bif_unique.h"
28
29 /*#define HARDDEBUG 1*/
30
31 #ifdef DEBUG
32 /*
33 ** DMC_DEBUG does NOT need DEBUG, but DEBUG needs DMC_DEBUG
34 */
35 #define DMC_DEBUG 1
36 #define ETS_DBG_FORCE_TRAP 1
37 #endif
38
39 /*
40 * These values can be returned from the functions performing the
41 * BIF operation for different types of tables. When the
42 * actual operations have been performed, the BIF function
43 * checks for negative returns and issues BIF_ERRORS based
44 * upon these values.
45 */
46 #define DB_ERROR_NONE_FALSE 1 /* No error am_false reult */
47 #define DB_ERROR_NONE 0 /* No error */
48 #define DB_ERROR_BADITEM -1 /* The item was malformed ie no
49 tuple or to small*/
50 #define DB_ERROR_BADTABLE -2 /* The Table is inconsisitent */
51 #define DB_ERROR_SYSRES -3 /* Out of system resources */
52 #define DB_ERROR_BADKEY -4 /* Returned if a key that should
53 exist does not. */
54 #define DB_ERROR_BADPARAM -5 /* Returned if a specified slot does
55 not exist (hash table only) or
56 the state parameter in db_match_object
57 is broken.*/
58 #define DB_ERROR_UNSPEC -10 /* Unspecified error */
59
60 /*#define DEBUG_CLONE*/
61
62 /*
63 * A datatype for a database entry stored out of a process heap
64 */
65 typedef struct db_term {
66 struct erl_off_heap_header* first_oh; /* Off heap data for term. */
67 Uint size; /* Heap size of term in "words" */
68 #ifdef DEBUG_CLONE
69 Eterm* debug_clone; /* An uncompressed copy */
70 #endif
71 Eterm tpl[1]; /* Term data. Top tuple always first */
72
73 /* Compression: is_immed and key element are uncompressed.
74 Compressed elements are stored in external format after each other
75 last in dbterm. The top tuple elements contains byte offsets, to
76 the start of the data, tagged as headers.
77 The allocated size of the dbterm in bytes is stored at tpl[arity+1].
78 */
79 } DbTerm;
80
81 #define DB_MUST_RESIZE 1
82 #define DB_NEW_OBJECT 2
83 #define DB_INC_TRY_GROW 4
84
85 /* Info about a database entry while it's being updated
86 * (by update_counter or update_element)
87 */
88 typedef struct {
89 DbTable* tb;
90 DbTerm* dbterm;
91 void** bp; /* {Hash|Tree}DbTerm** */
92 Uint new_size;
93 int flags;
94 union {
95 struct {
96 struct DbTableHashLockAndCounter* lck_ctr;
97 } hash;
98 struct {
99 struct DbTableCATreeNode* base_node;
100 struct DbTableCATreeNode* parent;
101 int current_level;
102 } catree;
103 } u;
104 } DbUpdateHandle;
105
106 /* How safe are we from double-hits or missed objects
107 * when iterating without fixation?
108 */
109 enum DbIterSafety {
110 ITER_UNSAFE, /* Must fixate to be safe */
111 ITER_SAFE_LOCKED, /* Safe while table is locked, not between trap calls */
112 ITER_SAFE /* No need to fixate at all */
113 };
114
115 typedef struct db_table_method
116 {
117 int (*db_create)(Process *p, DbTable* tb);
118 int (*db_first)(Process* p,
119 DbTable* tb, /* [in out] */
120 Eterm* ret /* [out] */);
121 int (*db_next)(Process* p,
122 DbTable* tb, /* [in out] */
123 Eterm key, /* [in] */
124 Eterm* ret /* [out] */);
125 int (*db_last)(Process* p,
126 DbTable* tb, /* [in out] */
127 Eterm* ret /* [out] */);
128 int (*db_prev)(Process* p,
129 DbTable* tb, /* [in out] */
130 Eterm key,
131 Eterm* ret);
132 int (*db_put)(DbTable* tb, /* [in out] */
133 Eterm obj,
134 int key_clash_fail, /* DB_ERROR_BADKEY if key exists */
135 SWord *consumed_reds_p);
136 int (*db_get)(Process* p,
137 DbTable* tb, /* [in out] */
138 Eterm key,
139 Eterm* ret);
140 int (*db_get_element)(Process* p,
141 DbTable* tb, /* [in out] */
142 Eterm key,
143 int index,
144 Eterm* ret);
145 int (*db_member)(DbTable* tb, /* [in out] */
146 Eterm key,
147 Eterm* ret);
148 int (*db_erase)(DbTable* tb, /* [in out] */
149 Eterm key,
150 Eterm* ret);
151 int (*db_erase_object)(DbTable* tb, /* [in out] */
152 Eterm obj,
153 Eterm* ret);
154 int (*db_slot)(Process* p,
155 DbTable* tb, /* [in out] */
156 Eterm slot,
157 Eterm* ret);
158 int (*db_select_chunk)(Process* p,
159 DbTable* tb, /* [in out] */
160 Eterm tid,
161 Eterm pattern,
162 Sint chunk_size,
163 int reverse,
164 Eterm* ret,
165 enum DbIterSafety);
166 int (*db_select)(Process* p,
167 DbTable* tb, /* [in out] */
168 Eterm tid,
169 Eterm pattern,
170 int reverse,
171 Eterm* ret,
172 enum DbIterSafety);
173 int (*db_select_delete)(Process* p,
174 DbTable* tb, /* [in out] */
175 Eterm tid,
176 Eterm pattern,
177 Eterm* ret,
178 enum DbIterSafety);
179 int (*db_select_continue)(Process* p,
180 DbTable* tb, /* [in out] */
181 Eterm continuation,
182 Eterm* ret,
183 enum DbIterSafety*);
184 int (*db_select_delete_continue)(Process* p,
185 DbTable* tb, /* [in out] */
186 Eterm continuation,
187 Eterm* ret,
188 enum DbIterSafety*);
189 int (*db_select_count)(Process* p,
190 DbTable* tb, /* [in out] */
191 Eterm tid,
192 Eterm pattern,
193 Eterm* ret,
194 enum DbIterSafety);
195 int (*db_select_count_continue)(Process* p,
196 DbTable* tb, /* [in out] */
197 Eterm continuation,
198 Eterm* ret,
199 enum DbIterSafety*);
200 int (*db_select_replace)(Process* p,
201 DbTable* tb, /* [in out] */
202 Eterm tid,
203 Eterm pattern,
204 Eterm* ret,
205 enum DbIterSafety);
206 int (*db_select_replace_continue)(Process* p,
207 DbTable* tb, /* [in out] */
208 Eterm continuation,
209 Eterm* ret,
210 enum DbIterSafety*);
211 int (*db_take)(Process *, DbTable *, Eterm, Eterm *);
212
213 SWord (*db_delete_all_objects)(Process* p,
214 DbTable* db,
215 SWord reds,
216 Eterm* nitems_holder_wb);
217 Eterm (*db_delete_all_objects_get_nitems_from_holder)(Process* p,
218 Eterm nitems_holder);
219 int (*db_free_empty_table)(DbTable* db);
220 SWord (*db_free_table_continue)(DbTable* db, SWord reds);
221
222 void (*db_print)(fmtfn_t to,
223 void* to_arg,
224 int show,
225 DbTable* tb /* [in out] */ );
226
227 void (*db_foreach_offheap)(DbTable* db, /* [in out] */
228 void (*func)(ErlOffHeap *, void *),
229 void *arg);
230
231 /* Lookup a dbterm for updating. Return false if not found. */
232 int (*db_lookup_dbterm)(Process *, DbTable *, Eterm key, Eterm obj,
233 DbUpdateHandle* handle);
234
235 /* Must be called for each db_lookup_dbterm that returned true, even if
236 ** dbterm was not updated. If the handle was of a new object and cret is
237 ** not DB_ERROR_NONE, the object is removed from the table. */
238 void (*db_finalize_dbterm)(int cret, DbUpdateHandle* handle);
239 void* (*db_eterm_to_dbterm)(int compress, int keypos, Eterm obj);
240 void* (*db_dbterm_list_prepend)(void* list, void* db_term);
241 void* (*db_dbterm_list_remove_first)(void** list);
242 int (*db_put_dbterm)(DbTable* tb, /* [in out] */
243 void* obj,
244 int key_clash_fail, /* DB_ERROR_BADKEY if key exists */
245 SWord *consumed_reds_p);
246 void (*db_free_dbterm)(int compressed, void* obj);
247 Eterm (*db_get_dbterm_key)(DbTable* tb, void* db_term);
248 int (*db_get_binary_info)(Process*, DbTable* tb, Eterm key, Eterm* ret);
249 /* Raw first/next same as first/next but also return pseudo deleted keys.
250 Only internal use by ets:info(_,binary) */
251 int (*db_raw_first)(Process*, DbTable*, Eterm* ret);
252 int (*db_raw_next)(Process*, DbTable*, Eterm key, Eterm* ret);
253 } DbTableMethod;
254
255 typedef struct db_fixation {
256 /* Node in fixed_tabs list */
257 struct {
258 struct db_fixation *next, *prev;
259 Binary* btid;
260 } tabs;
261
262 /* Node in fixing_procs tree */
263 struct {
264 struct db_fixation *left, *right, *parent;
265 int is_red;
266 Process* p;
267 } procs;
268
269 /* Number of fixations on table from procs.p
270 * Protected by table write lock or read lock + fixlock
271 */
272 Uint counter;
273 } DbFixation;
274
275 typedef struct {
276 DbTable *next;
277 DbTable *prev;
278 } DbTableList;
279
280 #define ERTS_DB_TABLE_NITEMS_COUNTER_ID 0
281 #define ERTS_DB_TABLE_MEM_COUNTER_ID 1
282
283 /*
284 * This structure contains data for all different types of database
285 * tables. Note that these fields must match the same fields
286 * in the table-type specific structures.
287 * The reason it is placed here and not in db.h is that some table
288 * operations may be the same on different types of tables.
289 */
290
291 typedef struct db_table_common {
292 erts_refc_t refc; /* reference count of table struct */
293 erts_refc_t fix_count;/* fixation counter */
294 DbTableList all;
295 DbTableList owned;
296 erts_rwmtx_t rwlock; /* rw lock on table */
297 erts_mtx_t fixlock; /* Protects fixing_procs and time */
298 int is_thread_safe; /* No fine locking inside table needed */
299 Uint32 type; /* table type, *read only* after creation */
300 Eterm owner; /* Pid of the creator */
301 Eterm heir; /* Pid of the heir */
302 UWord heir_data; /* To send in ETS-TRANSFER (is_immed or (DbTerm*) */
303 Uint64 heir_started_interval; /* To further identify the heir */
304 Eterm the_name; /* an atom */
305 Binary *btid;
306 DbTableMethod* meth; /* table methods */
307 /* The ErtsFlxCtr below contains:
308 * - Total number of items in table
309 * - Total memory size (NOTE: in bytes!) */
310 ErtsFlxCtr counters;
311 char extra_for_flxctr[ERTS_FLXCTR_NR_OF_EXTRA_BYTES(2)];
312 struct { /* Last fixation time */
313 ErtsMonotonicTime monotonic;
314 ErtsMonotonicTime offset;
315 } time;
316 DbFixation* fixing_procs; /* Tree of processes who have done safe_fixtable,
317 "local" fixations not included. */
318 /* All 32-bit fields */
319 Uint32 status; /* bit masks defined below */
320 int keypos; /* defaults to 1 */
321 int compress;
322
323 /* For unfinished operations that needs to be helped */
324 void (*continuation)(long *reds_ptr,
325 void** state,
326 void* extra_context); /* To help yielded process */
327 erts_atomic_t continuation_state;
328 Binary* continuation_res_bin;
329 #ifdef ETS_DBG_FORCE_TRAP
330 erts_atomic_t dbg_force_trap; /* &1 force enabled, &2 trap this call */
331 #endif
332 } DbTableCommon;
333
334 /* These are status bit patterns */
335 #define DB_PRIVATE (1 << 0)
336 #define DB_PROTECTED (1 << 1)
337 #define DB_PUBLIC (1 << 2)
338 #define DB_DELETE (1 << 3) /* table is being deleted */
339 #define DB_SET (1 << 4)
340 #define DB_BAG (1 << 5)
341 #define DB_DUPLICATE_BAG (1 << 6)
342 #define DB_ORDERED_SET (1 << 7)
343 #define DB_CA_ORDERED_SET (1 << 8)
344 #define DB_FINE_LOCKED (1 << 9) /* write_concurrency */
345 #define DB_FREQ_READ (1 << 10) /* read_concurrency */
346 #define DB_NAMED_TABLE (1 << 11)
347 #define DB_BUSY (1 << 12)
348
349 #define DB_CATREE_FORCE_SPLIT (1 << 31) /* erts_debug */
350 #define DB_CATREE_DEBUG_RANDOM_SPLIT_JOIN (1 << 30) /* erts_debug */
351
352 #define IS_HASH_TABLE(Status) (!!((Status) & \
353 (DB_BAG | DB_SET | DB_DUPLICATE_BAG)))
354 #define IS_TREE_TABLE(Status) (!!((Status) & \
355 DB_ORDERED_SET))
356 #define IS_CATREE_TABLE(Status) (!!((Status) & \
357 DB_CA_ORDERED_SET))
358 #define NFIXED(T) (erts_refc_read(&(T)->common.fix_count,0))
359 #define IS_FIXED(T) (NFIXED(T) != 0)
360
361 #define META_DB_LOCK_FREE() (erts_no_schedulers == 1)
362 #define DB_LOCK_FREE(T) META_DB_LOCK_FREE()
363
364 /*
365 * tplp is an untagged pointer to a tuple we know is large enough
366 * and dth is a pointer to a DbTableHash.
367 */
368 #define GETKEY(dth, tplp) (*((tplp) + ((DbTableCommon*)(dth))->keypos))
369
370
371 ERTS_GLB_INLINE Eterm db_copy_key(Process* p, DbTable* tb, DbTerm* obj);
372 Eterm db_copy_from_comp(DbTableCommon* tb, DbTerm* bp, Eterm** hpp,
373 ErlOffHeap* off_heap);
374 int db_eq_comp(DbTableCommon* tb, Eterm a, DbTerm* b);
375 DbTerm* db_alloc_tmp_uncompressed(DbTableCommon* tb, DbTerm* org);
376 void db_free_tmp_uncompressed(DbTerm* obj);
377
378 ERTS_GLB_INLINE Eterm db_copy_object_from_ets(DbTableCommon* tb, DbTerm* bp,
379 Eterm** hpp, ErlOffHeap* off_heap);
380 ERTS_GLB_INLINE int db_eq(DbTableCommon* tb, Eterm a, DbTerm* b);
381 Wterm db_do_read_element(DbUpdateHandle* handle, Sint position);
382
383 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
384
db_copy_key(Process * p,DbTable * tb,DbTerm * obj)385 ERTS_GLB_INLINE Eterm db_copy_key(Process* p, DbTable* tb, DbTerm* obj)
386 {
387 Eterm key = GETKEY(tb, obj->tpl);
388 if IS_CONST(key) return key;
389 else {
390 Uint size = size_object(key);
391 Eterm* hp = HAlloc(p, size);
392 Eterm res = copy_struct(key, size, &hp, &MSO(p));
393 ASSERT(EQ(res,key));
394 return res;
395 }
396 }
397
db_copy_object_from_ets(DbTableCommon * tb,DbTerm * bp,Eterm ** hpp,ErlOffHeap * off_heap)398 ERTS_GLB_INLINE Eterm db_copy_object_from_ets(DbTableCommon* tb, DbTerm* bp,
399 Eterm** hpp, ErlOffHeap* off_heap)
400 {
401 if (tb->compress) {
402 return db_copy_from_comp(tb, bp, hpp, off_heap);
403 }
404 else {
405 return copy_shallow(bp->tpl, bp->size, hpp, off_heap);
406 }
407 }
408
db_eq(DbTableCommon * tb,Eterm a,DbTerm * b)409 ERTS_GLB_INLINE int db_eq(DbTableCommon* tb, Eterm a, DbTerm* b)
410 {
411 if (!tb->compress) {
412 return EQ(a, make_tuple(b->tpl));
413 }
414 else {
415 return db_eq_comp(tb, a, b);
416 }
417 }
418
419 #endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
420
421
422 #define DB_READ (DB_PROTECTED|DB_PUBLIC)
423 #define DB_WRITE DB_PUBLIC
424 #define DB_INFO (DB_PROTECTED|DB_PUBLIC|DB_PRIVATE)
425 #define DB_READ_TBL_STRUCT (DB_PROTECTED|DB_PUBLIC|DB_PRIVATE|DB_BUSY)
426
427 #define ONLY_WRITER(P,T) (((T)->common.status & (DB_PRIVATE|DB_PROTECTED)) \
428 && (T)->common.owner == (P)->common.id)
429
430 #define ONLY_READER(P,T) (((T)->common.status & DB_PRIVATE) && \
431 (T)->common.owner == (P)->common.id)
432
433 /* Function prototypes */
434 BIF_RETTYPE db_get_trace_control_word(Process* p);
435 BIF_RETTYPE db_set_trace_control_word(Process* p, Eterm tcw);
436 BIF_RETTYPE db_get_trace_control_word_0(BIF_ALIST_0);
437 BIF_RETTYPE db_set_trace_control_word_1(BIF_ALIST_1);
438
439 void db_initialize_util(void);
440 Eterm db_getkey(int keypos, Eterm obj);
441 void db_cleanup_offheap_comp(DbTerm* p);
442 void db_free_term(DbTable *tb, void* basep, Uint offset);
443 void db_free_term_no_tab(int compress, void* basep, Uint offset);
444 Uint db_term_size(DbTable *tb, void* basep, Uint offset);
445 void* db_store_term(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj);
446 void* db_store_term_comp(DbTableCommon *tb, /*May be NULL*/
447 int keypos,
448 DbTerm* old,
449 Uint offset,Eterm obj);
450 Eterm db_copy_element_from_ets(DbTableCommon* tb, Process* p, DbTerm* obj,
451 Uint pos, Eterm** hpp, Uint extra);
452 int db_has_map(Eterm obj);
453 int db_has_variable(Eterm obj);
454 int db_is_variable(Eterm obj);
455 void db_do_update_element(DbUpdateHandle* handle,
456 Sint position,
457 Eterm newval);
458 void db_finalize_resize(DbUpdateHandle* handle, Uint offset);
459 Eterm db_add_counter(Eterm** hpp, Wterm counter, Eterm incr);
460 Binary *db_match_set_compile(Process *p, Eterm matchexpr,
461 Uint flags, Uint *freasonp);
462 int db_match_keeps_key(int keypos, Eterm match, Eterm guard, Eterm body);
463 int erts_db_match_prog_destructor(Binary *);
464
465 typedef struct match_prog {
466 ErlHeapFragment *term_save; /* Only if needed, a list of message
467 buffers for off heap copies
468 (i.e. binaries)*/
469 int single_variable; /* ets:match needs to know this. */
470 int num_bindings; /* Size of heap */
471 /* The following two are only filled in when match specs
472 are used for tracing */
473 struct erl_heap_fragment *saved_program_buf;
474 Eterm saved_program;
475 Uint heap_size; /* size of: heap + eheap + stack */
476 Uint stack_offset;
477 #ifdef DMC_DEBUG
478 UWord* prog_end; /* End of program */
479 #endif
480 UWord text[1]; /* Beginning of program */
481 } MatchProg;
482
483 /*
484 * The heap-eheap-stack block of a MatchProg is nowadays allocated
485 * when the match program is run.
486 * - heap: variable bindings
487 * - eheap: erlang heap storage
488 * - eheap: a "large enough" stack
489 */
490
491 #define DMC_ERR_STR_LEN 100
492
493 typedef enum { dmcWarning, dmcError} DMCErrorSeverity;
494
495 typedef struct dmc_error {
496 char error_string[DMC_ERR_STR_LEN + 1]; /* printf format string
497 with %d for the variable
498 number (if applicable) */
499 int variable; /* -1 if no variable is referenced
500 in error string */
501 struct dmc_error *next;
502 DMCErrorSeverity severity; /* Error or warning */
503 } DMCError;
504
505 typedef struct dmc_err_info {
506 unsigned int *var_trans; /* Translations of variable names,
507 initiated to NULL
508 and free'd with sys_free if != NULL
509 after compilation */
510 int num_trans;
511 int error_added; /* indicates if the error list contains
512 any fatal errors (dmcError severity) */
513 DMCError *first; /* List of errors */
514 } DMCErrInfo;
515
516 /*
517 ** Compilation flags
518 **
519 ** The dialect is in the 3 least significant bits and are to be interspaced by
520 ** by at least 2 (decimal), thats why ((Uint) 2) isn't used. This is to be
521 ** able to add DBIF_GUARD or DBIF BODY to it to use in the match_spec bif
522 ** table. The rest of the word is used like ordinary flags, one bit for each
523 ** flag. Note that DCOMP_TABLE and DCOMP_TRACE are mutually exclusive.
524 */
525 #define DCOMP_TABLE ((Uint) 1) /* Ets and dets. The body returns a value,
526 * and the parameter to the execution is a tuple. */
527 #define DCOMP_TRACE ((Uint) 4) /* Trace. More functions are allowed, and the
528 * parameter to the execution will be an array. */
529 #define DCOMP_DIALECT_MASK ((Uint) 0x7) /* To mask out the bits marking
530 dialect */
531 #define DCOMP_FAKE_DESTRUCTIVE ((Uint) 8) /* When this is active, no setting of
532 trace control words or seq_trace tokens will be done. */
533
534 /* Allow lock seizing operations on the tracee and 3rd party processes */
535 #define DCOMP_ALLOW_TRACE_OPS ((Uint) 0x10)
536
537 /* This is call trace */
538 #define DCOMP_CALL_TRACE ((Uint) 0x20)
539
540 Binary *db_match_compile(Eterm *matchexpr, Eterm *guards,
541 Eterm *body, int num_matches,
542 Uint flags,
543 DMCErrInfo *err_info,
544 Uint *freasonp);
545 /* Returns newly allocated MatchProg binary with refc == 0*/
546
547 Eterm db_match_dbterm_uncompressed(DbTableCommon* tb, Process* c_p, Binary* bprog,
548 DbTerm* obj, Eterm** hpp, Uint extra);
549 Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog,
550 DbTerm* obj, Eterm** hpp, Uint extra);
551
552 Eterm db_prog_match(Process *p, Process *self,
553 Binary *prog, Eterm term,
554 Eterm *termp, int arity,
555 enum erts_pam_run_flags in_flags,
556 Uint32 *return_flags /* Zeroed on enter */);
557
558 /* returns DB_ERROR_NONE if matches, 1 if not matches and some db error on
559 error. */
560 DMCErrInfo *db_new_dmc_err_info(void);
561 /* Returns allocated error info, where errors are collected for lint. */
562 Eterm db_format_dmc_err_info(Process *p, DMCErrInfo *ei);
563 /* Formats an error info structure into a list of tuples. */
564 void db_free_dmc_err_info(DMCErrInfo *ei);
565 /* Completely free's an error info structure, including all recorded
566 errors */
567
568 ERTS_GLB_INLINE Eterm erts_db_make_match_prog_ref(Process *p, Binary *mp, Eterm **hpp);
569 ERTS_GLB_INLINE Binary *erts_db_get_match_prog_binary(Eterm term);
570 ERTS_GLB_INLINE Binary *erts_db_get_match_prog_binary_unchecked(Eterm term);
571
572 /** @brief Ensure off-heap header is word aligned, make a temporary copy if
573 * not. Needed when inspecting ETS off-heap lists that may contain unaligned
574 * ProcBins if table is 'compressed'.
575 */
576 struct erts_tmp_aligned_offheap
577 {
578 ProcBin proc_bin;
579 };
580 ERTS_GLB_INLINE void erts_align_offheap(union erl_off_heap_ptr*,
581 struct erts_tmp_aligned_offheap* tmp);
582
583 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
584
585 /*
586 * Convert a match program to a "magic" ref to return up to erlang
587 */
erts_db_make_match_prog_ref(Process * p,Binary * mp,Eterm ** hpp)588 ERTS_GLB_INLINE Eterm erts_db_make_match_prog_ref(Process *p, Binary *mp, Eterm **hpp)
589 {
590 return erts_mk_magic_ref(hpp, &MSO(p), mp);
591 }
592
593 ERTS_GLB_INLINE Binary *
erts_db_get_match_prog_binary_unchecked(Eterm term)594 erts_db_get_match_prog_binary_unchecked(Eterm term)
595 {
596 Binary *bp = erts_magic_ref2bin(term);
597 ASSERT(bp->intern.flags & BIN_FLAG_MAGIC);
598 ASSERT((ERTS_MAGIC_BIN_DESTRUCTOR(bp) == erts_db_match_prog_destructor));
599 return bp;
600 }
601
602 ERTS_GLB_INLINE Binary *
erts_db_get_match_prog_binary(Eterm term)603 erts_db_get_match_prog_binary(Eterm term)
604 {
605 Binary *bp;
606 if (!is_internal_magic_ref(term))
607 return NULL;
608 bp = erts_magic_ref2bin(term);
609 ASSERT(bp->intern.flags & BIN_FLAG_MAGIC);
610 if (ERTS_MAGIC_BIN_DESTRUCTOR(bp) != erts_db_match_prog_destructor)
611 return NULL;
612 return bp;
613 }
614
615 ERTS_GLB_INLINE void
erts_align_offheap(union erl_off_heap_ptr * ohp,struct erts_tmp_aligned_offheap * tmp)616 erts_align_offheap(union erl_off_heap_ptr* ohp,
617 struct erts_tmp_aligned_offheap* tmp)
618 {
619 if ((UWord)ohp->voidp % sizeof(UWord) != 0) {
620 /*
621 * ETS store word unaligned ProcBins in its compressed format.
622 * Make a temporary aligned copy.
623 *
624 * Warning, must pass (void*)-variable to memcpy. Otherwise it will
625 * cause Bus error on Sparc due to false compile time assumptions
626 * about word aligned memory (type cast is not enough).
627 */
628 sys_memcpy(tmp, ohp->voidp, sizeof(*tmp));
629 ASSERT(tmp->proc_bin.thing_word == HEADER_PROC_BIN);
630 ohp->pb = &tmp->proc_bin;
631 }
632 }
633
634 #endif
635
636 /*
637 ** Convenience when compiling into Binary structures
638 */
639 #define IsMatchProgBinary(BP) \
640 (((BP)->intern.flags & BIN_FLAG_MAGIC) \
641 && ERTS_MAGIC_BIN_DESTRUCTOR((BP)) == erts_db_match_prog_destructor)
642
643 #define Binary2MatchProg(BP) \
644 (ASSERT(IsMatchProgBinary((BP))), \
645 ((MatchProg *) ERTS_MAGIC_BIN_DATA((BP))))
646
647 #endif /* _DB_UTIL_H */
648