aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_binary.h
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/erl_binary.h')
-rw-r--r--erts/emulator/beam/erl_binary.h282
1 files changed, 282 insertions, 0 deletions
diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h
new file mode 100644
index 0000000000..dc5539faad
--- /dev/null
+++ b/erts/emulator/beam/erl_binary.h
@@ -0,0 +1,282 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2000-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef __ERL_BINARY_H
+#define __ERL_BINARY_H
+
+#include "erl_threads.h"
+
+/*
+ * Maximum number of bytes to place in a heap binary.
+ */
+
+#define ERL_ONHEAP_BIN_LIMIT 64
+
+/*
+ * This structure represents a SUB_BINARY.
+ *
+ * Note: The last field (orig) is not counted in arityval in the header.
+ * This simplifies garbage collection.
+ */
+
+typedef struct erl_sub_bin {
+ Eterm thing_word; /* Subtag SUB_BINARY_SUBTAG. */
+ Uint size; /* Binary size in bytes. */
+ Uint offs; /* Offset into original binary. */
+ byte bitsize;
+ byte bitoffs;
+ byte is_writable; /* The underlying binary is writable */
+ Eterm orig; /* Original binary (REFC or HEAP binary). */
+} ErlSubBin;
+
+#define ERL_SUB_BIN_SIZE (sizeof(ErlSubBin)/sizeof(Eterm))
+#define HEADER_SUB_BIN _make_header(ERL_SUB_BIN_SIZE-2,_TAG_HEADER_SUB_BIN)
+
+/*
+ * This structure represents a HEAP_BINARY.
+ */
+
+typedef struct erl_heap_bin {
+ Eterm thing_word; /* Subtag HEAP_BINARY_SUBTAG. */
+ Uint size; /* Binary size in bytes. */
+ Eterm data[1]; /* The data in the binary. */
+} ErlHeapBin;
+
+#define heap_bin_size(num_bytes) \
+ (sizeof(ErlHeapBin)/sizeof(Eterm) - 1 + \
+ ((num_bytes)+sizeof(Eterm)-1)/sizeof(Eterm))
+
+#define header_heap_bin(num_bytes) \
+ _make_header(heap_bin_size(num_bytes)-1,_TAG_HEADER_HEAP_BIN)
+
+/*
+ * Get the size in bytes of any type of binary.
+ */
+
+#define binary_size(Bin) (binary_val(Bin)[1])
+
+#define binary_bitsize(Bin) \
+ ((*binary_val(Bin) == HEADER_SUB_BIN) ? \
+ ((ErlSubBin *) binary_val(Bin))->bitsize: \
+ 0)
+
+#define binary_bitoffset(Bin) \
+ ((*binary_val(Bin) == HEADER_SUB_BIN) ? \
+ ((ErlSubBin *) binary_val(Bin))->bitoffs: \
+ 0)
+
+/*
+ * Get the pointer to the actual data bytes in a binary.
+ * Works for any type of binary. Always use binary_bytes() if
+ * you know that the binary cannot be a sub binary.
+ *
+ * Bin: input variable (Eterm)
+ * Bytep: output variable (byte *)
+ * Bitoffs: output variable (Uint)
+ * Bitsize: output variable (Uint)
+ */
+
+#define ERTS_GET_BINARY_BYTES(Bin,Bytep,Bitoffs,Bitsize) \
+do { \
+ Eterm* _real_bin = binary_val(Bin); \
+ Uint _offs = 0; \
+ Bitoffs = Bitsize = 0; \
+ if (*_real_bin == HEADER_SUB_BIN) { \
+ ErlSubBin* _sb = (ErlSubBin *) _real_bin; \
+ _offs = _sb->offs; \
+ Bitoffs = _sb->bitoffs; \
+ Bitsize = _sb->bitsize; \
+ _real_bin = binary_val(_sb->orig); \
+ } \
+ if (*_real_bin == HEADER_PROC_BIN) { \
+ Bytep = ((ProcBin *) _real_bin)->bytes + _offs; \
+ } else { \
+ Bytep = (byte *)(&(((ErlHeapBin *) _real_bin)->data)) + _offs; \
+ } \
+} while (0)
+
+/*
+ * Get the real binary from any binary type, where "real" means
+ * a REFC or HEAP binary. Also get the byte and bit offset into the
+ * real binary. Useful if you want to build a SUB binary from
+ * any binary.
+ *
+ * Bin: Input variable (Eterm)
+ * RealBin: Output variable (Eterm)
+ * ByteOffset: Output variable (Uint)
+ * BitOffset: Offset in bits (Uint)
+ * BitSize: Extra bit size (Uint)
+ */
+
+#define ERTS_GET_REAL_BIN(Bin, RealBin, ByteOffset, BitOffset, BitSize) \
+ do { \
+ ErlSubBin* _sb = (ErlSubBin *) binary_val(Bin); \
+ if (_sb->thing_word == HEADER_SUB_BIN) { \
+ RealBin = _sb->orig; \
+ ByteOffset = _sb->offs; \
+ BitOffset = _sb->bitoffs; \
+ BitSize = _sb->bitsize; \
+ } else { \
+ RealBin = Bin; \
+ ByteOffset = BitOffset = BitSize = 0; \
+ } \
+ } while (0)
+
+/*
+ * Get a pointer to the binary bytes, for a heap or refc binary
+ * (NOT sub binary).
+ */
+#define binary_bytes(Bin) \
+ (*binary_val(Bin) == HEADER_PROC_BIN ? \
+ ((ProcBin *) binary_val(Bin))->bytes : \
+ (ASSERT_EXPR(thing_subtag(*binary_val(Bin)) == HEAP_BINARY_SUBTAG), \
+ (byte *)(&(((ErlHeapBin *) binary_val(Bin))->data))))
+
+void erts_init_binary(void);
+
+byte* erts_get_aligned_binary_bytes(Eterm, byte**);
+
+#if defined(__i386__) || !defined(__GNUC__)
+/*
+ * Doubles aren't required to be 8-byte aligned on intel x86.
+ * (if not gnuc we don't know if __i386__ is defined on x86;
+ * therefore, assume intel x86...)
+ */
+# define ERTS_BIN_ALIGNMENT_MASK ((Uint) 3)
+#else
+# define ERTS_BIN_ALIGNMENT_MASK ((Uint) 7)
+#endif
+
+#define ERTS_CHK_BIN_ALIGNMENT(B) \
+ do { ASSERT(!(B) || (((Uint) &((Binary *)(B))->orig_bytes[0]) & ERTS_BIN_ALIGNMENT_MASK) == ((Uint) 0)) } while(0)
+
+ERTS_GLB_INLINE void erts_free_aligned_binary_bytes(byte* buf);
+ERTS_GLB_INLINE Binary *erts_bin_drv_alloc_fnf(Uint size);
+ERTS_GLB_INLINE Binary *erts_bin_drv_alloc(Uint size);
+ERTS_GLB_INLINE Binary *erts_bin_nrml_alloc(Uint size);
+ERTS_GLB_INLINE Binary *erts_bin_realloc_fnf(Binary *bp, Uint size);
+ERTS_GLB_INLINE Binary *erts_bin_realloc(Binary *bp, Uint size);
+ERTS_GLB_INLINE void erts_bin_free(Binary *bp);
+ERTS_GLB_INLINE Binary *erts_create_magic_binary(Uint size,
+ void (*destructor)(Binary *));
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE void
+erts_free_aligned_binary_bytes(byte* buf)
+{
+ if (buf) {
+ erts_free(ERTS_ALC_T_TMP, (void *) buf);
+ }
+}
+
+ERTS_GLB_INLINE Binary *
+erts_bin_drv_alloc_fnf(Uint size)
+{
+ Uint bsize = sizeof(Binary) - 1 + size;
+ void *res;
+ res = erts_alloc_fnf(ERTS_ALC_T_DRV_BINARY, bsize);
+ ERTS_CHK_BIN_ALIGNMENT(res);
+ return (Binary *) res;
+}
+
+ERTS_GLB_INLINE Binary *
+erts_bin_drv_alloc(Uint size)
+{
+ Uint bsize = sizeof(Binary) - 1 + size;
+ void *res;
+ res = erts_alloc(ERTS_ALC_T_DRV_BINARY, bsize);
+ ERTS_CHK_BIN_ALIGNMENT(res);
+ return (Binary *) res;
+}
+
+
+ERTS_GLB_INLINE Binary *
+erts_bin_nrml_alloc(Uint size)
+{
+ Uint bsize = sizeof(Binary) - 1 + size;
+ void *res;
+ res = erts_alloc(ERTS_ALC_T_BINARY, bsize);
+ ERTS_CHK_BIN_ALIGNMENT(res);
+ return (Binary *) res;
+}
+
+ERTS_GLB_INLINE Binary *
+erts_bin_realloc_fnf(Binary *bp, Uint size)
+{
+ Binary *nbp;
+ Uint bsize = sizeof(Binary) - 1 + size;
+ ASSERT((bp->flags & BIN_FLAG_MAGIC) == 0);
+ if (bp->flags & BIN_FLAG_DRV)
+ nbp = erts_realloc_fnf(ERTS_ALC_T_DRV_BINARY, (void *) bp, bsize);
+ else
+ nbp = erts_realloc_fnf(ERTS_ALC_T_BINARY, (void *) bp, bsize);
+ ERTS_CHK_BIN_ALIGNMENT(nbp);
+ return nbp;
+}
+
+ERTS_GLB_INLINE Binary *
+erts_bin_realloc(Binary *bp, Uint size)
+{
+ Binary *nbp;
+ Uint bsize = sizeof(Binary) - 1 + size;
+ ASSERT((bp->flags & BIN_FLAG_MAGIC) == 0);
+ if (bp->flags & BIN_FLAG_DRV)
+ nbp = erts_realloc_fnf(ERTS_ALC_T_DRV_BINARY, (void *) bp, bsize);
+ else
+ nbp = erts_realloc_fnf(ERTS_ALC_T_BINARY, (void *) bp, bsize);
+ if (!nbp)
+ erts_realloc_n_enomem(ERTS_ALC_T2N(bp->flags & BIN_FLAG_DRV
+ ? ERTS_ALC_T_DRV_BINARY
+ : ERTS_ALC_T_BINARY),
+ bp,
+ bsize);
+ ERTS_CHK_BIN_ALIGNMENT(nbp);
+ return nbp;
+}
+
+ERTS_GLB_INLINE void
+erts_bin_free(Binary *bp)
+{
+ if (bp->flags & BIN_FLAG_MAGIC)
+ ERTS_MAGIC_BIN_DESTRUCTOR(bp)(bp);
+ if (bp->flags & BIN_FLAG_DRV)
+ erts_free(ERTS_ALC_T_DRV_BINARY, (void *) bp);
+ else
+ erts_free(ERTS_ALC_T_BINARY, (void *) bp);
+}
+
+ERTS_GLB_INLINE Binary *
+erts_create_magic_binary(Uint size, void (*destructor)(Binary *))
+{
+ Uint bsize = sizeof(Binary) - 1 + sizeof(ErtsBinaryMagicPart) - 1 + size;
+ Binary* bptr = erts_alloc_fnf(ERTS_ALC_T_BINARY, bsize);
+ if (!bptr)
+ erts_alloc_n_enomem(ERTS_ALC_T2N(ERTS_ALC_T_BINARY), bsize);
+ ERTS_CHK_BIN_ALIGNMENT(bptr);
+ bptr->flags = BIN_FLAG_MAGIC;
+ bptr->orig_size = sizeof(ErtsBinaryMagicPart) - 1 + size;
+ erts_refc_init(&bptr->refc, 0);
+ ERTS_MAGIC_BIN_DESTRUCTOR(bptr) = destructor;
+ return bptr;
+}
+
+#endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
+
+#endif