how is a list constructured by the erlang vm?

2019-02-17 16:16发布

问题:

When I create a list in erlang, such as in the erlang shell:

1> [1, 2].

From what I understand, in the vm this list will be represented as a singly linked list.

How is this structure created by the erlang runtime? For example, is it constructed something like this:

  1. create a structure in memory to hold an list that terminates the list
  2. create a structure in memory to hold the item '2', and a reference to the empty list.
  3. create a structure in memory to hold the item '1', and a reference to item '2'.

Am I correct in thinking the following c and erlang code is where the bulk of the work is done?

  • https://github.com/erlang/otp/blob/maint/lib/stdlib/src/lists.erl
  • https://github.com/erlang/otp/blob/maint/erts/emulator/beam/erl_bif_lists.c
  • https://github.com/erlang/otp/blob/maint/erts/emulator/beam/erl_term.h
  • https://github.com/erlang/otp/blob/maint/erts/emulator/beam/erl_term.c

erl_term.h contains a macro make_list but I haven't been able to find the implementation yet...

回答1:

The Erlang VM implementation BEAM uses a technique which dates back to first Lisp implementations back to the 60s or early 70s. It is sometimes referred as tagged or typed pointers. (Tags) This technique does not store type of a target in a target object (lists CONS in this case) but in the pointer itself or save a scalar value in the place where is usually a pointer. It allows save a quite good amount of memory especially in dynamically typed languages as LISP or Erlang. (It was interesting in old days when memory was very expensive and become important again nowadays when CPU become much faster than memory and cache miss/hit determines a speed of algorithms.) As a drawback, it also leads to a little bit confusing code. The whole part which deals with list construction starts at line 216 of erl_term.h. You can note there is macro

#define _unchecked_make_list(x) ((Uint) COMPRESS_POINTER(x) + TAG_PRIMARY_LIST)

which is macro you are looking for. It is your make_list. The line

_ET_DECLARE_CHECKED(Eterm,make_list,const Eterm*)

Would make a checked version of it when compiled with ET_DEBUG. (See more details.) Macro make_list

#define make_list(x)        _ET_APPLY(make_list,(x))

would just call the checked or unchecked version of make_list. The macros which really constructing list are

#define CONS(hp, car, cdr) \
        (CAR(hp)=(car), CDR(hp)=(cdr), make_list(hp))

#define CAR(x)  ((x)[0])
#define CDR(x)  ((x)[1])

The list cell structure is simply two consecutive Uint values on the heap (hp) which address is compressed and tagged (See _unchecked_make_list). I hope this description helps you.



标签: erlang