From 5a8e6c4183a30f3b10de22fa5ba80950dfb2adea Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Mon, 7 Dec 2009 15:25:32 +0100 Subject: Fit all heap data into the 32-bit address range This is the first step in the implementation of the half-word emulator, a 64-bit emulator where all pointers to heap data will be stored in 32-bit words. Code specific for this emulator variant is conditionally compiled when the HALFWORD_HEAP define has a non-zero value. First force all pointers to heap data to fall into a single 32-bit range, but still store them in 64-bit words. Temporary term data stored on C stack is moved into scheduler specific storage (allocated as heaps) and macros are added to make this happen only in emulators where this is needed. For a vanilla VM the temporary terms are still stored on the C stack. --- erts/emulator/beam/erl_term.h | 59 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 9 deletions(-) (limited to 'erts/emulator/beam/erl_term.h') diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index a6596558fa..016d6e66a7 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -20,6 +20,35 @@ #ifndef __ERL_TERM_H #define __ERL_TERM_H +#ifdef ARCH_64 +#define HALFWORD_HEAP 1 +#define HALFWORD_ASSERT 1 +#endif + +#if HALFWORD_HEAP +# define HEAP_ON_C_STACK 0 +# if HALFWORD_ASSERT +# ifdef ET_DEBUG +# undef ET_DEBUG +# endif +# define ET_DEBUG 1 +# endif +# if 1 +# define CHECK_POINTER_MASK 0xFFFFFFFF00000000UL +# define COMPRESS_POINTER(AnUint) (AnUint) +# define EXPAND_POINTER(APointer) (APointer) +# else +# define CHECK_POINTER_MASK 0x0UL +# define COMPRESS_POINTER(AnUint) (AnUint) +# define EXPAND_POINTER(APointer) (APointer) +# endif +#else +# define HEAP_ON_C_STACK 1 +# define CHECK_POINTER_MASK 0x0UL +# define COMPRESS_POINTER(AnUint) (AnUint) +# define EXPAND_POINTER(APointer) (APointer) +#endif + struct erl_node_; /* Declared in erl_node_tables.h */ /* @@ -158,9 +187,16 @@ struct erl_node_; /* Declared in erl_node_tables.h */ /* boxed object access methods */ +#if HALFWORD_HEAP +#define _is_taggable_pointer(x) (((Uint)(x) & (CHECK_POINTER_MASK | 0x3)) == 0) +#define _boxed_precond(x) (is_boxed(x)) +#else +#define _is_taggable_pointer(x) (((Uint)(x) & 0x3) == 0) +#define _boxed_precond(x) (is_boxed(x)) +#endif #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 _unchecked_make_boxed(x) COMPRESS_POINTER((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)) @@ -170,13 +206,13 @@ _ET_DECLARE_CHECKED(int,is_boxed,Eterm) #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 _unchecked_boxed_val(x) EXPAND_POINTER((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 _unchecked_make_list(x) COMPRESS_POINTER((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)) @@ -187,8 +223,13 @@ _ET_DECLARE_CHECKED(int,is_not_list,Eterm) #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) +#if HALFWORD_HEAP +#define _list_precond(x) (is_list(x)) +#else +#define _list_precond(x) (is_list(x)) +#endif +#define _unchecked_list_val(x) EXPAND_POINTER((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) \ @@ -198,7 +239,7 @@ _ET_DECLARE_CHECKED(Eterm*,list_val,Eterm) #define CDR(x) ((x)[1]) /* generic tagged pointer (boxed or list) access methods */ -#define _unchecked_ptr_val(x) ((Eterm*)((x) & ~((Uint) 0x3))) +#define _unchecked_ptr_val(x) EXPAND_POINTER((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*/ -- cgit v1.2.3 From fb94cd974dc03baf149264ca4f4d50c6d1f80f21 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Wed, 20 Jan 2010 16:26:14 +0100 Subject: Store pointers to heap data in 32-bit words Store Erlang terms in 32-bit entities on the heap, expanding the pointers to 64-bit when needed. This works because all terms are stored on addresses in the 32-bit address range (the 32 most significant bits of pointers to term data are always 0). Introduce a new datatype called UWord (along with its companion SWord), which is an integer having the exact same size as the machine word (a void *), but might be larger than Eterm/Uint. Store code as machine words, as the instructions are pointers to executable code which might reside outside the 32-bit address range. Continuation pointers are stored on the 32-bit stack and hence must point to addresses in the low range, which means that loaded beam code much be placed in the low 32-bit address range (but, as said earlier, the instructions themselves are full words). No Erlang term data can be stored on C stacks (enforced by an earlier commit). This version gives a prompt, but test cases still fail (and dump core). The loader (and emulator loop) has instruction packing disabled. The main issues has been in rewriting loader and actual virtual machine. Subsystems (like distribution) does not work yet. --- erts/emulator/beam/erl_term.h | 45 ++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'erts/emulator/beam/erl_term.h') diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index 016d6e66a7..8e74502022 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -20,10 +20,7 @@ #ifndef __ERL_TERM_H #define __ERL_TERM_H -#ifdef ARCH_64 -#define HALFWORD_HEAP 1 -#define HALFWORD_ASSERT 1 -#endif +#include "sys.h" /* defines HALFWORD_HEAP */ #if HALFWORD_HEAP # define HEAP_ON_C_STACK 0 @@ -35,8 +32,8 @@ # endif # if 1 # define CHECK_POINTER_MASK 0xFFFFFFFF00000000UL -# define COMPRESS_POINTER(AnUint) (AnUint) -# define EXPAND_POINTER(APointer) (APointer) +# define COMPRESS_POINTER(APointer) ((Eterm) (UWord) (APointer)) +# define EXPAND_POINTER(AnEterm) ((UWord) (AnEterm)) # else # define CHECK_POINTER_MASK 0x0UL # define COMPRESS_POINTER(AnUint) (AnUint) @@ -188,14 +185,14 @@ struct erl_node_; /* Declared in erl_node_tables.h */ /* boxed object access methods */ #if HALFWORD_HEAP -#define _is_taggable_pointer(x) (((Uint)(x) & (CHECK_POINTER_MASK | 0x3)) == 0) +#define _is_taggable_pointer(x) (((UWord)(x) & (CHECK_POINTER_MASK | 0x3)) == 0) #define _boxed_precond(x) (is_boxed(x)) #else #define _is_taggable_pointer(x) (((Uint)(x) & 0x3) == 0) #define _boxed_precond(x) (is_boxed(x)) #endif #define _is_aligned(x) (((Uint)(x) & 0x3) == 0) -#define _unchecked_make_boxed(x) COMPRESS_POINTER((Uint)(x) + TAG_PRIMARY_BOXED) +#define _unchecked_make_boxed(x) ((Uint) COMPRESS_POINTER(x) + TAG_PRIMARY_BOXED) _ET_DECLARE_CHECKED(Eterm,make_boxed,Eterm*); #define make_boxed(x) _ET_APPLY(make_boxed,(x)) #if 1 @@ -206,12 +203,12 @@ _ET_DECLARE_CHECKED(int,is_boxed,Eterm) #else #define is_boxed(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_BOXED) #endif -#define _unchecked_boxed_val(x) EXPAND_POINTER((Eterm*)((x) - TAG_PRIMARY_BOXED)) +#define _unchecked_boxed_val(x) ((Eterm*) EXPAND_POINTER(((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) COMPRESS_POINTER((Uint)(x) + TAG_PRIMARY_LIST) +#define _unchecked_make_list(x) ((Uint) COMPRESS_POINTER(x) + TAG_PRIMARY_LIST) _ET_DECLARE_CHECKED(Eterm,make_list,Eterm*); #define make_list(x) _ET_APPLY(make_list,(x)) #if 1 @@ -228,7 +225,7 @@ _ET_DECLARE_CHECKED(int,is_not_list,Eterm) #else #define _list_precond(x) (is_list(x)) #endif -#define _unchecked_list_val(x) EXPAND_POINTER((Eterm*)((x) - TAG_PRIMARY_LIST)) +#define _unchecked_list_val(x) ((Eterm*) EXPAND_POINTER((x) - TAG_PRIMARY_LIST)) _ET_DECLARE_CHECKED(Eterm*,list_val,Eterm); #define list_val(x) _ET_APPLY(list_val,(x)) @@ -239,13 +236,13 @@ _ET_DECLARE_CHECKED(Eterm*,list_val,Eterm); #define CDR(x) ((x)[1]) /* generic tagged pointer (boxed or list) access methods */ -#define _unchecked_ptr_val(x) EXPAND_POINTER((Eterm*)((x) & ~((Uint) 0x3))) +#define _unchecked_ptr_val(x) ((Eterm*) EXPAND_POINTER((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) +#if defined(ARCH_64) && !HALFWORD_HEAP #define SMALL_BITS (64-4) #define SMALL_DIGITS (17) #else @@ -370,7 +367,11 @@ _ET_DECLARE_CHECKED(Eterm*,fun_val,Eterm) _ET_DECLARE_CHECKED(Eterm*,export_val,Eterm) #define export_val(x) _ET_APPLY(export_val,(x)) #define is_export_header(x) ((x) == HEADER_EXPORT) +#if HALFWORD_HEAP +#define HEADER_EXPORT _make_header(2,_TAG_HEADER_EXPORT) +#else #define HEADER_EXPORT _make_header(1,_TAG_HEADER_EXPORT) +#endif /* bignum access methods */ #define make_pos_bignum_header(sz) _make_header((sz),_TAG_HEADER_POS_BIG) @@ -394,7 +395,7 @@ _ET_DECLARE_CHECKED(Eterm*,big_val,Eterm) #define big_val(x) _ET_APPLY(big_val,(x)) /* flonum ("float") access methods */ -#ifdef ARCH_64 +#if defined(ARCH_64) && !HALFWORD_HEAP #define HEADER_FLONUM _make_header(1,_TAG_HEADER_FLOAT) #else #define HEADER_FLONUM _make_header(2,_TAG_HEADER_FLOAT) @@ -415,12 +416,12 @@ typedef union float_def byte fb[sizeof(ieee754_8)]; Uint16 fs[sizeof(ieee754_8) / sizeof(Uint16)]; Uint32 fw[sizeof(ieee754_8) / sizeof(Uint32)]; -#ifdef ARCH_64 +#if defined(ARCH_64) && !HALFWORD_HEAP Uint fdw; #endif } FloatDef; -#ifdef ARCH_64 +#if defined(ARCH_64) && !HALFWORD_HEAP #define GET_DOUBLE(x, f) (f).fdw = *(float_val(x)+1) #define PUT_DOUBLE(f, x) *(x) = HEADER_FLONUM, \ @@ -720,7 +721,7 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_port_node,Eterm) #define ERTS_MAX_REF_NUMBERS 3 #define ERTS_REF_NUMBERS ERTS_MAX_REF_NUMBERS -#ifdef ARCH_64 +#if defined(ARCH_64) && !HALFWORD_HEAP # define ERTS_REF_WORDS (ERTS_REF_NUMBERS/2 + 1) # define ERTS_REF_32BIT_WORDS (ERTS_REF_NUMBERS+1) #else @@ -742,7 +743,7 @@ typedef struct { #define make_ref_thing_header(DW) \ _make_header((DW)+REF_THING_HEAD_SIZE-1,_TAG_HEADER_REF) -#ifdef ARCH_64 +#if defined(ARCH_64) && !HALFWORD_HEAP /* * Ref layout on a 64-bit little endian machine: @@ -985,15 +986,15 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm) #error "fix yer arch, like" #endif -#define _unchecked_make_cp(x) ((Eterm)(x)) -_ET_DECLARE_CHECKED(Eterm,make_cp,Uint*) +#define _unchecked_make_cp(x) ((Eterm) COMPRESS_POINTER(x)) +_ET_DECLARE_CHECKED(Eterm,make_cp,UWord*); #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 _unchecked_cp_val(x) ((UWord*) EXPAND_POINTER(x)) +_ET_DECLARE_CHECKED(UWord*,cp_val,Eterm); #define cp_val(x) _ET_APPLY(cp_val,(x)) #define make_catch(x) (((x) << _TAG_IMMED2_SIZE) | _TAG_IMMED2_CATCH) -- cgit v1.2.3 From 20ba5ed3c281d3f0be587395fa66182873d229f0 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Thu, 4 Feb 2010 15:21:36 +0100 Subject: Add the BeamInstr data type for loaded BEAM code For cleanliness, use BeamInstr instead of the UWord data type to any machine-sized words that are used for BEAM instructions. Only use UWord for untyped words in general. --- erts/emulator/beam/erl_term.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/emulator/beam/erl_term.h') diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index 8e74502022..25d12bf16e 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -987,14 +987,14 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm) #endif #define _unchecked_make_cp(x) ((Eterm) COMPRESS_POINTER(x)) -_ET_DECLARE_CHECKED(Eterm,make_cp,UWord*); +_ET_DECLARE_CHECKED(Eterm,make_cp,BeamInstr*); #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) ((UWord*) EXPAND_POINTER(x)) -_ET_DECLARE_CHECKED(UWord*,cp_val,Eterm); +#define _unchecked_cp_val(x) ((BeamInstr*) EXPAND_POINTER(x)) +_ET_DECLARE_CHECKED(BeamInstr*,cp_val,Eterm); #define cp_val(x) _ET_APPLY(cp_val,(x)) #define make_catch(x) (((x) << _TAG_IMMED2_SIZE) | _TAG_IMMED2_CATCH) -- cgit v1.2.3 From c591f7b2a78b44ab321d0b99c100b349c8606c15 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Tue, 9 Feb 2010 17:21:28 +0100 Subject: Make tracing and distribution work Rewrite trace code and external coding. Also slightly correct the interface to the match-spec engine to make tracing work. That will make the test suites runnable. --- erts/emulator/beam/erl_term.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'erts/emulator/beam/erl_term.h') diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index 25d12bf16e..3a8c30fe6a 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -849,6 +849,11 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_ref_node,Eterm) * */ +/* XXX:PaN - this structure is not perfect for halfword heap, it takes + a lot of memory due to padding, and the array will not begin at the end of the + structure, as otherwise expected. Be sure to access data.ui32 array and not try + to do pointer manipulation on an Eterm * to reach the actual data... */ + typedef struct external_thing_ { /* ----+ */ Eterm header; /* | */ -- cgit v1.2.3