diff options
Diffstat (limited to 'erts/emulator/beam/erl_term.h')
-rw-r--r-- | erts/emulator/beam/erl_term.h | 1056 |
1 files changed, 1056 insertions, 0 deletions
diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h new file mode 100644 index 0000000000..b0a57a3ebe --- /dev/null +++ b/erts/emulator/beam/erl_term.h @@ -0,0 +1,1056 @@ +/* + * %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_TERM_H +#define __ERL_TERM_H + +struct erl_node_; /* Declared in erl_node_tables.h */ + +/* + * Defining ET_DEBUG to 1 causes all type-specific data access + * macros to perform runtime type checking. This is very useful + * during development but reduces performance, so ET_DEBUG should + * be disabled during benchmarking or release. + */ +/* #define ET_DEBUG 1 */ +#ifndef ET_DEBUG +# ifdef DEBUG +# define ET_DEBUG 1 +# else +# define ET_DEBUG 0 +# endif +#endif + +#if ET_DEBUG +#define _ET_DECLARE_CHECKED(TF,F,TX) extern TF checked_##F(TX,const char*,unsigned) +#define _ET_APPLY(F,X) checked_##F(X,__FILE__,__LINE__) +#else +#define _ET_DECLARE_CHECKED(TF,F,TX) +#define _ET_APPLY(F,X) _unchecked_##F(X) +#endif + +#define _TAG_PRIMARY_SIZE 2 +#define _TAG_PRIMARY_MASK 0x3 +#define TAG_PRIMARY_HEADER 0x0 +#define TAG_PRIMARY_LIST 0x1 +#define TAG_PRIMARY_BOXED 0x2 +#define TAG_PRIMARY_IMMED1 0x3 + +#define primary_tag(x) ((x) & _TAG_PRIMARY_MASK) + +#define _TAG_IMMED1_SIZE 4 +#define _TAG_IMMED1_MASK 0xF +#define _TAG_IMMED1_PID ((0x0 << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_IMMED1) +#define _TAG_IMMED1_PORT ((0x1 << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_IMMED1) +#define _TAG_IMMED1_IMMED2 ((0x2 << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_IMMED1) +#define _TAG_IMMED1_SMALL ((0x3 << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_IMMED1) + +#define _TAG_IMMED2_SIZE 6 +#define _TAG_IMMED2_MASK 0x3F +#define _TAG_IMMED2_ATOM ((0x0 << _TAG_IMMED1_SIZE) | _TAG_IMMED1_IMMED2) +#define _TAG_IMMED2_CATCH ((0x1 << _TAG_IMMED1_SIZE) | _TAG_IMMED1_IMMED2) +#define _TAG_IMMED2_NIL ((0x3 << _TAG_IMMED1_SIZE) | _TAG_IMMED1_IMMED2) + +/* + * HEADER representation: + * + * aaaaaaaaaaaaaaaaaaaaaaaaaatttt00 arity:26, tag:4 + * + * HEADER tags: + * + * 0000 ARITYVAL + * 0001 BINARY_AGGREGATE | + * 001x BIGNUM with sign bit | + * 0100 REF | + * 0101 FUN | THINGS + * 0110 FLONUM | + * 0111 EXPORT | + * 1000 REFC_BINARY | | + * 1001 HEAP_BINARY | BINARIES | + * 1010 SUB_BINARY | | + * 1011 Not used + * 1100 EXTERNAL_PID | | + * 1101 EXTERNAL_PORT | EXTERNAL THINGS | + * 1110 EXTERNAL_REF | | + * 1111 Not used + * + * COMMENTS: + * + * - The tag is zero for arityval and non-zero for thing headers. + * - A single bit differentiates between positive and negative bignums. + * - If more tags are needed, the REF and and EXTERNAL_REF tags could probably + * be combined to one tag. + * + * XXX: globally replace XXX_SUBTAG with TAG_HEADER_XXX + */ +#define ARITYVAL_SUBTAG (0x0 << _TAG_PRIMARY_SIZE) /* TUPLE */ +#define BIN_MATCHSTATE_SUBTAG (0x1 << _TAG_PRIMARY_SIZE) +#define POS_BIG_SUBTAG (0x2 << _TAG_PRIMARY_SIZE) /* BIG: tags 2&3 */ +#define NEG_BIG_SUBTAG (0x3 << _TAG_PRIMARY_SIZE) /* BIG: tags 2&3 */ +#define _BIG_SIGN_BIT (0x1 << _TAG_PRIMARY_SIZE) +#define REF_SUBTAG (0x4 << _TAG_PRIMARY_SIZE) /* REF */ +#define FUN_SUBTAG (0x5 << _TAG_PRIMARY_SIZE) /* FUN */ +#define FLOAT_SUBTAG (0x6 << _TAG_PRIMARY_SIZE) /* FLOAT */ +#define EXPORT_SUBTAG (0x7 << _TAG_PRIMARY_SIZE) /* FLOAT */ +#define _BINARY_XXX_MASK (0x3 << _TAG_PRIMARY_SIZE) +#define REFC_BINARY_SUBTAG (0x8 << _TAG_PRIMARY_SIZE) /* BINARY */ +#define HEAP_BINARY_SUBTAG (0x9 << _TAG_PRIMARY_SIZE) /* BINARY */ +#define SUB_BINARY_SUBTAG (0xA << _TAG_PRIMARY_SIZE) /* BINARY */ +#define EXTERNAL_PID_SUBTAG (0xC << _TAG_PRIMARY_SIZE) /* EXTERNAL_PID */ +#define EXTERNAL_PORT_SUBTAG (0xD << _TAG_PRIMARY_SIZE) /* EXTERNAL_PORT */ +#define EXTERNAL_REF_SUBTAG (0xE << _TAG_PRIMARY_SIZE) /* EXTERNAL_REF */ + + +#define _TAG_HEADER_ARITYVAL (TAG_PRIMARY_HEADER|ARITYVAL_SUBTAG) +#define _TAG_HEADER_FUN (TAG_PRIMARY_HEADER|FUN_SUBTAG) +#define _TAG_HEADER_POS_BIG (TAG_PRIMARY_HEADER|POS_BIG_SUBTAG) +#define _TAG_HEADER_NEG_BIG (TAG_PRIMARY_HEADER|NEG_BIG_SUBTAG) +#define _TAG_HEADER_FLOAT (TAG_PRIMARY_HEADER|FLOAT_SUBTAG) +#define _TAG_HEADER_EXPORT (TAG_PRIMARY_HEADER|EXPORT_SUBTAG) +#define _TAG_HEADER_REF (TAG_PRIMARY_HEADER|REF_SUBTAG) +#define _TAG_HEADER_REFC_BIN (TAG_PRIMARY_HEADER|REFC_BINARY_SUBTAG) +#define _TAG_HEADER_HEAP_BIN (TAG_PRIMARY_HEADER|HEAP_BINARY_SUBTAG) +#define _TAG_HEADER_SUB_BIN (TAG_PRIMARY_HEADER|SUB_BINARY_SUBTAG) +#define _TAG_HEADER_EXTERNAL_PID (TAG_PRIMARY_HEADER|EXTERNAL_PID_SUBTAG) +#define _TAG_HEADER_EXTERNAL_PORT (TAG_PRIMARY_HEADER|EXTERNAL_PORT_SUBTAG) +#define _TAG_HEADER_EXTERNAL_REF (TAG_PRIMARY_HEADER|EXTERNAL_REF_SUBTAG) +#define _TAG_HEADER_BIN_MATCHSTATE (TAG_PRIMARY_HEADER|BIN_MATCHSTATE_SUBTAG) + + +#define _TAG_HEADER_MASK 0x3F +#define _HEADER_SUBTAG_MASK 0x3C /* 4 bits for subtag */ +#define _HEADER_ARITY_OFFS 6 + +#define header_is_transparent(x) \ + (((x) & (_HEADER_SUBTAG_MASK)) == ARITYVAL_SUBTAG) +#define header_is_arityval(x) (((x) & _HEADER_SUBTAG_MASK) == ARITYVAL_SUBTAG) +#define header_is_thing(x) (!header_is_transparent((x))) +#define header_is_bin_matchstate(x) ((((x) & (_HEADER_SUBTAG_MASK)) == BIN_MATCHSTATE_SUBTAG)) + +#define _CPMASK 0x3 + +/* immediate object access methods */ +#define is_immed(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_IMMED1) +#define is_not_immed(x) (!is_immed((x))) +#define IS_CONST(x) is_immed((x)) +#if TAG_PRIMARY_IMMED1 == _TAG_PRIMARY_MASK +#define is_both_immed(x,y) is_immed(((x)&(y))) +#else +#define is_both_immed(x,y) (is_immed((x)) && is_immed((y))) +#endif +#define is_not_both_immed(x,y) (!is_both_immed((x),(y))) + + +/* boxed object access methods */ +#define _is_aligned(x) (((Uint)(x) & 0x3) == 0) +#define _unchecked_make_boxed(x) ((Uint)(x) + TAG_PRIMARY_BOXED) +_ET_DECLARE_CHECKED(Eterm,make_boxed,Eterm*); +#define make_boxed(x) _ET_APPLY(make_boxed,(x)) +#if 1 +#define _is_not_boxed(x) ((x) & (_TAG_PRIMARY_MASK-TAG_PRIMARY_BOXED)) +#define _unchecked_is_boxed(x) (!_is_not_boxed((x))) +_ET_DECLARE_CHECKED(int,is_boxed,Eterm); +#define is_boxed(x) _ET_APPLY(is_boxed,(x)) +#else +#define is_boxed(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_BOXED) +#endif +#define _unchecked_boxed_val(x) ((Eterm*)((x) - TAG_PRIMARY_BOXED)) +_ET_DECLARE_CHECKED(Eterm*,boxed_val,Eterm); +#define boxed_val(x) _ET_APPLY(boxed_val,(x)) + +/* cons cell ("list") access methods */ +#define _unchecked_make_list(x) ((Uint)(x) + TAG_PRIMARY_LIST) +_ET_DECLARE_CHECKED(Eterm,make_list,Eterm*); +#define make_list(x) _ET_APPLY(make_list,(x)) +#if 1 +#define _unchecked_is_not_list(x) ((x) & (_TAG_PRIMARY_MASK-TAG_PRIMARY_LIST)) +_ET_DECLARE_CHECKED(int,is_not_list,Eterm); +#define is_not_list(x) _ET_APPLY(is_not_list,(x)) +#define is_list(x) (!is_not_list((x))) +#else +#define is_list(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_LIST) +#define is_not_list(x) (!is_list((x))) +#endif +#define _unchecked_list_val(x) ((Eterm*)((x) - TAG_PRIMARY_LIST)) +_ET_DECLARE_CHECKED(Eterm*,list_val,Eterm); +#define list_val(x) _ET_APPLY(list_val,(x)) + +#define CONS(hp, car, cdr) \ + (CAR(hp)=(car), CDR(hp)=(cdr), make_list(hp)) + +#define CAR(x) ((x)[0]) +#define CDR(x) ((x)[1]) + +/* generic tagged pointer (boxed or list) access methods */ +#define _unchecked_ptr_val(x) ((Eterm*)((x) & ~((Uint) 0x3))) +#define ptr_val(x) _unchecked_ptr_val((x)) /*XXX*/ +#define _unchecked_offset_ptr(x,offs) ((x)+((offs)*sizeof(Eterm))) +#define offset_ptr(x,offs) _unchecked_offset_ptr(x,offs) /*XXX*/ + +/* fixnum ("small") access methods */ +#if defined(ARCH_64) +#define SMALL_BITS (64-4) +#define SMALL_DIGITS (17) +#else +#define SMALL_BITS (28) +#define SMALL_DIGITS (8) +#endif +#define MAX_SMALL ((1L << (SMALL_BITS-1))-1) +#define MIN_SMALL (-(1L << (SMALL_BITS-1))) +#define make_small(x) (((Uint)(x) << _TAG_IMMED1_SIZE) + _TAG_IMMED1_SMALL) +#define is_small(x) (((x) & _TAG_IMMED1_MASK) == _TAG_IMMED1_SMALL) +#define is_not_small(x) (!is_small((x))) +#define is_byte(x) (((x) & ((~(Uint)0 << (_TAG_IMMED1_SIZE+8)) + _TAG_IMMED1_MASK)) == _TAG_IMMED1_SMALL) +#define is_valid_bit_size(x) (((Sint)(x)) >= 0 && ((x) & 0x7F) == _TAG_IMMED1_SMALL) +#define is_not_valid_bit_size(x) (!is_valid_bit_size((x))) +#define MY_IS_SSMALL(x) (((Uint) (((x) >> (SMALL_BITS-1)) + 1)) < 2) +#define _unchecked_unsigned_val(x) ((x) >> _TAG_IMMED1_SIZE) +_ET_DECLARE_CHECKED(Uint,unsigned_val,Eterm); +#define unsigned_val(x) _ET_APPLY(unsigned_val,(x)) +#define _unchecked_signed_val(x) ((Sint)(x) >> _TAG_IMMED1_SIZE) +_ET_DECLARE_CHECKED(Sint,signed_val,Eterm); +#define signed_val(x) _ET_APPLY(signed_val,(x)) + +#if _TAG_IMMED1_SMALL == 0x0F +#define is_both_small(x,y) (((x) & (y) & _TAG_IMMED1_MASK) == _TAG_IMMED1_SMALL) +#elif _TAG_IMMED1_SMALL == 0x00 +#define is_both_small(x,y) ((((x)|(y)) & _TAG_IMMED1_MASK) == _TAG_IMMED1_SMALL) +#else +#define is_both_small(x,y) (is_small(x) && is_small(y)) +#endif + +/* NIL access methods */ +#define NIL ((~((Uint) 0) << _TAG_IMMED2_SIZE) | _TAG_IMMED2_NIL) +#define is_nil(x) ((x) == NIL) +#define is_not_nil(x) ((x) != NIL) + +#define MAX_ATOM_INDEX (~(~((Uint) 0) << (sizeof(Uint)*8 - _TAG_IMMED2_SIZE))) + +/* atom access methods */ +#define make_atom(x) ((Eterm)(((x) << _TAG_IMMED2_SIZE) + _TAG_IMMED2_ATOM)) +#define is_atom(x) (((x) & _TAG_IMMED2_MASK) == _TAG_IMMED2_ATOM) +#define is_not_atom(x) (!is_atom(x)) +#define _unchecked_atom_val(x) ((x) >> _TAG_IMMED2_SIZE) +_ET_DECLARE_CHECKED(Uint,atom_val,Eterm); +#define atom_val(x) _ET_APPLY(atom_val,(x)) + +/* header (arityval or thing) access methods */ +#define _make_header(sz,tag) ((Uint)(((sz) << _HEADER_ARITY_OFFS) + (tag))) +#define is_header(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_HEADER) +#define _unchecked_header_arity(x) ((x) >> _HEADER_ARITY_OFFS) +_ET_DECLARE_CHECKED(Uint,header_arity,Eterm); +#define header_arity(x) _ET_APPLY(header_arity,(x)) + +/* arityval access methods */ +#define make_arityval(sz) _make_header((sz),_TAG_HEADER_ARITYVAL) +#define is_arity_value(x) (((x) & _TAG_HEADER_MASK) == _TAG_HEADER_ARITYVAL) +#define is_not_arity_value(x) (!is_arity_value((x))) +#define _unchecked_arityval(x) _unchecked_header_arity((x)) +_ET_DECLARE_CHECKED(Uint,arityval,Eterm); +#define arityval(x) _ET_APPLY(arityval,(x)) + +/* thing access methods */ +#define is_thing(x) (is_header((x)) && header_is_thing((x))) +#define _unchecked_thing_arityval(x) _unchecked_header_arity((x)) +_ET_DECLARE_CHECKED(Uint,thing_arityval,Eterm); +#define thing_arityval(x) _ET_APPLY(thing_arityval,(x)) +#define _unchecked_thing_subtag(x) ((x) & _HEADER_SUBTAG_MASK) +_ET_DECLARE_CHECKED(Uint,thing_subtag,Eterm); +#define thing_subtag(x) _ET_APPLY(thing_subtag,(x)) + +/* + * Magic non-value object. + * Used as function return error and "absent value" indicator + * in the original runtime system. The new runtime system also + * uses it as forwarding marker for CONS cells. + * + * This value is 0 in the original runtime system, which unfortunately + * promotes sloppy programming practices. It also prevents some useful + * tag assignment schemes, e.g. using a 2-bit tag 00 for FIXNUM. + * + * To help find code which makes unwarranted assumptions about zero, + * we now use a non-zero bit-pattern in debug mode. + */ +#if ET_DEBUG +#define THE_NON_VALUE _make_header(0,_TAG_HEADER_FLOAT) +#else +#define THE_NON_VALUE (0) +#endif +#define is_non_value(x) ((x) == THE_NON_VALUE) +#define is_value(x) ((x) != THE_NON_VALUE) + +/* binary object access methods */ +#define is_binary_header(x) (((x) & (_TAG_HEADER_MASK-_BINARY_XXX_MASK)) == _TAG_HEADER_REFC_BIN) +#define make_binary(x) make_boxed((Eterm*)(x)) +#define is_binary(x) (is_boxed((x)) && is_binary_header(*boxed_val((x)))) +#define is_not_binary(x) (!is_binary((x))) +#define _unchecked_binary_val(x) _unchecked_boxed_val((x)) +_ET_DECLARE_CHECKED(Eterm*,binary_val,Eterm); +#define binary_val(x) _ET_APPLY(binary_val,(x)) + +/* process binaries stuff (special case of binaries) */ +#define HEADER_PROC_BIN _make_header(PROC_BIN_SIZE-1,_TAG_HEADER_REFC_BIN) + +/* fun & export objects */ +#define is_any_fun(x) (is_fun((x)) || is_export((x))) +#define is_not_any_fun(x) (!is_any_fun((x))) + +/* fun objects */ +#define HEADER_FUN _make_header(ERL_FUN_SIZE-2,_TAG_HEADER_FUN) +#define is_fun_header(x) ((x) == HEADER_FUN) +#define make_fun(x) make_boxed((Eterm*)(x)) +#define is_fun(x) (is_boxed((x)) && is_fun_header(*boxed_val((x)))) +#define is_not_fun(x) (!is_fun((x))) +#define _unchecked_fun_val(x) _unchecked_boxed_val((x)) +_ET_DECLARE_CHECKED(Eterm*,fun_val,Eterm); +#define fun_val(x) _ET_APPLY(fun_val,(x)) + +/* export access methods */ +#define make_export(x) make_boxed((x)) +#define is_export(x) (is_boxed((x)) && is_export_header(*boxed_val((x)))) +#define is_not_export(x) (!is_export((x))) +#define _unchecked_export_val(x) _unchecked_boxed_val(x) +_ET_DECLARE_CHECKED(Eterm*,export_val,Eterm); +#define export_val(x) _ET_APPLY(export_val,(x)) +#define is_export_header(x) ((x) == HEADER_EXPORT) +#define HEADER_EXPORT _make_header(1,_TAG_HEADER_EXPORT) + +/* bignum access methods */ +#define make_pos_bignum_header(sz) _make_header((sz),_TAG_HEADER_POS_BIG) +#define make_neg_bignum_header(sz) _make_header((sz),_TAG_HEADER_NEG_BIG) +#define _is_bignum_header(x) (((x) & (_TAG_HEADER_MASK-_BIG_SIGN_BIT)) == _TAG_HEADER_POS_BIG) +#define _unchecked_bignum_header_is_neg(x) ((x) & _BIG_SIGN_BIT) +_ET_DECLARE_CHECKED(int,bignum_header_is_neg,Eterm); +#define bignum_header_is_neg(x) _ET_APPLY(bignum_header_is_neg,(x)) +#define _unchecked_bignum_header_neg(x) ((x) | _BIG_SIGN_BIT) +_ET_DECLARE_CHECKED(Eterm,bignum_header_neg,Eterm); +#define bignum_header_neg(x) _ET_APPLY(bignum_header_neg,(x)) +#define _unchecked_bignum_header_arity(x) _unchecked_header_arity((x)) +_ET_DECLARE_CHECKED(Uint,bignum_header_arity,Eterm); +#define bignum_header_arity(x) _ET_APPLY(bignum_header_arity,(x)) +#define BIG_ARITY_MAX ((1 << 19)-1) +#define make_big(x) make_boxed((x)) +#define is_big(x) (is_boxed((x)) && _is_bignum_header(*boxed_val((x)))) +#define is_not_big(x) (!is_big((x))) +#define _unchecked_big_val(x) _unchecked_boxed_val((x)) +_ET_DECLARE_CHECKED(Eterm*,big_val,Eterm); +#define big_val(x) _ET_APPLY(big_val,(x)) + +/* flonum ("float") access methods */ +#ifdef ARCH_64 +#define HEADER_FLONUM _make_header(1,_TAG_HEADER_FLOAT) +#else +#define HEADER_FLONUM _make_header(2,_TAG_HEADER_FLOAT) +#endif +#define make_float(x) make_boxed((x)) +#define is_float(x) (is_boxed((x)) && *boxed_val((x)) == HEADER_FLONUM) +#define is_not_float(x) (!is_float(x)) +#define _unchecked_float_val(x) _unchecked_boxed_val((x)) +_ET_DECLARE_CHECKED(Eterm*,float_val,Eterm); +#define float_val(x) _ET_APPLY(float_val,(x)) + +/* Float definition for byte and word access */ +typedef double ieee754_8; + +typedef union float_def +{ + ieee754_8 fd; + byte fb[sizeof(ieee754_8)]; + Uint16 fs[sizeof(ieee754_8) / sizeof(Uint16)]; + Uint32 fw[sizeof(ieee754_8) / sizeof(Uint32)]; +#ifdef ARCH_64 + Uint fdw; +#endif +} FloatDef; + +#ifdef ARCH_64 +#define GET_DOUBLE(x, f) (f).fdw = *(float_val(x)+1) + +#define PUT_DOUBLE(f, x) *(x) = HEADER_FLONUM, \ + *((x)+1) = (f).fdw +#define GET_DOUBLE_DATA(p, f) (f).fdw = *((Uint *) (p)) +#define PUT_DOUBLE_DATA(f,p) *((Uint *) (p)) = (f).fdw +#else +#define GET_DOUBLE(x, f) (f).fw[0] = *(float_val(x)+1), \ + (f).fw[1] = *(float_val(x)+2) + +#define PUT_DOUBLE(f, x) *(x) = HEADER_FLONUM, \ + *((x)+1) = (f).fw[0], \ + *((x)+2) = (f).fw[1] +#define GET_DOUBLE_DATA(p, f) (f).fw[0] = *((Uint *) (p)),\ + (f).fw[1] = *(((Uint *) (p))+1) +#define PUT_DOUBLE_DATA(f,p) *((Uint *) (p)) = (f).fw[0],\ + *(((Uint *) (p))+1) = (f).fw[1] +#endif +#define DOUBLE_DATA_WORDS (sizeof(ieee754_8)/sizeof(Eterm)) +#define FLOAT_SIZE_OBJECT (DOUBLE_DATA_WORDS+1) + +/* tuple access methods */ +#define make_tuple(x) make_boxed((x)) +#define is_tuple(x) (is_boxed((x)) && is_arity_value(*boxed_val((x)))) +#define is_not_tuple(x) (!is_tuple((x))) +#define is_tuple_arity(x, a) \ + (is_boxed((x)) && *boxed_val((x)) == make_arityval((a))) +#define is_not_tuple_arity(x, a) (!is_tuple_arity((x),(a))) +#define _unchecked_tuple_val(x) _unchecked_boxed_val(x) +_ET_DECLARE_CHECKED(Eterm*,tuple_val,Eterm); +#define tuple_val(x) _ET_APPLY(tuple_val,(x)) + +#define TUPLE0(t) \ + ((t)[0] = make_arityval(0), \ + make_tuple(t)) +#define TUPLE1(t,e1) \ + ((t)[0] = make_arityval(1), \ + (t)[1] = (e1), \ + make_tuple(t)) +#define TUPLE2(t,e1,e2) \ + ((t)[0] = make_arityval(2), \ + (t)[1] = (e1), \ + (t)[2] = (e2), \ + make_tuple(t)) +#define TUPLE3(t,e1,e2,e3) \ + ((t)[0] = make_arityval(3), \ + (t)[1] = (e1), \ + (t)[2] = (e2), \ + (t)[3] = (e3), \ + make_tuple(t)) +#define TUPLE4(t,e1,e2,e3,e4) \ + ((t)[0] = make_arityval(4), \ + (t)[1] = (e1), \ + (t)[2] = (e2), \ + (t)[3] = (e3), \ + (t)[4] = (e4), \ + make_tuple(t)) +#define TUPLE5(t,e1,e2,e3,e4,e5) \ + ((t)[0] = make_arityval(5), \ + (t)[1] = (e1), \ + (t)[2] = (e2), \ + (t)[3] = (e3), \ + (t)[4] = (e4), \ + (t)[5] = (e5), \ + make_tuple(t)) +#define TUPLE6(t,e1,e2,e3,e4,e5,e6) \ + ((t)[0] = make_arityval(6), \ + (t)[1] = (e1), \ + (t)[2] = (e2), \ + (t)[3] = (e3), \ + (t)[4] = (e4), \ + (t)[5] = (e5), \ + (t)[6] = (e6), \ + make_tuple(t)) + +#define TUPLE7(t,e1,e2,e3,e4,e5,e6,e7) \ + ((t)[0] = make_arityval(7), \ + (t)[1] = (e1), \ + (t)[2] = (e2), \ + (t)[3] = (e3), \ + (t)[4] = (e4), \ + (t)[5] = (e5), \ + (t)[6] = (e6), \ + (t)[7] = (e7), \ + make_tuple(t)) + +#define TUPLE8(t,e1,e2,e3,e4,e5,e6,e7,e8) \ + ((t)[0] = make_arityval(8), \ + (t)[1] = (e1), \ + (t)[2] = (e2), \ + (t)[3] = (e3), \ + (t)[4] = (e4), \ + (t)[5] = (e5), \ + (t)[6] = (e6), \ + (t)[7] = (e7), \ + (t)[8] = (e8), \ + make_tuple(t)) + +/* This macro get Size bits starting at low order position Pos + and adjusts the bits to the right + bits are numbered from 0 - (sizeof(Uint)*8-1) */ + +#define _GETBITS(X,Pos,Size) (((X) >> (Pos)) & ~(~((Uint) 0) << (Size))) + +/* + * Observe! New layout for pids, ports and references in R9 (see also note + * in erl_node_container_utils.h). + */ + + +/* + * Creation in node specific data (pids, ports, refs) + */ + +#define _CRE_SIZE 2 + +/* MAX value for the creation field in pid, port and reference */ +#define MAX_CREATION (1 << _CRE_SIZE) + +/* + * PID layout (internal pids): + * + * |3 3 2 2 2 2 2 2|2 2 2 2 1 1 1 1|1 1 1 1 1 1 | | + * |1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0| + * | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |n n n n n n n n n n n n n n n n n n n n n n n n n n n n|0 0|1 1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * n : number + * + * Old pid layout: + * + * |3 3 2 2 2 2 2 2|2 2 2 2 1 1 1 1|1 1 1 1 1 1 | | + * |1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0| + * | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |s s s|n n n n n n n n n n n n n n n|N N N N N N N N|c c|0 0|1 1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * s : serial + * n : number + * c : creation + * N : node number + * + */ + +#define _PID_R9_SER_SIZE 3 +#define _PID_SER_SIZE (_PID_DATA_SIZE - _PID_NUM_SIZE) +#define _PID_NUM_SIZE 15 + +#define _PID_DATA_SIZE 28 +#define _PID_DATA_SHIFT (_TAG_IMMED1_SIZE) + +#define _GET_PID_DATA(X) _GETBITS((X),_PID_DATA_SHIFT,_PID_DATA_SIZE) +#define _GET_PID_NUM(X) _GETBITS((X),0,_PID_NUM_SIZE) +#define _GET_PID_SER(X) _GETBITS((X),_PID_NUM_SIZE,_PID_SER_SIZE) + +#define make_pid_data(Ser, Num) \ + ((Uint) ((Ser) << _PID_NUM_SIZE | (Num))) + +#define make_internal_pid(X) \ + ((Eterm) (((X) << _PID_DATA_SHIFT) | _TAG_IMMED1_PID)) + +#define is_internal_pid(x) (((x) & _TAG_IMMED1_MASK) == _TAG_IMMED1_PID) +#define is_not_internal_pid(x) (!is_internal_pid((x))) + +#define _unchecked_internal_pid_data(x) _GET_PID_DATA((x)) +_ET_DECLARE_CHECKED(Uint,internal_pid_data,Eterm); +#define internal_pid_data(x) _ET_APPLY(internal_pid_data,(x)) + +#define _unchecked_internal_pid_node(x) erts_this_node +_ET_DECLARE_CHECKED(struct erl_node_*,internal_pid_node,Eterm); +#define internal_pid_node(x) _ET_APPLY(internal_pid_node,(x)) + +#define internal_pid_number(x) _GET_PID_NUM(internal_pid_data((x))) +#define internal_pid_serial(x) _GET_PID_SER(internal_pid_data((x))) + +#define internal_pid_data_words(x) (1) + +/* + * PORT layout (internal ports): + * + * |3 3 2 2 2 2 2 2|2 2 2 2 1 1 1 1|1 1 1 1 1 1 | | + * |1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0| + * | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |n n n n n n n n n n n n n n n n n n n n n n n n n n n n|0 1|1 1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * n : number + * + * Old port layout: + * + * |3 3 2 2 2 2 2 2|2 2 2 2 1 1 1 1|1 1 1 1 1 1 | | + * |1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0| + * | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |N N N N N N N N|n n n n n n n n n n n n n n n n n n|c c|0 1|1 1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * s : serial + * n : number + * c : creation + * N : node number + * + */ +#define _PORT_R9_NUM_SIZE 18 +#define _PORT_NUM_SIZE _PORT_DATA_SIZE + +#define _PORT_DATA_SIZE 28 +#define _PORT_DATA_SHIFT (_TAG_IMMED1_SIZE) + +#define _GET_PORT_DATA(X) _GETBITS((X),_PORT_DATA_SHIFT,_PORT_DATA_SIZE) +#define _GET_PORT_NUM(X) _GETBITS((X), 0, _PORT_NUM_SIZE) + + +#define make_internal_port(X) \ + ((Eterm) (((X) << _PORT_DATA_SHIFT) | _TAG_IMMED1_PORT)) + +#define is_internal_port(x) (((x) & _TAG_IMMED1_MASK) == _TAG_IMMED1_PORT) +#define is_not_internal_port(x) (!is_internal_port(x)) + +#define _unchecked_internal_port_data(x) _GET_PORT_DATA((x)) +_ET_DECLARE_CHECKED(Uint,internal_port_data,Eterm); +#define internal_port_data(x) _ET_APPLY(internal_port_data,(x)) + +#define internal_port_number(x) _GET_PORT_NUM(internal_port_data((x))) + +#define _unchecked_internal_port_node(x) erts_this_node +_ET_DECLARE_CHECKED(struct erl_node_*,internal_port_node,Eterm); +#define internal_port_node(x) _ET_APPLY(internal_port_node,(x)) + +#define internal_port_data_words(x) (1) +/* + * Ref layout (internal references): + * + * |3 3 2 2 2 2 2 2|2 2 2 2 1 1 1 1|1 1 1 1 1 1 | | + * |1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0| + * | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1|0 1 0 0|0 0| Thing + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0 0 0 0 0 0 0 0 0 0 0 0 0 0|r r r r r r r r r r r r r r r r r r| Data 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r| Data 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r| Data 2 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * r : reference number + * c : creation + * + * + * Old "heap ref" layout: + * + * + * |3 3 2 2 2 2 2 2|2 2 2 2 1 1 1 1|1 1 1 1 1 1 | | + * |1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0| + * | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1|0 1 0 0|0 0| Thing + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |N N N N N N N N|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|c c|0 1 1 1| Head + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0 0 0 0 0 0 0 0 0 0 0 0 0 0|r r r r r r r r r r r r r r r r r r| Word 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r| Word 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r| Word 2 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * r : reference number + * c : creation + * N : node index + * + * Old "one-word ref" layout: + * + * |3 3 2 2 2 2 2 2|2 2 2 2 1 1 1 1|1 1 1 1 1 1 | | + * |1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0| + * | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |N N N N N N N N|r r r r r r r r r r r r r r r r r r|c c|T T T T| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * r : reference number + * c : creation + * N : node index + * + */ +#define _REF_NUM_SIZE 18 + +/* Old maximum number of references in the system */ +#define MAX_REFERENCE (1 << _REF_NUM_SIZE) +#define REF_MASK (~(~((Uint)0) << _REF_NUM_SIZE)) +#define ERTS_MAX_REF_NUMBERS 3 +#define ERTS_REF_NUMBERS ERTS_MAX_REF_NUMBERS + +#ifdef ARCH_64 +# define ERTS_REF_WORDS (ERTS_REF_NUMBERS/2 + 1) +# define ERTS_REF_32BIT_WORDS (ERTS_REF_NUMBERS+1) +#else +# define ERTS_REF_WORDS ERTS_REF_NUMBERS +# define ERTS_REF_32BIT_WORDS ERTS_REF_NUMBERS +#endif + +typedef struct { + Eterm header; + union { + Uint32 ui32[ERTS_REF_32BIT_WORDS]; + Uint ui[ERTS_REF_WORDS]; + } data; +} RefThing; + +#define REF_THING_SIZE (sizeof(RefThing)/sizeof(Uint)) +#define REF_THING_HEAD_SIZE (sizeof(Eterm)/sizeof(Uint)) + +#define make_ref_thing_header(DW) \ + _make_header((DW)+REF_THING_HEAD_SIZE-1,_TAG_HEADER_REF) + +#ifdef ARCH_64 + +/* + * Ref layout on a 64-bit little endian machine: + * + * 63 31 0 + * +--------------+--------------+ + * | Thing word | + * +--------------+--------------+ + * | Data 0 | 32-bit arity | + * +--------------+--------------+ + * | Data 2 | Data 1 | + * +--------------+--------------+ + * + * Data is stored as an Uint32 array with 32-bit arity as first number. + */ + +#define write_ref_thing(Hp, R0, R1, R2) \ +do { \ + ((RefThing *) (Hp))->header = make_ref_thing_header(ERTS_REF_WORDS); \ + ((RefThing *) (Hp))->data.ui32[0] = ERTS_REF_NUMBERS; \ + ((RefThing *) (Hp))->data.ui32[1] = (R0); \ + ((RefThing *) (Hp))->data.ui32[2] = (R1); \ + ((RefThing *) (Hp))->data.ui32[3] = (R2); \ +} while (0) + +#else + +#define write_ref_thing(Hp, R0, R1, R2) \ +do { \ + ((RefThing *) (Hp))->header = make_ref_thing_header(ERTS_REF_WORDS); \ + ((RefThing *) (Hp))->data.ui32[0] = (R0); \ + ((RefThing *) (Hp))->data.ui32[1] = (R1); \ + ((RefThing *) (Hp))->data.ui32[2] = (R2); \ +} while (0) + +#endif + +#define is_ref_thing_header(x) (((x) & _TAG_HEADER_MASK) == _TAG_HEADER_REF) +#define make_internal_ref(x) make_boxed((Eterm*)(x)) + +#define _unchecked_ref_thing_ptr(x) \ + ((RefThing*) _unchecked_internal_ref_val(x)) +#define ref_thing_ptr(x) \ + ((RefThing*) internal_ref_val(x)) + +#define is_internal_ref(x) \ + (_unchecked_is_boxed((x)) && is_ref_thing_header(*boxed_val((x)))) +#define is_not_internal_ref(x) \ + (!is_internal_ref((x))) + +#define _unchecked_internal_ref_val(x) _unchecked_boxed_val((x)) +_ET_DECLARE_CHECKED(Eterm*,internal_ref_val,Eterm); +#define internal_ref_val(x) _ET_APPLY(internal_ref_val,(x)) + +#define _unchecked_internal_ref_data_words(x) \ + (_unchecked_thing_arityval(*_unchecked_internal_ref_val(x))) +_ET_DECLARE_CHECKED(Uint,internal_ref_data_words,Eterm); +#define internal_ref_data_words(x) _ET_APPLY(internal_ref_data_words,(x)) + +#define _unchecked_internal_ref_data(x) (_unchecked_ref_thing_ptr(x)->data.ui32) +_ET_DECLARE_CHECKED(Uint32*,internal_ref_data,Eterm); +#define internal_ref_data(x) _ET_APPLY(internal_ref_data,(x)) + +#define _unchecked_internal_ref_node(x) erts_this_node +_ET_DECLARE_CHECKED(struct erl_node_*,internal_ref_node,Eterm); +#define internal_ref_node(x) _ET_APPLY(internal_ref_node,(x)) + +/* + * + * External thing layout (external pids, ports, and refs): + * + * |3 3 2 2 2 2 2 2|2 2 2 2 1 1 1 1|1 1 1 1 1 1 | | + * |1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0| + * | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |A A A A A A A A A A A A A A A A A A A A A A A A A A|t t t t|0 0| Thing + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N| Next + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E| ErlNode + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X| Data 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . . . + * . . . + * . . . + * + * A : Arity + * t : External pid thing tag (1100) + * t : External port thing tag (1101) + * t : External ref thing tag (1110) + * N : Next (external thing) pointer + * E : ErlNode pointer + * X : Type specific data + * + * External pid and port layout: + * External pids and ports only have one data word (Data 0) which has + * the same layout as internal pids resp. internal ports. + * + * External refs layout: + * External refs has the same layout for the data words as in the internal + * ref. + * + */ + +typedef struct external_thing_ { + /* ----+ */ + Eterm header; /* | */ + struct external_thing_ *next; /* > External thing head */ + struct erl_node_ *node; /* | */ + /* ----+ */ + union { + Uint32 ui32[1]; + Uint ui[1]; + } data; +} ExternalThing; + +#define EXTERNAL_THING_HEAD_SIZE (sizeof(ExternalThing)/sizeof(Uint) - 1) + +#define make_external_pid_header(DW) \ + _make_header((DW)+EXTERNAL_THING_HEAD_SIZE-1,_TAG_HEADER_EXTERNAL_PID) +#define is_external_pid_header(x) \ + (((x) & _TAG_HEADER_MASK) == _TAG_HEADER_EXTERNAL_PID) + +#define make_external_port_header(DW) \ + _make_header((DW)+EXTERNAL_THING_HEAD_SIZE-1,_TAG_HEADER_EXTERNAL_PORT) +#define is_external_port_header(x) \ + (((x) & _TAG_HEADER_MASK) == _TAG_HEADER_EXTERNAL_PORT) + +#define make_external_ref_header(DW) \ + _make_header((DW)+EXTERNAL_THING_HEAD_SIZE-1,_TAG_HEADER_EXTERNAL_REF) +#define is_external_ref_header(x) \ + (((x) & _TAG_HEADER_MASK) == _TAG_HEADER_EXTERNAL_REF) + +#define is_external_header(x) \ + (((x) & (_TAG_HEADER_MASK-_BINARY_XXX_MASK)) == _TAG_HEADER_EXTERNAL_PID) + +#define is_external(x) \ + (is_boxed((x)) && is_external_header(*boxed_val((x)))) +#define is_external_pid(x) \ + (is_boxed((x)) && is_external_pid_header(*boxed_val((x)))) +#define is_external_port(x) \ + (is_boxed((x)) && is_external_port_header(*boxed_val((x)))) +#define is_external_ref(x) \ + (_unchecked_is_boxed((x)) && is_external_ref_header(*boxed_val((x)))) + +#define _unchecked_is_external(x) \ + (_unchecked_is_boxed((x)) && is_external_header(*_unchecked_boxed_val((x)))) + +#define is_not_external(x) (!is_external((x))) +#define is_not_external_pid(x) (!is_external_pid((x))) +#define is_not_external_port(x) (!is_external_port((x))) +#define is_not_external_ref(x) (!is_external_ref((x))) + + +#define make_external(x) make_boxed((Eterm *) (x)) + +#define make_external_pid make_external +#define make_external_port make_external +#define make_external_ref make_external + +#define _unchecked_external_val(x) _unchecked_boxed_val((x)) +_ET_DECLARE_CHECKED(Eterm*,external_val,Eterm); +#define external_val(x) _ET_APPLY(external_val,(x)) + +#define external_thing_ptr(x) ((ExternalThing *) external_val((x))) +#define _unchecked_external_thing_ptr(x) \ + ((ExternalThing *) _unchecked_external_val((x))) + +#define _unchecked_external_data_words(x) \ + (_unchecked_thing_arityval(_unchecked_external_thing_ptr((x))->header) \ + + (1 - EXTERNAL_THING_HEAD_SIZE)) +_ET_DECLARE_CHECKED(Uint,external_data_words,Eterm); +#define external_data_words(x) _ET_APPLY(external_data_words,(x)) + +#define _unchecked_external_data(x) (_unchecked_external_thing_ptr((x))->data.ui) +#define _unchecked_external_node(x) (_unchecked_external_thing_ptr((x))->node) + +#define external_data(x) (external_thing_ptr((x))->data.ui) +#define external_node(x) (external_thing_ptr((x))->node) + +#define _unchecked_external_pid_data_words(x) \ + _unchecked_external_data_words((x)) +_ET_DECLARE_CHECKED(Uint,external_pid_data_words,Eterm); +#define external_pid_data_words(x) _ET_APPLY(external_pid_data_words,(x)) + +#define _unchecked_external_pid_data(x) _unchecked_external_data((x))[0] +_ET_DECLARE_CHECKED(Uint,external_pid_data,Eterm); +#define external_pid_data(x) _ET_APPLY(external_pid_data,(x)) + +#define _unchecked_external_pid_node(x) _unchecked_external_node((x)) +_ET_DECLARE_CHECKED(struct erl_node_*,external_pid_node,Eterm); +#define external_pid_node(x) _ET_APPLY(external_pid_node,(x)) + +#define external_pid_number(x) _GET_PID_NUM(external_pid_data((x))) +#define external_pid_serial(x) _GET_PID_SER(external_pid_data((x))) + +#define _unchecked_external_port_data_words(x) \ + _unchecked_external_data_words((x)) +_ET_DECLARE_CHECKED(Uint,external_port_data_words,Eterm); +#define external_port_data_words(x) _ET_APPLY(external_port_data_words,(x)) + +#define _unchecked_external_port_data(x) _unchecked_external_data((x))[0] +_ET_DECLARE_CHECKED(Uint,external_port_data,Eterm); +#define external_port_data(x) _ET_APPLY(external_port_data,(x)) + +#define _unchecked_external_port_node(x) _unchecked_external_node((x)) +_ET_DECLARE_CHECKED(struct erl_node_*,external_port_node,Eterm); +#define external_port_node(x) _ET_APPLY(external_port_node,(x)) + +#define external_port_number(x) _GET_PORT_NUM(external_port_data((x))) + +#define _unchecked_external_ref_data_words(x) \ + _unchecked_external_data_words((x)) +_ET_DECLARE_CHECKED(Uint,external_ref_data_words,Eterm); +#define external_ref_data_words(x) _ET_APPLY(external_ref_data_words,(x)) + +#define _unchecked_external_ref_data(x) (_unchecked_external_thing_ptr((x))->data.ui32) +_ET_DECLARE_CHECKED(Uint32*,external_ref_data,Eterm); +#define external_ref_data(x) _ET_APPLY(external_ref_data,(x)) + +#define _unchecked_external_ref_node(x) _unchecked_external_node((x)) +_ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm); +#define external_ref_node(x) _ET_APPLY(external_ref_node,(x)) + +/* number tests */ + +#define is_integer(x) (is_small(x) || is_big(x)) +#define is_not_integer(x) (!is_integer(x)) +#define is_number(x) (is_integer(x) || is_float(x)) + +#define SMALL_MINUS_ONE make_small(-1) +#define SMALL_ZERO make_small(0) +#define SMALL_ONE make_small(1) + +#define ENULL 0 + +/* on some architectures CP contains labels which are not aligned */ +#ifdef NOT_ALIGNED +#error "fix yer arch, like" +#endif + +#define _unchecked_make_cp(x) ((Eterm)(x)) +_ET_DECLARE_CHECKED(Eterm,make_cp,Uint*); +#define make_cp(x) _ET_APPLY(make_cp,(x)) + +#define is_not_CP(x) ((x) & _CPMASK) +#define is_CP(x) (!is_not_CP(x)) + +#define _unchecked_cp_val(x) ((Uint*)(x)) +_ET_DECLARE_CHECKED(Uint*,cp_val,Eterm); +#define cp_val(x) _ET_APPLY(cp_val,(x)) + +#define make_catch(x) (((x) << _TAG_IMMED2_SIZE) | _TAG_IMMED2_CATCH) +#define is_catch(x) (((x) & _TAG_IMMED2_MASK) == _TAG_IMMED2_CATCH) +#define is_not_catch(x) (!is_catch(x)) +#define _unchecked_catch_val(x) ((x) >> _TAG_IMMED2_SIZE) +_ET_DECLARE_CHECKED(Uint,catch_val,Eterm); +#define catch_val(x) _ET_APPLY(catch_val,(x)) + +#define make_blank(X) ((X) = NIL) + +/* + * Overloaded tags. + * + * SMALL = 15 + * ATOM/NIL=7 + * + * Note that the two least significant bits in SMALL/ATOM/NIL always are 3; + * thus, we can distinguish register from literals by looking at only these + * two bits. + */ + +#define X_REG_DEF 0 +#define Y_REG_DEF 1 +#define R_REG_DEF 2 + +#define beam_reg_tag(x) ((x) & 3) + +#define make_rreg() R_REG_DEF +#define make_xreg(ix) (((ix) * sizeof(Eterm)) | X_REG_DEF) +#define make_yreg(ix) (((ix) * sizeof(Eterm)) | Y_REG_DEF) + +#define _is_xreg(x) (beam_reg_tag(x) == X_REG_DEF) +#define _is_yreg(x) (beam_reg_tag(x) == Y_REG_DEF) + +#define _unchecked_x_reg_offset(R) ((R) - X_REG_DEF) +_ET_DECLARE_CHECKED(Uint,x_reg_offset,Uint); +#define x_reg_offset(R) _ET_APPLY(x_reg_offset,(R)) + +#define _unchecked_y_reg_offset(R) ((R) - Y_REG_DEF) +_ET_DECLARE_CHECKED(Uint,y_reg_offset,Uint); +#define y_reg_offset(R) _ET_APPLY(y_reg_offset,(R)) + +#define reg_index(R) ((R) / sizeof(Eterm)) + +#define _unchecked_x_reg_index(R) ((R) >> 2) +_ET_DECLARE_CHECKED(Uint,x_reg_index,Uint); +#define x_reg_index(R) _ET_APPLY(x_reg_index,(R)) + +#define _unchecked_y_reg_index(R) ((R) >> 2) +_ET_DECLARE_CHECKED(Uint,y_reg_index,Uint); +#define y_reg_index(R) _ET_APPLY(y_reg_index,(R)) + +/* + * Backwards compatibility definitions: + * - #define virtal *_DEF constants with values that fit term order: + * number < atom < ref < fun < port < pid < tuple < nil < cons < binary + * - tag_val_def() function generates virtual _DEF tag + * - not_eq_tags() and NUMBER_CODE() defined in terms + * of the tag_val_def() function + */ + +#define BINARY_DEF 0x0 +#define LIST_DEF 0x1 +#define NIL_DEF 0x2 +#define TUPLE_DEF 0x3 +#define PID_DEF 0x4 +#define EXTERNAL_PID_DEF 0x5 +#define PORT_DEF 0x6 +#define EXTERNAL_PORT_DEF 0x7 +#define EXPORT_DEF 0x8 +#define FUN_DEF 0x9 +#define REF_DEF 0xa +#define EXTERNAL_REF_DEF 0xb +#define ATOM_DEF 0xc +#define FLOAT_DEF 0xd +#define BIG_DEF 0xe +#define SMALL_DEF 0xf + +#if ET_DEBUG +extern unsigned tag_val_def_debug(Eterm, const char*, unsigned); +#define tag_val_def(x) tag_val_def_debug((x),__FILE__,__LINE__) +#else +extern unsigned tag_val_def(Eterm); +#endif +#define not_eq_tags(X,Y) (tag_val_def((X)) ^ tag_val_def((Y))) + +#define NUMBER_CODE(x,y) ((tag_val_def(x) << 4) | tag_val_def(y)) +#define _NUMBER_CODE(TX,TY) ((TX << 4) | TY) +#define SMALL_SMALL _NUMBER_CODE(SMALL_DEF,SMALL_DEF) +#define SMALL_BIG _NUMBER_CODE(SMALL_DEF,BIG_DEF) +#define SMALL_FLOAT _NUMBER_CODE(SMALL_DEF,FLOAT_DEF) +#define BIG_SMALL _NUMBER_CODE(BIG_DEF,SMALL_DEF) +#define BIG_BIG _NUMBER_CODE(BIG_DEF,BIG_DEF) +#define BIG_FLOAT _NUMBER_CODE(BIG_DEF,FLOAT_DEF) +#define FLOAT_SMALL _NUMBER_CODE(FLOAT_DEF,SMALL_DEF) +#define FLOAT_BIG _NUMBER_CODE(FLOAT_DEF,BIG_DEF) +#define FLOAT_FLOAT _NUMBER_CODE(FLOAT_DEF,FLOAT_DEF) + +#endif /* __ERL_TERM_H */ + |