diff --git a/.gitignore b/.gitignore index 9949ec7..f53e4f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/docs/build/* /src/* *.iml .idea/* \ No newline at end of file diff --git a/docs/build/.gitignore b/docs/build/.gitignore deleted file mode 100644 index 535a06c..0000000 --- a/docs/build/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/doctrees diff --git a/docs/build/html/.buildinfo b/docs/build/html/.buildinfo deleted file mode 100644 index 4dc7772..0000000 --- a/docs/build/html/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 8a260c513cd58159f13121bc11fc769c -tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/build/html/_images/eli5-atom-tab.png b/docs/build/html/_images/eli5-atom-tab.png deleted file mode 100644 index 3aedff0..0000000 Binary files a/docs/build/html/_images/eli5-atom-tab.png and /dev/null differ diff --git a/docs/build/html/_images/eli5-process-mqueue.png b/docs/build/html/_images/eli5-process-mqueue.png deleted file mode 100644 index 2d9be17..0000000 Binary files a/docs/build/html/_images/eli5-process-mqueue.png and /dev/null differ diff --git a/docs/build/html/_images/eli5-process-sched.png b/docs/build/html/_images/eli5-process-sched.png deleted file mode 100644 index 2ef161e..0000000 Binary files a/docs/build/html/_images/eli5-process-sched.png and /dev/null differ diff --git a/docs/build/html/_images/eli5-process-stack.png b/docs/build/html/_images/eli5-process-stack.png deleted file mode 100644 index 63a952e..0000000 Binary files a/docs/build/html/_images/eli5-process-stack.png and /dev/null differ diff --git a/docs/build/html/_images/memory-layout-bignum.png b/docs/build/html/_images/memory-layout-bignum.png deleted file mode 100644 index 87ff7bc..0000000 Binary files a/docs/build/html/_images/memory-layout-bignum.png and /dev/null differ diff --git a/docs/build/html/_images/memory-layout-box.png b/docs/build/html/_images/memory-layout-box.png deleted file mode 100644 index 3d1d978..0000000 Binary files a/docs/build/html/_images/memory-layout-box.png and /dev/null differ diff --git a/docs/build/html/_images/memory-layout-export.png b/docs/build/html/_images/memory-layout-export.png deleted file mode 100644 index 2a7eb84..0000000 Binary files a/docs/build/html/_images/memory-layout-export.png and /dev/null differ diff --git a/docs/build/html/_images/memory-layout-immed.png b/docs/build/html/_images/memory-layout-immed.png deleted file mode 100644 index 52cef19..0000000 Binary files a/docs/build/html/_images/memory-layout-immed.png and /dev/null differ diff --git a/docs/build/html/_images/memory-layout-list.png b/docs/build/html/_images/memory-layout-list.png deleted file mode 100644 index a8c5e37..0000000 Binary files a/docs/build/html/_images/memory-layout-list.png and /dev/null differ diff --git a/docs/build/html/_images/memory-layout-ref.png b/docs/build/html/_images/memory-layout-ref.png deleted file mode 100644 index 1db6465..0000000 Binary files a/docs/build/html/_images/memory-layout-ref.png and /dev/null differ diff --git a/docs/build/html/_images/memory-layout-tuple.png b/docs/build/html/_images/memory-layout-tuple.png deleted file mode 100644 index 10bfbd2..0000000 Binary files a/docs/build/html/_images/memory-layout-tuple.png and /dev/null differ diff --git a/docs/build/html/_sources/definitions.rst.txt b/docs/build/html/_sources/definitions.rst.txt deleted file mode 100644 index 4f5c926..0000000 --- a/docs/build/html/_sources/definitions.rst.txt +++ /dev/null @@ -1,226 +0,0 @@ -BEAM Definitions -================= - -For specific constant values, bit positions and bit sizes please always -refer to original beam sources, file: ``erl_term.h`` - -.. _def-box: - -**Boxed Value** - A term value, whose :ref:`primary tag ` is - (``TAG_PRIMARY_BOXED=2``), contains a pointer to data on heap. - - The first word of the box always has header tag (``TAG_PRIMARY_HEADER=0``) - in its 2 least-significant bits. Then goes the subtag (following 4 bits) - which determines type of the value inside the box. Knowing this allows - scanning heap and interpreting found data. - - VM uses boxes to store larger values, which do not fit into - :ref:`Word ` size minus 4 bits (:ref:`immediate-1 `) - or :ref:`Word ` size minus 6 bits - (for immediate-2). - - Examples of box: - **bigint**, **float**, **fun**, **export**, heap and refcounted **binary**, - external **ports** and **pids** (with host name in them). - -.. _def-cache-locality: - -**Cache Locality** - A mythical creature used to scare naughty developers. It may have either - huge impact on your code performance or very little. Always run - performance tests before you start optimizing for this. - -**Context** - Virtual machine context is a small structure which contains a copy of - active registers, instruction pointer, few other pointers from the - currently running process. It is stored in CPU registers or on stack - (based on C compiler judgement when building the emulator). - - When a process is ready to run, its fields are copied into the context, - i.e. *swapped in*. - When a process is suspended or scheduled out, the context is stored back - into the process. This operation is called *swapping out*. - This is not a cheap operation, so VM tries to minimize context switches. - - A context switch is also performed when changing from BEAM code to native - compiled code by HiPE or JIT. This is why mixing HiPE and normal Erlang - code in your program, which calls each other, is an expensive luxury. - -.. _def-cp: - -**CP, Continuation pointer** - A raw pointer to a location in prepared BEAM code. - It is used as a return value or as a label offset. - CP and can only be found on the stack, never in registers or on heap. - -.. _def-header: - -**Header tag** - When a box is referenced or when a block of memory is stored in heap, - its first :ref:`Word ` usually has few least-significant bits - reserved (currently 6). First goes the primary tag (2 bits of - ``TAG_PRIMARY_HEADER=0``). Then follows the header tag (4 bits) which - defines the type of contents. Remaining bits may hold other information, - often these bits store the arity (contents size). - -.. _def-immed: - -**Immediate** - A term value, whose :ref:`primary tag ` is - ``TAG_PRIMARY_IMMED1=3`` contains an immediate value. Two bits follow the - primary tag and determine the value type (``TAG_IMMED1_*`` macros). - If the immediate-1 tag equals ``TAG_IMMED1_IMMED2=2`` then two more bits - are used to interpret the value type (``TAG_IMMED2_*`` macros). - - Examples of immediate: - **small** integers, local **pids** and **ports**, **atoms**, - empty list ``NIL``. - An immediate value fits into one :ref:`Word ` - and does not reference any memory. - -.. _def-heap: - -**Heap** - Dynamically allocated block of :ref:`Words ` used by a process. - Heap can be resized with help of either ``ERTS_REALLOC*`` macro or by - allocating a new fragment and moving data there using garbage collector. - Data is placed onto heap sequentially from its start. - -.. _def-port: - -**Port** - A special value which you receive when you call ``erlang:open_port``. - It is hooked to a port driver (built-in or custom). You can send it commands - and receive messages from it, you can close it, link to it and monitor it - (monitoring added in v.19). - - A port driver manages some resource, such as a file, a socket, a ZIP - archive etc. Ports provide your process with a stream of events from - some resource, and you can write commands and data to them as well. - -.. _def-primary-tag: - -**Primary Tag** - When a term value is encoded, several least-significant bits (currently - 2 bits) are reserved to represent type of contained term. - - Term tag can be: - a :ref:`box ` (``TAG_PRIMARY_BOXED=2``), - a list (``TAG_PRIMARY_LIST=1``), - a :ref:`header ` (``TAG_PRIMARY_HEADER=0``) - or an :ref:`immediate ` (``TAG_PRIMARY_IMMED1=3``). - -.. _def-reduction: - -**Reduction** - Each instruction or a call has a cost, it uses imaginary units called - *reductions*, where 1 reduction is approximately one function call. - Cost of other calls and operations is derived from this approximately. - -.. _def-registers: - -**Registers** - An array of :ref:`Words ` used to pass arguments in a function - call. When a recursive call is made, affected registers are also saved onto - the stack. - -.. _def-roots: - -**Roots** - During garbage collection, the roots are all known to be live values, - they are collected from: - - * the stack - * the live registers - * the process dictionary - * the message queue - * the group leader and the exception reason fields. - - Anything that can be traced by following references from the roots is - considered to be reachable data. - This data is moved to the new heap. - Previous heap is discarded, because no data can be reached on it anymore. - -.. _def-scheduler: - -**Scheduler** - Scheduler is a loop which runs on a fixed CPU core and it either fetches - and executes next instruction based on instruction pointer in current - process, or takes next process in the queue. As soon as a process has been - running for certain number of :ref:`reductions ` (say 2000 - but number may change), it is scheduled out and put to sleep, and next - process takes its place and continues running where it left off. This allows - some sort of fair scheduling where everyone is guaranteed a slice of time, - no matter how busy some processes are. - -**Slot** - A special tagged value which points at a register, float register, or a - stack slot. It is used internally by instructions and never appears in - Erlang programs as data. - -.. _def-stack: - -**Stack** - A section of young heap of a process, which is used as temporary storage and - return stack by a process. A new process creates a stack which has zero size - and begins at the ``heap_end``. - Stack grows back (decrementing memory address) until it meets - heap write position (``heap_top``). Then heap is considered full - and garbage collection will trigger. - - Data on stack is grouped into :ref:`Stack Frames `. - -.. _def-stack-frame: - -**Stack Frame** - Functions can create a stack frame by pushing a :ref:`CP ` value - and reserving several extra words on stack. Sometimes, when code throws an - exception, VM scans the stack to build a stacktrace and uses these CP values - as markers. - - Each frame corresponds to a function call. A frame always begins with a - CP value which marks a return address can be used to find a frame boundary. - Rest of the frame is used to store any temporary variables and register - values between the calls. - -.. _def-term: - -**Term** - A term is any value in Erlang. Internally a term is a :ref:`Word ` - with few least-significant bits reserved (2 to 6 bits depending on the value) - which define its type. Remaining bits either contain the value itself (for - :ref:`immediate ` values) or a pointer to data on heap - (:ref:`box ` values). - -.. _def-terminate: - -**Terminating a Process** - An exit or kill signal is sent to a process which works similar to an - exception. If process was able to catch an exit signal (``trap_exit``), then - nothing else happens. - - Process that is going to die will free its memory, trigger all monitors - and links, leave the process queue and get unregistered from the process - registry. - -.. _def-nonvalue: - -**THE_NON_VALUE** - Internal value used by emulator, you will never be able to see it from Erlang. - It marks exception or special type of return value from BIF functions, also - it used to mark memory during garbage collection. - - Depending on whether ``DEBUG`` macro is set and HiPE is enabled, - ``THE_NON_VALUE`` takes value of primary float header - (6 least-significant bits are ``0110-00``) with remaining bits set - to either all 0 or all 1. Or it is all zero-bits :ref:`Word ` - (marking a zero arity tuple on Heap), which never can appear in a register, - thus marking it useful to be the special return value. - -.. _def-word: - -**Word** - Machine-dependent register-sized unsigned integer. This will have width of - 32 bits on 32-bit architecture, and 64 on a 64-bit architecture. - In BEAM source code Word can be unsigned (UWord) or signed (SWord). diff --git a/docs/build/html/_sources/eli5-atoms.rst.txt b/docs/build/html/_sources/eli5-atoms.rst.txt deleted file mode 100644 index 1029fc5..0000000 --- a/docs/build/html/_sources/eli5-atoms.rst.txt +++ /dev/null @@ -1,30 +0,0 @@ -Atoms ELI5 -========== - -.. image:: _static/img/eli5-atom-tab.png - :width: 300 - :align: right - - -Atom table is a global table which maps internal atom value (an integer) to a -string. There is also the opposite lookup table, which maps a string to an -internal value. Atom table has a hard size limit: 1048576. If it is ever -reached, the node will crash --- this is why creating atoms in runtime is a -risky idea. Atom table size is set with ``+t`` flag for ``erl``. - -Atom is a symbol which does not change its value in runtime. When a new atom -is created, it gets a unique value for this node used as its value. -Internally atoms are just integer values referring to atom table. This is why -atoms operations are cheap. - -BEAM loader routine reads atom values and looks them up in atom table. It -replaces atom names with their integer values, tagged as Atom -:ref:`immediate `. Henceforth the code manipulates immediate integer -values instead of names. - -These internal values cannot leave the node (over the network or on disk) as -integers. This is because another node will have different numeric values -for atoms. Thus when leaving the node atoms are always converted to strings. -This affects BEAM files, external pids, external ports, atoms in Mnesia/DETS -and so on. This is the reason why sometimes developers prefer short atom names -for database field names — they will appear as strings in database data. diff --git a/docs/build/html/_sources/eli5-bif-nif.rst.txt b/docs/build/html/_sources/eli5-bif-nif.rst.txt deleted file mode 100644 index 0cdfda8..0000000 --- a/docs/build/html/_sources/eli5-bif-nif.rst.txt +++ /dev/null @@ -1,54 +0,0 @@ -BIF and NIF functions ELI5 -========================== - -BIF Functions -------------- - -Unless you work on OTP C source, you will never have to create own BIF function. -If you want to implement own native function for your project, -check out the next section about NIFs! - -In the standard Erlang library most functions are implemented in Erlang. But -many features of the virtual machine and internal functions are impossible -to reach from pure Erlang. So they were written in C and are exported as BIF ---- built-in functions. -BIFs are used in standard Erlang libraries and are statically built into -emulator during compile-time. - -When reading Erlang standard library modules you often can see functions -with a single call to ``erlang:nif_error(...).`` -These are BIF stubs. -BEAM loader finds the native library and replaces these stubs with references -to native implementation in C. -You can also create BIF or NIF functions in other languages like C++ or Rust. -You should also register a new BIF in a special file, called ``bif.tab`` which -connects module:function name and the BIF when you build the emulator. - -If you are curious, search for some function in OTP C source, for example: -``lists_reverse_2`` in ``erl_bif_lists.c``. -A BIF function takes ``Process`` pointer and a pointer to registers, where it -can access as many :ref:`Term ` (``Eterm`` C type) registers as it needs. -A BIF must return a :ref:`Term ` value or a ``THE_NON_VALUE`` -for special execution control features like traps, yields and exceptions. - - -NIF Functions -------------- - -NIFs are a different way of making native functions, more suited for separate -compilation and to be loaded by user modules. -NIF interface and type system is also simplified --- they abstract away and -hide many internal types, bits and fields of the emulator. - -There is a good `NIF tutorial`_ in standard documentation and about a million -of NIF functions written by users and available in various Github projects. - -.. _NIF tutorial: http://erlang.org/doc/tutorial/nif.html - -Still even if it is simplified, one must be careful! A badly written NIF is -able to tip over the whole virtual machine or hog the resources and slow the -execution to a grind. - -.. seealso:: - BEAM Wisdoms: :doc:`interfacing` for a list of NIF, interoperability - libraries, and port drivers for different programming languages. diff --git a/docs/build/html/_sources/eli5-efficiency-memory-perf.rst.txt b/docs/build/html/_sources/eli5-efficiency-memory-perf.rst.txt deleted file mode 100644 index e84940f..0000000 --- a/docs/build/html/_sources/eli5-efficiency-memory-perf.rst.txt +++ /dev/null @@ -1,125 +0,0 @@ -Memory Performance ELI5 -======================= - -Data Locality -------------- - -In recent decades performance of computer memory did not grow as fast as -performance of CPUs has improved. -To offset impact of memory low performance several levels of CPU caches -are used which store recently accessed data closer to the CPU. -When you access any byte in memory, larger blocks of data are loaded to -cache or flushed at once (these are called cache rows). - -The general rule of gaining best performance is to store relevant data close -together. From Erlang point of view it means also creating all -relevant data together which will place them together in process heap. - -If the data is large, it should be grouped to allow sequential -processing. And the cost of memory access can be so high that some values -are cheaper to calculate instead of loading them from some cold -(uncached and rarely read) memory location. - -Hot (often accessed) memory is a welcome place to store -your variables and working data, for C and C++ programs this is program stack -and for C++ this would be fields of your current class object, because it -always was accessed recently. It is harder to say which memory is hot for -Erlang, as we don't control much of its behaviour, but there are some tricks -that affect data placement on heap and how it will perform after. - - -Cache Miss ----------- - -A "cache miss" is a special situation which occurs when CPU accesses some data -and the data wasn't in cache. A cache row (64 bytes) of data are requested -from main RAM. CPU is forced to wait for the data. If possible the CPU -will try and do some other work by reordering machine instructions, but -this does not always happen and just assume that it is waiting for the data. - -Typical cost of a cache miss is ~100 CPU cycles. This is a lot of time, -many simpler values can be calculated without accessing memory and save -significant time with not reading the main RAM. - -Even worse if your program runs on a large production server with hundreds -GB of memory, then most likely it uses non-uniform memory architecture (NUMA) -and the memory is divided between CPU cores. The cost of a cache miss on -such machines is even higher, especially if accessing part of RAM "owned" -by another CPU core. Erlang and BEAM VM is aware about this and does its -best to preserve the core locality of used memory. - -So when you are optimizing your awesome algorithm which now is perfect and -doesn't run any better no matter the effort, have a look at how it works with -memory. The reward for using memory efficiently is your code running -much faster! - - -Data Types ----------- - -.. note:: - Major garbage collection of a process will order its data in - memory by placing all list cells together, and tuple values will follow the - tuple in memory. This is very good for memory locality although moving all - this data might be super expensive. - -.. note:: - - **For memory-heavy operations** - consider owning the data in the process which does the work instead of - requesting it from ETS or database while doing the work. - Keeping at most one memory-intensive process per available CPU core is - welcome, let the BEAM VM do the rest for you. - Also consider doing a major GC on your worker process before running a - big calculation (see ``erlang:garbage_collect``). - -Immediate Values -```````````````` - -These values are smallest, they always fit into a CPU register and there is -not much you can do to make them work any faster. They are atoms, -small integers, local pids etc. - -Lists -````` - -Lists in BEAM are represented as single-linked lists of value pairs (cells). -If a list is created in a complex algorithm slowly, its cells might be sparsely -distributed in memory interleaved with other data created at the same time. -This may lead to inefficient CPU cache usage. A way to offset this -is to create your large working lists in tight loops while not creating other -unnecessary data. This will place list cells tightly together with their values. -When it is not possible, you can always invoke a major garbage collection and -have everything sorted for you (at a cost). - - -Tuples -`````` - -As tuples are stored as arrays, they are cache friendly. If a tuple contains -other data structures such as lists or tuples, the data will be stored somewhere -else on heap and the tuple will only contain pointers to it. -Even better if a major garbage collection was performed recently which sorts -your data in memory and groups it together. - - -Floats -`````` - -Even if a floating point value fits into a CPU register and has same size as -an immediate value (small integer or atom etc), actually they are -stored on-heap with a header word marking their presence. This makes floats -consume double the memory and each access to them will dereference a pointer -to a possibly cold memory location where no other floats are stored. - -Best you can do here is to create your arrays or lists of floating point values -in tight loop together, which will maximize how many floats are cached when -a single cache row of 64 bytes is loaded. -Or run a major GC to group them automatically. - - -ETS Tables -`````````` - -There is not much you can do to affect ETS table memory behaviour, so here -you are at the mercy of BEAM VM developers. diff --git a/docs/build/html/_sources/eli5-efficiency.rst.txt b/docs/build/html/_sources/eli5-efficiency.rst.txt deleted file mode 100644 index 8991541..0000000 --- a/docs/build/html/_sources/eli5-efficiency.rst.txt +++ /dev/null @@ -1,42 +0,0 @@ -Efficiency ELI5 -=============== - -Data copying ------------- - -Here are general rules regarding data copying and performance. - -* Data is stored in process heap most of the time. -* As long as data is moved **inside** the owning process, it is **not copied**, - only a pointer is passed. -* If the data ever leaves the process, a message for example, it will be - **copied** to its new owner. -* If the data is moved to or from ETS, it behaves similarly, it will be - **copied** (ETS has own heap separate from any process). -* If the data is moved between a process and a port, it will be **copied** - (ports behave similar to processes, and own resources in a similar way). -* Large binaries >64 bytes are **never** copied, instead they are reference - counted and reference is shared between processes. This is why you want to - GC periodically all processes which have touched a large binary, otherwise it - may take a long time before the binary is freed. - - -Literals (Constants) --------------------- - -All Erlang values in your module (literals) are saved in the module file and -then loaded when your module loads. -These values are stored in special memory area called constant pool and later -when you reload your code the garbage collector will move old constants to your -process heap (see note below, this has changed in OTP 20.0). - -Accessing a literal value of any size is cheap. You can use this trick to define -large constant structures, lookup tuples with cheap element access, -store large binaries in code etc. - -.. note:: - - In Erlang versions prior to 20.0 a constant value will be copied when - crossing process boundary (explained above in "Data Copying"). This has changed - in version 20.0 - (OTP-13529 in `Release Notes `_ ) diff --git a/docs/build/html/_sources/eli5-etf.rst.txt b/docs/build/html/_sources/eli5-etf.rst.txt deleted file mode 100644 index 84e0fdc..0000000 --- a/docs/build/html/_sources/eli5-etf.rst.txt +++ /dev/null @@ -1,39 +0,0 @@ -External Term Format ELI5 -========================= - -To communicate with the outer world and other Erlang nodes, also to save things -on disk, Erlang uses special encoding --- External Term Format. - -The main requirements to the format: - -* Easy for human and machine to see an encoded term and what it is. An external - term always starts with byte 131 (``0x83``). -* Compact with optional compression. - A tag 131 (``0x83``), 80 (``0x50``), U32/big length marks a compressed term. -* Cross-platform, all integers are encoded as - `big endian `_ (from most - significant bytes to least), - floats use big endian - `IEEE encoding `_, - text uses UTF-8 or ISO-8859-1 (ASCII superset). - -To encode a term see ``erlang:term_to_binary`` and the opposite operation is -``erlang:binary_to_term``. - -Decoding a crafted binary allows us to construct terms which are impossible to -make with standard library functions, such as non-existing ports and pids. - -Usually atoms are encoded as strings. -But in the distributed mode (over the network) to further reduce the protocol -size a distribution header can be added. -It contains a table of atom names which are included in the encoded message. -Atoms in the message are placed in this table and their occurences are replaced -with indexes. - -It is impossible to encode internal VM value types which never appear in -Erlang programs, such as ``THE_NON_VALUE``, references to registers, CP -(continuation pointer) etc. - -.. seealso:: - `External Term Format `_ - documentation. diff --git a/docs/build/html/_sources/eli5-io.rst.txt b/docs/build/html/_sources/eli5-io.rst.txt deleted file mode 100644 index 56652f0..0000000 --- a/docs/build/html/_sources/eli5-io.rst.txt +++ /dev/null @@ -1,49 +0,0 @@ -Input/Output and Ports ELI5 -=========================== - -A main reason why people run computer programs is to have side effects. A pure -program without side effects will consume watts of power, warm up -your room and do nothing else. To connect programs to the outer world, there are -input and output features in every language. For example: reading and writing -files, accessing hardware ports or interacting with OS drivers, drawing on -screen and so on. - -Erlang does this with ports, driven by small C modules, called *port drivers*. -Some drivers are built into Erlang, and some you will have to create yourself, -or pay someone to do it for you. For many port problems there may already be a -solution on Github (Unix pipes as example). - -When you connect to a resource to start using it, you receive a -:ref:`Port ` value back. It behaves similar to a process: it consumes -CPU time to process your data, you can send messages to it, also it can send -messages back to you. You can link to a port or monitor a port (monitors added -since v.19). - -Port Tasks ----------- - -Each port similar to processes gets assigned to one scheduler. -Every scheduler on each CPU core will periodically check assigned ports and -perform polling and maintenance (this is called running port tasks). -This gives CPU time to port drivers to perform actual IO and deliver results -to the processes who are waiting. - -To improve this situation and to separate port tasks from schedulers, so that -they don't affect main code, Async Threads have been invented. -VM creates extra CPU threads which have only one primary goal --- -to serve IO tasks. - -This can be controlled with ``+A`` command line flag. -Default value is 10 async threads. - -Port Driver ------------ - -A C module can be registered by name as a port driver. You can specify, which -driver to invoke, when opening a port. -Port driver performs several basic commands as opening, closing a port, sending -data to it or reading from it. Socket interface, OS process spawning -- for -example they are implemented as port drivers. - -.. seealso:: - Technical details :doc:`indepth-io` diff --git a/docs/build/html/_sources/eli5-process-heap.rst.txt b/docs/build/html/_sources/eli5-process-heap.rst.txt deleted file mode 100644 index 545481b..0000000 --- a/docs/build/html/_sources/eli5-process-heap.rst.txt +++ /dev/null @@ -1,76 +0,0 @@ -Process Heaps ELI5 -================== - -Everything in Erlang is a :ref:`Term `. - -A heap of the process is an array of :ref:`Terms `. A stack is -another array of :ref:`Terms `. Stack is located inside the heap. -:ref:`Registers ` --- are array of :ref:`Terms ` too! -Things on the heap are mostly arrays of :ref:`Terms `, but tagged -with :ref:`header tag ` (see :doc:`indepth-memory-layout`). - -Heap Carriers -------------- - -Allocation in Erlang happens inside so called “carriers”. They look like -“zone memory”, used by games — big chunks of system heap pre-allocated -beforehand. Inside carriers the real allocation is happening. For simplicity -you can imagine simple malloc/realloc, that’s how its done. - -This complication is done to fight memory fragmentation and is not important -for the understanding. -You can see ``erts/emulator/beam/erl_*alloc.c`` (many those files, one per -strategy of allocation). Emulator has command line flags, which control -allocation strategies (see http://erlang.org/doc/man/erts_alloc.html flags -section). - -Allocating Inside Heap ----------------------- - -When a process needs some memory, its ``heap_top`` is incremented and memory -under it is ready to use. Some activities may want to allocate on other -process' heaps, for example sending a message will perform a copy to the -receiving process. - -No bookkeeping is happening inside a process heap. -There is no tracking which word belongs where, but it is possible to know -what is stored in each memory cell by looking at the tag bits. - -Garbage Collection ------------------- - -Garbage collector traces known live values from registers and stack and saves -them, then drops everything else. - -When a heap comes to its capacity threshold (something like 75%), the process -triggers garbage collection. A new bigger heap may be allocated. -Scanning generational garbage collection algorithm runs on the heap. -The algorithm takes the “:ref:`roots `” and moves them to the -new heap. -Then it scans the remaining parts of source heap -and extracts more values, referred by the roots. After the scanning, source -heap contains only dead values and algorithm drops it. - -"Scanning" means, that garbage collector follows the data -:ref:`roots ` from the start to the end, parsing everything it meets. -"Generational" means, that algorithm splits data into young and old generation, -assuming that data often dies young, and old data is less likely to be freed. -Also the algorithm remembers the old position (``mature``), where the previous -scanning has finished. -Any data below it is guaranteed to have not updated since the last scan. -This trick reduces amount of scanning and speeds up the algorithm. - -In reality the picture is a bit more complicated. There can be one or two -heaps with different placement logic applied to them. - -Having garbage collector run per process heap allows Erlang to keep -collection latency low. Also it doesn’t pause or affect other processes on -other schedulers. This is not a simple topic, but theory is all here: -http://gchandbook.org/ - -.. seealso:: - BEAM Wisdoms: In depth: :doc:`indepth-heap-layout`. - - BEAM Wisdoms: In depth: :doc:`indepth-memory-layout`. - - `Garbage Collector in Erlang 19 `_ diff --git a/docs/build/html/_sources/eli5-processes.rst.txt b/docs/build/html/_sources/eli5-processes.rst.txt deleted file mode 100644 index 46b1c99..0000000 --- a/docs/build/html/_sources/eli5-processes.rst.txt +++ /dev/null @@ -1,165 +0,0 @@ -Processes ELI5 -=============== - -This is a high level overview for how processes are made and how they work. - -General overview ----------------- - -A process is a simple C structure, which contains -a :ref:`heap `, -a :ref:`stack `, -:ref:`registers `, -and an instruction pointer. Also, there are some extra fields for exception -handling, tracing etc. A new process is this structure created with a minimal -size heap. - -Spawning a new Process (Actor) -`````````````````````````````` - -When you call `spawn` or `spawn_link`, the VM allocates a small piece of memory -with a new process header (approx 200-300 bytes) and the {heap with the stack} -(they live together and take about 1kb initially). A new process is granted a -new unique PID, which won't repeat for a fair amount of days or months after its -death, and is registered in a process lookup table. - -There are no messages involved in process creation only a couple of memory -allocations. - -So the newly created process is not known to any scheduler yet. It is then -placed into a run queue for its priority (99.99% of processes run as normal), -where one of schedulers is able to pick it up and begin executing. Newer -versions of Erlang have run queues one per scheduler, but the principle is -the same. - - -Stack -````` - -.. image:: _static/img/eli5-process-stack.png - :width: 300 - :align: right - -:ref:`Stack ` is an array of memory on the young heap used as return -stack and temporary storage for variables. Stack begins at the end of the heap -and grows back (downwards). -The data on stack is grouped into :ref:`Stack Frames `. - -When a function needs some temporary memory, it allocates several words on the -stack and marks the 0-th word with special CP value. Later it can be used -as return address and to find out where next stack frame begins. This temporary -memory is also used to preserve registers during recursive calls (thus growing -the stack). - -Tail-recursive calls avoid keeping this temporary data or free it before -recursing. They pass arguments in a smarter way that does not require saving -them on stack and does not grow it. - -Execution -````````` - -Every new process is assigned to a :ref:`Scheduler `. -Scheduler picks one process from the queue and takes its instruction pointer. -Then scheduler executes one instruction and loops. After certain amount of work -done (:ref:`reductions `) scheduler will place the current -process to the back of the queue and select another one. This allows some sort -of fair scheduling: every process gets CPU time no matter how busy were other -processes in the queue. - -Killing and Exiting -``````````````````` - -Killing a process is like sending it an exit exception. The process wakes up -from sleep, receives CPU time, and discovers an exception. Then it will either -:ref:`terminate ` or catch the exception and process it like -a regular value. An unconditional ``kill`` signal works similarly except that -Erlang code cannot catch it. - -Scheduling and Load balancing ------------------------------ - -.. image:: _static/img/eli5-process-sched.png - :width: 300 - :align: right - -By default BEAM VM starts one Erlang scheduler per CPU core. Processes get a -scheduler assigned to them in some manner (for simplicity you can say it is -random). You can configure schedulers using flags ``+S`` and ``+SP``. Schedulers -can be bound to cores in different ways (``+sbt`` flag). - -There are 4 process priorities: low, normal, high and max. -Process at max always runs first making everything else wait. -High runs approximately 8 times much often than normal (the number -is implementation dependent). -Low runs when there is no other work to do. - -At runtime schedulers will compare their process queue with the other (namely -the previous one in scheduler array). If the other queue is longer, the -scheduler will steal one or more processes from it. This is the default -behaviour which can be changed. The balancing strategy and can be configured -with VM flags ``+S`` and ``+scl``. You could want to use as few cores as -possible to let other CPU cores sleep and save energy. Or you could prefer -equal spread of processes to cut the latency. - -Stealing is as easy as moving a pointer from one array to another. This may -affect :ref:`cache locality ` when an active process -jumps CPU core. - -Process Registry ----------------- - -A global process table maps process identifier (pid) to a Process structure. -To know a pid of a process, refer to its ``Process.common.id`` field. A process -is uniquely identified by its local pid. Remote pids contain more information: -a node name and internal node id. Remote pids have to be resolved on the node -which owns them. - -Another global table (process registry) maps names to pid. You can reach it -from Erlang by using ``erlang:register``, ``erlang:unregister`` and -``erlang:whereis`` BIFs. - -Message Queues --------------- - -.. image:: _static/img/eli5-process-mqueue.png - :width: 300 - :align: right - -Messages are stored on the heap or in heap fragments, and are chained together -using a single linked list. Message queue is a C structure which belongs in -Process struct and it contains :ref:`Terms ` sent to the process. -:ref:`Boxed data ` for larger or nested terms is located on the heap. -A pointer to position in the queue exists, and it is advanced with BEAM -opcodes which scan the mailbox. -When scan pointer reaches the end of the mailbox, the process is put to -receive sleep. -The pointer is reset to the beginning of the queue only if a message was matched. -This is why selective receive on large mailbox queues is slow. - -Sending a Message -````````````````` - -Sending a message to a process is simple — this is how VM does it: - -1. Lock the process mailbox (or don't, if running on a single core). -2. Copy message to destination process heap. -3. Add the resulting term to process mailbox. -4. Unlock the mailbox. -5. If the process was sleeping in a receive, it would return back to - scheduling queue and wake up when possible. - -A process waiting for a message (in receive operator) is never queued for -execution until a message arrives. This is why millions of idle processes can -exist on a single machine without it breaking a sweat. - -Traps ------ - -Traps are a feature of the VM loop which allow to interrupt long running BIFs -temporarily. State is saved in temporary memory block and control returns to -the scheduler. Process sets its instruction pointer to the special trap -instruction and the BIF returns. - -During the trap the current process is placed to the back of the process queue -which allows other processes to run. When the time comes again, the VM loop -encounters the trap instruction and jumps back to the long running BIF. diff --git a/docs/build/html/_sources/eli5-property-based.rst.txt b/docs/build/html/_sources/eli5-property-based.rst.txt deleted file mode 100644 index fd4f7a8..0000000 --- a/docs/build/html/_sources/eli5-property-based.rst.txt +++ /dev/null @@ -1,65 +0,0 @@ -Property Based Testing ELI5 -=========================== - -Assume you know about regular unit testing, possibly you've heard about the -common test. -There is another way to check your system, different from ordinary testing -methods. It is called *property based testing*. - -To make a test one should define types and ranges for the input data, -which the system will take under the test. -Definition of input data looks like a tuple with type and range argument -descriptions. They are *data*, and you build this data before the test. - -Then the test engine will call your code with random combinations of defined -input data. -Test engine tries to observe if the *system under test* still shows the -defined properties. - -If at some moment the required property is not observed, test will stop and -engine will try to shrink the input. -This is an attempt to find simplest input data which still breaks the test. -Test engine will try to reduce complexity for as many parameters as possible. - -.. seealso:: - - Libraries which offer property based testing: - `PropEr `_ and - `Quviq QuickCheck (commercial) `_ - (note that QuickCheck also exists for other languages!) - -Example -------- - -Imagine that your boss asked you to write a ``fizz_buzz`` function. -From the documentation it is clear, that a good ``fizz_buzz`` takes an integer -argument between 1 and 100. -Also it will return ``fizz`` for arguments that are divisible by 3, -``buzz`` for arguments that are divisible by 5, -``fizbuzz`` for arguments divisible by both 3 and 5. - -So the input range: it is an integer between 1 and 100. - -And 3 properties we want to observe: - -1. When ``X rem 15 =:= 0`` we want to see ``fizzbuzz`` as return value. -2. When ``X rem 3 =:= 0`` we want to see ``fizz``. -3. When ``X rem 5 =:= 0`` we want to see ``buzz``. - -.. note:: - - Please consult actual documentation for the selected test library. - The syntax of the library calls differs. - -Test engine will apply random combinations of values from the defined input range. -Test engine will ensure that all 3 properties are observed during the run. - -.. note:: - - You can test any black box system this way, without knowing its internals. - The *system under test* can be a C program or even a real piece of hardware! - - It is also possible to run parallel tests - (ensure that a parallel system doesn't break when things happen in parallel) - and state machine tests - (ensure that a state machine doesn't break under the random input). \ No newline at end of file diff --git a/docs/build/html/_sources/eli5-tracing.rst.txt b/docs/build/html/_sources/eli5-tracing.rst.txt deleted file mode 100644 index 93724c3..0000000 --- a/docs/build/html/_sources/eli5-tracing.rst.txt +++ /dev/null @@ -1,41 +0,0 @@ -Tracing ELI5 -============ - -How does Erlang VM perform tracing of calls, messages, processes spawning and -passing away? - -Tracing is a VM mode, that can be toggled on and off, and starts producing a -stream of events. -A call to ``dbg:tracer()`` starts a process which will receive this stream. -You can create your own tracer with its own state and feed events to it. - -Tracing is able to produce overwhelming amount of irrelevant data. -To limit this data a trace filter is applied with ``dbg:tp/4`` (and similar). - -When everything is prepared: a tracer and a filter, it is time to open the -valve. A call to ``dbg:p/2`` (and similar) sets the trace target (a process, -a port, spawn and exit events, everything, and so on). -It will start sending everything that matches trace target and the filter -you've set to the tracer process. - - -Inner Workings of the Tracing ------------------------------ - -Simple things, like process lifetime events or messages have tracer checks -in place everywhere in the virtual machine's C code. If tracing is enabled, -then a message is sent to the current tracer. - -Tracing calls and returns from BIF functions is a bit more complex. Because BIF -are not real Erlang code, they have to be wrapped in a tracing code somehow. -This is done by replacing BIF table with BIF entry function addresses with -another table. -Each entry in this new table is a simple call to ``erts_bif_trace`` with a -function name and arguments. -This function performs the real call and sends trace messages. - -At certain moments, when we want to trace a BIF trapping and returning to -execution later, another trick is used. -Address to a special BEAM opcode is pushed onto the stack before the BIF is -finished. This allows to catch up when trap continues execution and will send -the trace event correctly when the BIF was finished. diff --git a/docs/build/html/_sources/eli5-types.rst.txt b/docs/build/html/_sources/eli5-types.rst.txt deleted file mode 100644 index 97f7666..0000000 --- a/docs/build/html/_sources/eli5-types.rst.txt +++ /dev/null @@ -1,75 +0,0 @@ -Types ELI5 -========== - -Erlang is dynamically typed language. It means that any variable, -field or function argument can contain any allowed value. - -Type Specs ----------- - -There is the type description language, which you can use to -describe what YOU think your functions should take and return. -These type specs are optional and the compiler will run your program like -nothing happened even if a type violation exists. -To ensure that your type specs do not contradict each other, there is -another tool called Dialyzer. - -A type spec is a directive in source ERL file, which looks like - -.. code-block:: erlang - - -spec func_name(Arg :: integer(), _, Y :: any()) -> float(). - -Type specs are not code, they neither run nor prevent your program from compiling. - -.. seealso:: - You can read more about specifying types of your program in - `Typespec Reference Manual `_ - and other existing books, such as - `Learn You Some Erlang `_ - -Dialyzer --------- - -Dialyzer takes compiled BEAM or ERL source files as input, then -tries to guess types (type inference). - -How This Works -`````````````` - -Say you have written a function, ``f`` which takes one argument ``X`` and -returns something. -Dialyzer first does a general assumption that ``f`` is a ``fun()``, which -takes any value (``X :: any()``) and returns whatever (``any()``). -This is what Dialyzer guesses initially: - -.. code-block:: erlang - - -spec f(X :: any()) -> any(). - -``Any()`` is the widest type possible which covers any value. -Then Dialyzer analyzes usage of this function and its code and -tries to reduce argument and return types to more narrow -specific set of types. - -For example, if Dialyzer discovers that the only two places -which call your function ``f`` pass an integer or an atom -argument, then ``X``'s type is reduced to ``integer()|atom()`` -(a set of two types). This is what Dialyzer may possibly calculate: - -.. code-block:: erlang - - -spec f(X :: integer() | atom()) -> any(). - -If Dialyzer finds a contradiction, i.e. some types collapse to an empty type -(``none()``) or incompatible types are found, Dialyzer reports an error. -These errors may look confusing, but they often (always?) point to an -existing problem in the code. - -Typer ------ - -Typer is another optional tool, found in your OTP distribution. -Using same algorithm as Dialyzer, it infers the types for a given module and -prints them. You can take them and insert into your program for future use -or to better document a large legacy project. diff --git a/docs/build/html/_sources/eli5-vm.rst.txt b/docs/build/html/_sources/eli5-vm.rst.txt deleted file mode 100644 index c63e6e5..0000000 --- a/docs/build/html/_sources/eli5-vm.rst.txt +++ /dev/null @@ -1,70 +0,0 @@ -BEAM VM ELI5 -============ - -BEAM got its name from Bogdan/Björn Erlang Abstract machine. This is register -VM, but it also has a stack. - -Registers and Calls -------------------- - -Being a register VM means that stack is not used to pass arguments -between calls, but registers are. They are not same registers as one would -expect to see in a CPU architecture, but rather just an array of -:ref:`Term ` values. There are 1024 registers but functions of such -arity are rare, so usually VM only uses first 3 to 10 registers. - -For example, when a call to a function of arity 3 is made: registers x0, x1, -and x2 are set to function arguments. If we ever need to make a recursive -call, we will have to overwrite registers and lose the original values in -them. In this situation, we will need to save old values on the stack. There -is no dynamic stack allocation other than stack frame, determined by the -compiler. - -Each process has own set of registers. - -Instructions ------------- - -BEAM instruction set contains approximately 158 basic instructions, most of them -can be visible if you dump assembly by calling ``erlc -S yourfile.erl``. Each -instruction has 0 or more arguments. Different tricks are used to encode -arguments in a portable and compact way. For example locations in code (so called -labels) are encoded by their index, and code loader later translates them to -memory addresses. - -During BEAM code loading, some combinations of opcodes are replaced with a -faster opcode. This is optimisation trick called *superinstruction*. -For each opcode, there is a piece of C code in ``beam_emu.c`` which has a -C label. An array of C labels is stored at the end of the same VM loop routine -and is used as the lookup table. - -.. seealso:: - BEAM Wisdoms: In depth: :doc:`indepth-beam-file`. - - BEAM Wisdoms: In depth: :doc:`indepth-beam-instructions`. - -Threaded VM Loop ----------------- - -VM emulator loop in ``emulator/beam/beam_emu.s`` contains a lot of small -pieces of code, each having a label and handling one BEAM instruction. -They all belong to one very long function. -A table of labels is stored in the same function which is used as lookup table. - -After the loading opcodes are replaced with such label addresses, followed by -arguments. For example, for opcode #1, an element with index 1 from labels -array is placed in the code memory. - -This way it is easy to jump to a location in C code which handles next opcode. -Just read a ``void*`` pointer and do a ``goto *p``. This feature is an -extension to C and C++ compilers. This type of VM loop is called -*direct-threaded dispatch* virtual machine loop. - -Other types of VM loops are: - -* *switch dispatch* VM (this one is used by BEAM VM source if the C compiler - refuses to support labels extension. It is also 20 to 30% slower than direct - threading; -* *direct call threading* -* and a few more exotic - http://www.cs.toronto.edu/~matz/dissertation/matzDissertation-latex2html/node6.html diff --git a/docs/build/html/_sources/indepth-beam-file.rst.txt b/docs/build/html/_sources/indepth-beam-file.rst.txt deleted file mode 100644 index d6337c9..0000000 --- a/docs/build/html/_sources/indepth-beam-file.rst.txt +++ /dev/null @@ -1,338 +0,0 @@ -BEAM File Format -================ - -BEAM file format is binary chunked file format, which contains multiple named -sections and has a header. - -* Read 4 bytes of a .beam file: ``'FOR1'`` - (marks `IFF container `_). -* Read U32/big length (so many more bytes must be available in the file) -* Read 4 bytes ``'BEAM'`` marking a BEAM file section of an IFF file. - -Sections --------- - -Repeat until end of file: - -* Read 4 bytes chunk name (for example can be: Atom, Code, CatT, FunT, ExpT, - LitT, StrT, ImpT, Line, Abst and possibly other chunks). - Do a sanity check: Must contain ASCII letters. -* Read U32/big chunk length. This is the data size. -* Perform chunk-dependent reading (see subsections below) -* To find next chunk, pad the length to the multiple of ALIGN=4 - - .. code-block:: c - - file_pos += ALIGN * ((chunk_length + ALIGN - 1) / ALIGN); - -"Atom" and "AtU8" - Atoms Table -``````````````````````````````` - -Both tables have same format and same limitations (256 bytes max length) -except that bytes in strings are treated either as latin1 or utf8. - -* Read U32/big atoms count. -* For each atom: read byte length, followed by characters - -Atoms[0] is a module name from ``-module(M).`` attribute. - -"Code" - Compiled Bytecode -`````````````````````````` - -* Read U32/big code version (must match emulator's own version) -* Read U32/big max opcode, U32/big label count, U32/big fun count -* Read the code as a block. Format is discussed at :ref:`beam-code-format`. - -"Abst" - Abstract Syntax Tree -````````````````````````````` - -Optional section which contains ``term_to_binary`` encoded AST tree. - -A quick way to get ``Abst`` section (if it exists): - -.. code-block:: erlang - - get_abst(Filename) -> - Chunks = beam_lib:all_chunks(Filename), - Abst = proplists:get_value("Abst", element(3, Chunks)), - binary_to_term(Abst). - -"CatT" - Catch Table -```````````````````` - -Contains catch labels nicely lined up and marking try/catch blocks. -This section description is INCOMPLETE and UNTESTED. - -* Read U32/big count -* Read array of ``count`` U32/big offsets or labels (not sure). - -"FunT" - Function/Lambda Table -`````````````````````````````` - -Contains pointers to functions in the module. - -* Read U32/big count - -Until the ``count`` do: - -* Read U32/big fun_atom_index (name by index from atom table), - U32/big arity, - U32/big offset (code position), - U32/big index, - U32/big nfree (frozen values for closures), - U32/big ouniq. Sanity check: fun_Atom_index must be in atom table range. - -"ExpT" - Exports Table -`````````````````````` - -Encodes exported functions and arity in the ``-export([]).`` attribute. - -* Read U32/big count - -Until the ``count`` do: - -* Read U32/big export name atom index. Sanity check: atom table range. -* Read U32/big arity, U32/big label (offset in BEAM code section, should - be translated into the loaded code offset). - -"LitT" - Literals Table -``````````````````````` - -Contains all the constants in file which are larger than 1 machine Word. -It is compressed using zip Deflate. - -* Read U32/big uncompressed size (prepare output buffer of this size). Run - zip inflate (uncompress) on the data. - -Inside the uncompressed data: - -* Read U32/big value count - -Until the ``value count`` do: - -* Skip U32/big -* Read byte ext term format marker (must be 131) -* Read tag byte, ... (follow the documentation) - -Values are encoded using the external term format. -A better reference is in the -`standard documentation `_ - -"ImpT" - Imports Table -`````````````````````` - -Encodes functions from other modules invoked by the current module. - -* Read U32/big count - -Until the ``count`` do: - -* Read U32/big module atom index, U32/big function atom index, U32/big arity - -"LocT" - Local Functions -```````````````````````` - -Essentially same as the export table format ``ExpT`` for local functions. - -* Read U32/big count - -Until the ``count`` do: - -* Read U32/big func atom index, U32/big arity, U32/big location (label) - -"Line" - Line Numbers Table -``````````````````````````` - -Encodes line numbers mapping to give better error reporting and code navigation -for the program user. - -* Read U32/big version (must match emulator's own version 0). -* Skip U32/big flags -* Read U32/big line_instr_count, U32/big num_line_refs, U32/big num_filenames -* Store invalid location const as Word[] linerefs first element which points - at file #0, line 0. -* Set fname_index = 0, this is index in file name table, empty now - -Until the ``num_line_refs`` do: - -* Parse term at read position (see :ref:`BEAM Term format `) -* If the term is a small integer, push a pair of (fname_index, value) to - the linerefs array. -* If the term is an atom, use its numeric value as new fname_index. Sanity - check: value must be under ``num_filenames``. - -Until the ``num_filenames`` do (fill the file names table): - -* Read U16/big name size -* Read string of bytes -* Convert string to an atom and push into file names table - -"StrT" - Strings Table -`````````````````````` - -This is a huge binary with all concatenated strings from the Erlang parsed AST -(syntax tree). Everything ``{string, X}`` goes here. There are no size markers -or separators between strings, so opcodes that need these values (e.g. bs_put_string) -must provide an index and a string length to extract what they need out of this -chunk. - -Consider ``compiler`` application in standard library, files: -``beam_asm``, ``beam_dict`` (record ``#asm{}`` field ``strings``), and -``beam_disasm``. - -"Attr" - Attributes -``````````````````` - -Contains two parts: a proplist of module attributes, encoded as External Term -Format, and a compiler info (options and version) encoded similarly. - - -.. _beam-term-format: - -BEAM Compact Term Encoding --------------------------- - -BEAM file uses a special encoding to store simple terms in BEAM file in -a space-efficient way. -It is different from memory term layout, used by BEAM VM. - -The idea is to stick as many type and value data into the 1st byte as possible:: - - 7 6 5 4 3 | 2 1 0 - ----------+------ - | 0 0 0 — Literal - | 0 0 1 — Integer - | 0 1 0 — Atom - | 0 1 1 — X Register - | 1 0 0 — Y Register - | 1 0 1 — Label - | 1 1 0 — Character - 0 0 0 1 0 | 1 1 1 — Extended — Float - 0 0 1 0 0 | 1 1 1 — Extended — List - 0 0 1 1 0 | 1 1 1 — Extended — Floating point register - 0 1 0 0 0 | 1 1 1 — Extended — Allocation list - 0 1 0 1 0 | 1 1 1 — Extended — Literal - -.. note:: - - In OTP 20 the Floats are encoded as literals, and every other extended code - is shifted, i.e. List becomes 1 (0b10111), Float register becomes 2 (0b100111), - alloc list becomes 3 (0b110111) and literal becomes 4 (0b1000111). - -It uses first 3 bits of a first byte as a tag to specify the type of the -following value. -If the bits were all 1 (special value 7), then few more bits are used. - -For values under 16 the value is placed entirely into bits 4-5-6-7 having bit -3 set to 0:: - - 7 6 5 4 | 3 | 2 1 0 - --------+---+------ - Value>> | 0 | Tag>> - -For values under 16#800 (2048) bit 3 is set to 1, marks that 1 continuation -byte will be used and 3 most significant bits of the value will extend into -this byte's bits 5-6-7:: - - 7 6 5 | 4 3 | 2 1 0 - ------+-----+------ - Value | 0 1 | Tag>> - -Larger and negative values are first converted to bytes. -Then if the value takes 2..8 bytes, bits 3-4 will be set to 1, and bits -5-6-7 will contain the ``(Bytes-2)`` size for the value, which follows:: - - 7 6 5 | 4 3 | 2 1 0 - --------+-----+------ - Bytes-2 | 1 1 | Tag>> - -If the following value is greater than 8 bytes, then all bits 3-4-5-6-7 -will be set to 1, followed by a nested encoded unsigned ``?tag_u`` value -of ``(Bytes-9):8``, and then the data:: - - 7 6 5 4 3 | 2 1 0 - ----------+------ Followed by nested encoded int (Size-9) - 1 1 1 1 1 | Tag>> - -.. seealso :: - Refer to ``beam_asm:encode/2`` in the ``compiler`` application for - details about how this is encoded. Tag values are presented in this - section, but also can be found in ``compiler/src/beam_opcodes.hrl``. - -Base and Extended Tag -````````````````````` - -Let's parse the value of ``tag``: - -* Read a byte and extract its least 3 bits. This is the base tag. - It can be Literal=0, Integer=1, Atom=2, XRegister=3, YRegister=4, Label=5, - Character=6, Extended=7. -* If the base tag was Extended=7, then bits 4-5-6-7 PLUS 7 will become - the extended tag. It can have values - Float=8, List=9, FloatReg=10, AllocList=11, Literal=12. - -A badly written and incomplete -`Github example of reading signed word `_ -routine used to read signed words later: - -.. _beam-parse-smallint: - -A badly written and incomplete -`Github example of parsing a small integer `_: -(used to read SmallInt values later). - -Reading the Value -````````````````` - -This is the logic, as was decoded from source code of BEAM VM and Ling VM. -It looks at the bits in slightly different order. - -* Look into the first byte read, bit 3: - - * Bit 3 is 1, so look into bit 4: - - * Bit is 1: Use remaining 3 bits of the byte as byte length - (if under 7 - read ``N+2`` bytes into signed words, - if the value is 7 - then length is larger than that and we - have to read length first -- it follows as ``?tag_u=0`` - (Literal) nested unsigned value) - * Bit 4 is 0: use remaining 3 bits + 8 more bits of the following byte - - * Bit #3 = 0: Use remaining 4 bits - -Now how to parse an encoded term: - -* Read a SmallInt, case ``tag`` of: - - * Tag=Integer: use the value (signed?) - * Tag=Literal: use smallint value as index in ``LitT`` table. - * Tag=Atom: use smallint value MINUS 1 as index in the atom table. - 0 smallint means ``NIL []``. - * Tag=Label: use as label index, or 0 means invalid value. - * Tag=XRegister, Tag=YRegister: use as register index. - * Tag=Character (an Unicode symbol): use val as unsigned. - * Tag=Extended List: contains pairs of terms. - Read smallint ``Size``. Create tuple of ``Size``, which will contain - ``Size/2`` values. - For ``Size/2`` do: - read and parse a term (``case of`` value), - read a small int (label index), place them into the tuple. - -.. _beam-code-format: - -BEAM Code Section Format ------------------------- - -Code section in BEAM file contains list of instructions and arguments. -To read an encoded term see :ref:`BEAM Term format `. - -* Read a byte, this is opcode (R19 has 158 base opcodes). - Opcode is converted into a label address (for threaded interpreter) or - a pointer to handler function. -* Query opcode table and get arity for this opcode. -* Until ``arity``: parse term and put it into the output one term or word at - a time. VM loop will read the opcode later and expect that ``arity`` - args will follow it. -* If any of the parsed terms was a label value, remember its output position - to later revisit it and overwrite with actual label address in memory - (it is not known until code parsing is done). diff --git a/docs/build/html/_sources/indepth-beam-instructions.rst.txt b/docs/build/html/_sources/indepth-beam-instructions.rst.txt deleted file mode 100644 index 2ace6bf..0000000 --- a/docs/build/html/_sources/indepth-beam-instructions.rst.txt +++ /dev/null @@ -1,482 +0,0 @@ -BEAM Instruction Codes -====================== - -BEAM file stores code in ``Code`` section, using 1 byte for opcode, and encoding -arguments one after one using :ref:`compact term encoding `. -Opcode table defines arity, or how many arguments each opcode can take. - -The table is not complete, for details on remaining opcodes please refer to -`LING VM opcode table `_ or to the source -``beam_emu.c``. Also see the opcode rules table ``ops.tab``, which defines -special opcodes and rules to to create superinstructions. -Superinstructions bundle several often used instructions into one and try to -optimize for specific argument types. - -As of R19 there are 158 base opcodes and several hundreds of superinstructions. - -Opcode Table ------------- - -Search for "#N" to find opcode N. - -**Slots** are special values marking stack cell or a register. They can be -used to point at the data source or move destination. There are several -values of secondary tag which denote them. - -.. |op-no-update-cp| replace:: Does not update the CP register with a return - address, making return bypass current code location. - -.. |op-save-cp| replace:: Return address is saved in CP. - -.. |op-mfarity-def| replace:: mfarity (a tuple ``{Mod, Fun, Arity}``) - which can point to an exported function or a BIF - -.. |op-mfarity-def-short| replace:: mfarity (a tuple ``{Mod, Fun, Arity}``) - -#2 func_info -```````````` - -``Func_info`` is located at the beginning of every function, but execution -always begins at the next label. -If all function clauses have failed guard checks, VM will jump to this -instruction. -It raises ``function_clause`` error with appropriate line number. - -#4 call -``````` - -Spec: ``call Arity Label`` - -Saves current IP to CP (return address) and jumps to the ``Label``, -which usually is a function entry point. - -#5 call_last -```````````` - -Spec: ``call_last Arity Label Deallocate`` - -Deallocates ``Deallocate`` words on stack and does a tail recursive call (jump) -to the function at ``Label``. -|op-no-update-cp| - -#6 call_only -```````````` - -Spec: ``call_only Arity Label`` - -Performs tail recursive call of a function at ``Label``. -|op-no-update-cp| - -#7 call_ext -``````````` - -Spec: ``call_ext Arity Destination::mfarity()`` - -Performs call to an external ``Destination`` |op-mfarity-def|. -|op-save-cp| - -#8 call_ext_last -```````````````` - -Spec: ``call_ext_last Arity Destination::mfarity() Deallocate`` - -Deallocates ``Deallocate`` words from stack and performs a tail recursive -call to an external ``Destination`` |op-mfarity-def|. -|op-no-update-cp| - -#9 bif0 -``````` - -Spec: ``bif0 ImportIndex Dst::mfarity()`` (note no fail label) - -Looks up BIF with zero arguments by ``Dst`` |op-mfarity-def-short| and calls it. -Cannot silently fail by jumping to a label and will always throw an exception. - -#10 bif1 #11 bif2 #152 bif3 -``````````````````````````` - -Spec: ``bif1 Fail::label() ImportIndex Arg1 Dst::mfarity()`` - -Spec: ``bif2 Fail::label() ImportIndex Arg1 Arg2 Dst::mfarity()`` - -Spec: ``bif3 Fail::label() ImportIndex Arg1 Arg2 Arg3 Dst::mfarity()`` - -Looks up BIF with 1, 2 or 3 arguments by ``Dst`` |op-mfarity-def-short| -and calls it. -If ``Fail`` label is valid (not 0?), VM will jump to the label on error, -otherwise will throw an exception. - -#12 allocate #14 allocate_zero -`````````````````````````````` - -Spec: ``allocate StackNeed Live`` - -Spec: ``allocate_zero StackNeed Live`` - -Allocates ``StackNeed`` words on the stack (a stack frame). -``Live`` defines how many X registers are currently in use (for GC call). -Current CP value is saved on top of the stack. -``Allocate_zero`` writes NIL to all new stack cells, while ``allocate`` may -or may not do this. - -#13 allocate_heap #15 allocate_heap_zero -```````````````````````````````````````` - -Spec: ``allocate_heap StackNeed HeapNeed Live`` - -Spec: ``allocate_heap_zero StackNeed HeapNeed Live`` - -Allocates ``StackNeed`` words on the stack and ensures that there are -``HeapNeed`` available words on the heap. -``Live`` defines how many X registers are currently in use (for GC call). -Current CP value is saved on top of the stack. -``Allocate_heap_zero`` writes NIL to all new stack (possibly heap too?) cells, -while ``allocate_heap`` may or may not do this. - -#16 test_heap -````````````` - -Spec: ``test_heap Need Live`` - -Ensures there are at least ``Need`` words on the heap. If needed, GC is -performed using ``Live`` values from registers array. - -#17 init -```````` - -Spec: ``init Y`` - -Clears ``Y+1``-th stack word by writing ``NIL``. Offset by one is there because -CP is also stored on stack but it is not considered an ``Y`` cell. - -#18 deallocate -`````````````` - -Spec: ``deallocate N`` - -Restores CP from stack and deallocates ``N+1`` words from stack (one extra for -the CP). - -#19 return -`````````` - -Jumps to current value of CP register. Sets CP to 0. - -#20 send -```````` - -Sends value ``X[1]`` to the process specified by ``X[0]``. ``X[1]`` becomes -the result of the operation (is moved to ``X[0]``). - -#21 remove_message -`````````````````` - -Unlinks current message from the message queue. Message is moved to ``X[0]``. -*Current* means that there is a movable pointer to a message in the linked list. - -#23 loop_rec -```````````` - -Spec: ``loop_rec Label Source`` - -Picks up next message in the queue and places it into ``X[0]``. If there is no -message, jumps to ``Label`` which points to a ``wait`` or ``wait_timeout`` -instruction. - -#24 loop_rec_end -```````````````` - -Spec: ``loop_rec_end Label`` - -Advances message pointer to the next message, then jump to ``Label`` which -points to a ``loop_rec`` instruction. - -#25 wait -```````` - -Spec: ``wait Label`` - -Jumps to the ``Label`` and immediately suspends the process (wait for event). - -Comparisons -``````````` - -Spec: `` Label Arg1 Arg2`` - -Performs a comparison and jumps to ``Label`` if false. - -* #39 ``is_lt`` - is less -* #40 ``is_ge`` - is greater or equal -* #41 ``is_eq`` - equal ``==`` -* #42 ``is_ne`` - not equal ``/=`` -* #43 ``is_eq_exact`` - exactly equal ``=:=`` -* #44 ``is_ne_exact`` - exactly not equal ``=/=`` -* #58 ``test_arity`` - checks if ``Arg1`` is a tuple of size ``Arg2`` -* #115 ``is_function2`` - checks if ``Arg1`` is a fun of arity ``Arg2`` - -Guards as Opcodes -````````````````` - -Spec: `` Label Arg`` - -Some guards are implemented as opcodes. -Performs a check and jumps to ``Label`` if false. - -* #45 ``is_integer`` - is small or bignum -* #46 ``is_float`` -* #47 ``is_number`` - is small or bignum or float -* #48 ``is_atom`` -* #49 ``is_pid`` -* #50 ``is_reference`` -* #51 ``is_port`` -* #52 ``is_nil`` -* #53 ``is_binary`` -* #54 ``is_constant`` - possibly checks if term belongs to literal area of a module? -* #55 ``is_list`` - term is a NIL or points to a cons cell -* #56 ``is_nonempty_list`` - term points to a cons cell -* #57 ``is_tuple`` -* #77 ``is_function`` -* #114 ``is_boolean`` - -#59 select_val -`````````````` - -Spec: ``select_val Arg FailLabel Destinations`` - -Scans ``Destinations`` even elements (0, 2, 4...) and compares with ``Arg``. -If match is found, jumps to the label in the next odd element (1, 3, 5...) -otherwise jumpts to ``FailLabel``. -By "match" naive compare is meant. - -#60 select_tuple_arity -`````````````````````` - -Spec: ``select_tuple_arity Tuple FailLabel Destinations`` - -Check the arity of the ``Tuple`` and jump to the corresponding ``Destination`` -label, if no arity matches, jump to ``FailLabel``. - -#61 jump -```````` - -Spec: ``jump Address`` - -#62 catch -````````` - -Spec: ``catch Y Label`` - -Saves a resumption address &CatchEnd in the local frame at position -``Y``. Increments the process catch counter. The instruction is followed by a -``catch_end`` instruction. By followed we mean that the ``catch_end`` -instruction is put after corresponding Erlang expression that is protected -from errors by the catch. - -#63 catch_end -````````````` - -Spec: ``catch_end Y`` - -Clears a resumption address stored in the local frame at position ``Y``. -Decrements the process catch counter. -This instruction is preceded by a matching ``catch`` instruction. - -#64 move -```````` - -Spec: ``move Src Dst`` - -Moves value from the ``Src`` to the ``Dst``. - -``Src`` can be a value or a slot. -``Dst`` must be a slot. - -#65 get_list -```````````` - -Spec: ``get_list Source Head Tail`` - -Gets the head and tail of a list (splits its cons cell) from ``Source`` -and puts values into the registers ``Head`` and ``Tail``. - -#66 get_tuple_element -````````````````````` - -Spec ``get_tuple_element Source Element Destination::slot()`` - -Gets ``Element``-th item from the tuple denoted by ``Source`` and puts -it into the ``Destination`` slot. - -#69 put_list -```````````` - -Spec: ``put_list H T Dst::slot()`` - -Creates a cons cell with ``[H|T]`` and places the value into ``Dst``. - -#70 put_tuple #71 put -````````````````````` - -Spec ``put_tuple Arity Dst`` - -This opcode is followed by ``Arity`` repeated ``put Value`` opcodes. -Creates an empty tuple of ``Arity`` and places pointer to it into ``Dst``. -Then moves instruction pointer forward, while next opcode is ``put``, -reads argument for every ``put`` and places it into the next tuple element. -Stops after ``Arity`` steps. - -#72 badmatch -```````````` -Produces an error. - -#73 if_clause -````````````` - -Produces an error. - -#74 case_clause -``````````````` - -Produces an error. - -#75 call_fun -```````````` - -Spec: ``call_fun Arity`` - -Calls a fun or export. -Arguments are in ``X[0..Arity-1]``. -Function object is in ``X[Arity]``. -|op-save-cp| - -Raises ``badarity`` if arity does not match the function object. -Raises ``badfun`` if object is not callable (not a fun or export). - -#76 make_fun -```````````` - -Seems to be deprecated, so compiler always generates ``make_fun2``. - -#78 call_ext_only -````````````````` - -Spec: ``call_ext_only Arity Destination::mfarity()`` - -Performs a tail recursive call to a ``Destination`` |op-mfarity-def|. -|op-no-update-cp| - -#89 bs_put_integer/5 -```````````````````` - -Spec: ``bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s`` - -An integer from ``src`` and having bitsize ``sz`` is appended to the current -writable binary (stored in the internal state) at the current bit offset -(stored in the state too). - -#103 make_fun2 -`````````````` - -Spec: ``make_fun2 Lambda`` - -Produces a callable fun object. ``Lambda`` should be resolved at load time -to a function entry. Creates a callable box object on the heap which points -to this fun object and also has space to store frozen values (Free variables). - -#104 try/2 -`````````` - -Spec ``try Yregister Label`` - -Begins a guarded code section by writing a special crafted catch value into the -given Y register. The catch value points to the label in case of exception, where -a ``try_case`` instruction is located. - -#105 try_end/1 -`````````````` - -Spec: ``try_end Yregister`` - -Ends the guarded section by clearing the catch value on stack with a NIL. - -#106 try_case/1 -``````````````` - -Begins investigation of an exception, also clears the catch value on stack. From -here if you need the exception to propagate, you have to raise it again. - -#107 try_case_end/1 -``````````````````` - -#108 raise/2 -```````````` - -Spec: ``raise Stacktrace ExcValue`` - -A legacy instruction which takes error type from the provided stacktrace -object and creates an exception with the exception value (second argument). - -#109 bs_init2/6 -``````````````` - -Creates a new writable binary of requested size with some extra words, runs GC -if needed, then the binary is stored in the internal state. Following ``bs_put*`` -instructions will add to it. The write bit offset in the internal state is -also reset to 0. - -#112 apply #113 apply_last -`````````````````````````` - -Spec ``apply Arity`` - -Spec ``apply_last Arity Dealloc`` - -Calls function at ``X[Arity+1]`` in module ``X[Arity]`` -with arguments ``X[0..Arity-1]``. Module is an atom or a tuple. Function is an -atom. - -``Apply`` saves current instruction pointer into CP and performs a -call to the destination. - -``Apply_last`` cuts the stack by ``Dealloc`` words preserving the CP on top -of the stack, and then jumps to the destination. - -#136 trim -````````` - -Spec: ``trim N _Remaining`` - -Drops ``N`` words on stack after saved CP, moving it ``N`` words up. - -Binary Matching and Operations ------------------------------- - -#119 bs_get_binary2/7 -````````````````````` - -Spec: ``bs_get_binary2 Fail MatchState Live Size Unit Dst`` - -For current binary match position (started by ``bs_start_match*``) extract -a sub-binary (a slice) and return it. ``Live`` is used for an occasional garbage -collection act if the memory is tight. ``Size:Unit`` determines how many bits -go into the result. - - -#166 bs_start_match3 -```````````````````` - -Spec ``bs_start_match3 Fail Context Live Dst`` - -This opcode was introduced in OTP 22 and replaces ``bs_start_match2``. - -Depending on whether the value in the ``Context`` is binary, or an existing match -state, creates a new match state if needed. The position from the match state is used -for binary matching step by step by the following ``bs_*`` opcodes. - -#121 bs_test_tail2 -`````````````````` - -Spec: ``bs_test_tail2 Fail, MatchState, N`` - -Ensures that the match state has ``N`` bits remaining for processing. If this is -not true, the VM will jump to the ``Fail`` label. diff --git a/docs/build/html/_sources/indepth-data-sizes.rst.txt b/docs/build/html/_sources/indepth-data-sizes.rst.txt deleted file mode 100644 index 0102f63..0000000 --- a/docs/build/html/_sources/indepth-data-sizes.rst.txt +++ /dev/null @@ -1,85 +0,0 @@ -BEAM Internal data sizes -======================== - -.. seealso:: - Data sizes in the - `Erlang Efficiency Guide ` - -Each boxed term has size described below plus one word for term value -itself which you store somewhere else (be it on heap then you should count size -for this term too, or in register/on stack - then it will not consume heap -memory). - -For specific bit positions and bit sizes please always refer to original beam -sources, file: ``erl_term.h`` - -Immediate ---------- - -All immediate values have size of one :ref:`Word `. - -They are: local **pid**, local **port**, **small integer**, **atom**, **NIL** -(an empty list ``[]``) and catch (internal value). :ref:`CP ` can -also be considered an immediate although it is a special value which only -appears on stack and never in registers or heap. - -List ----- - -List value is a pointer to cons cell. Cons cell has size of two -:ref:`Words ` (one for head, and another for tail). Cons cell can -link to next cons cell and so on, until tail becomes a non-list term (for improper -lists) or ``NIL`` (for proper lists). - -Size of a list is 1 :ref:`Word ` (for a pointer) and also on the heap -``2*num_cells`` :ref:`Words `. - -Boxed ------ - -Boxed value is a pointer to the heap or some other area and always takes 1 -:ref:`Words `. -A Box always points to a memory block which starts with a Header (below) -except during GC. - -Header ------- - -A Box always points to a Header except during GC. -Header word typically contains an `arity`, which is stored in most-significant -bits of their first word, following the header tag (which is 4+2 bits). - -Header is a special tag which hides all sorts of internal opaque data. Header -can be found on heap only and remaining most-significant bits usually represent -its size (arity). For maps, arity is calculated using different formula (see -``MAP_HEADER_ARITY`` macro). - -By header tag headers can mark the beginning of: -arityval (a **tuple**), -**fun** (closure with frozen variable values), -positive and negative **bigint** (tagged separately to avoid storing sign bit), -**float**, **export**, **refvalue**, **refcounted binary**, **heap binary**, -**subbinary**, external **pid**, **port**, **ref**, -**matchstate** (internal object) and **map**. - -Tuple -````` - -Tuple size on heap is its arity plus 1 :ref:`Word ` header. -Also 1 :ref:`Word ` to store each pointer to the tuple box. - -Float -````` - -Float size is always 64 bit (1 or 2 words) + 1 :ref:`Word ` header. -Also 1 :ref:`Word ` to store each pointer to the float box. - -Big Integer -``````````` - -Bigint size is ``ceil(log2^64(Number))`` :ref:`Words ` -+ 1 :ref:`Word ` header. -Thus a <=64bit integer will take 1 word,65-127bit will take 2 words and so on. -On 32-bit architectures, of course, the Word size is 32 bit and everything is -32-bit based. -Also +1 :ref:`Word ` to store each pointer to the bigint box. diff --git a/docs/build/html/_sources/indepth-heap-layout.rst.txt b/docs/build/html/_sources/indepth-heap-layout.rst.txt deleted file mode 100644 index 856f946..0000000 --- a/docs/build/html/_sources/indepth-heap-layout.rst.txt +++ /dev/null @@ -1,44 +0,0 @@ -Process Heap Layout -=================== - -An Erlang process has a young heap (where all new data is placed), old heap -(possibly this one does not exist, contains data which survived previous garbage -collection) and a stack, which is located inside young heap. - -Also a process has access to read-only literal area, which belongs to one or more -of Erlang modules, it contains constant literals which are found in module code. -At some rare occasions (code upgrade or purge) literal area can be copied to -old heap by means of garbage-collection (see ``erts_garbage_collect_literals`` -in ``erl_gc.c``). - -A process has chain of Off-heap objects (so-called MSO -- mark and sweep object -list). The head of the chain is a field in ``Process`` struct, and the chain -continues through the heap visiting :ref:`Header ` objects such as -refc binaries and fun closures. During garbage collection this chain is followed -and actions can be taken (similar to C++ destructors) when an MSO object is going -to die -- for example refc binaries have their refcount reduced and possibly -are freed. MSO objects are strictly sorted from new to old, by the order of their -creation on heap. - -How Heap Grows --------------- - -Additionally heap segments can exist (for situations, when heap is not enough, -but data must be allocated). Heap segments are consolidated before garbage -collection and merged onto heap. - -Heap top (``heap_top``) marks current allocation position in heap. When more data -is needed, ``heap_top`` is advanced forward and data goes there. - -Heap always grows forward from ``heap_start`` (see ``erl_process.h``, ``Process`` -struct, fields ``heap``, ``old_heap``). Stack always grows backwards from -``heap_end`` to ``heap_top``, as soon as stack meets heap top, the young heap -is considered full and garbage collection is triggered. - -Old heap does not contain a stack. Old heap can only grow during garbage -collection and its future size is precalculated. - -To minimize memory fragmentation, heap sizes like a puzzle pieces are allocated -following Fibonacci sequence (starting from 12 and 38 :ref:`Words `) -for 23 total steps, after which (at about 1.3 million :ref:`Words `) -sequence continues by adding 20% to the previous value. \ No newline at end of file diff --git a/docs/build/html/_sources/indepth-io.rst.txt b/docs/build/html/_sources/indepth-io.rst.txt deleted file mode 100644 index 3011b92..0000000 --- a/docs/build/html/_sources/indepth-io.rst.txt +++ /dev/null @@ -1,39 +0,0 @@ -IO in Erlang -============ - -How a Driver Looks Like ------------------------ - -A port driver is a C module with several functions defined (see ``ErlDrvEntry`` -in ``emulator/beam/erl_driver.h``: - -* Start/stop, finish, process exit/emergency close functions -* IO events (async/input/output) -* Timeout handler -* Call function, which passes commands to the port -* Control function, which changes options in the port -* Flush function, which ensures that all data is written - -Making a Port Driver --------------------- - -Define an ``erl_drv_entry`` variable (a struct) and fill it with pointers to -callback functions. -You will need to cover things such as starting your driver, -stopping it, opening a port, sending commands and receiving data, and few other. - -.. seealso:: - BEAM Wisdoms: :doc:`interfacing` - - `Driver HowTo `_ - - `Port Driver and erl_drv_entry documentation `_ - -Load your port driver and register it in the system under a name -(``add_driver_entry``). - -.. seealso:: - `Erl Dynamic Driver Loader Linker `_ - -.. todo:: - this goes to indepth section diff --git a/docs/build/html/_sources/indepth-memory-layout.rst.txt b/docs/build/html/_sources/indepth-memory-layout.rst.txt deleted file mode 100644 index fb700e5..0000000 --- a/docs/build/html/_sources/indepth-memory-layout.rst.txt +++ /dev/null @@ -1,215 +0,0 @@ -Data Types Memory Layout -======================== - -This describes data format on heap, as seen in C code or from debugger. -You will never be able to see this format from Erlang code. - -Immediate values ----------------- - -.. image:: _static/img/memory-layout-immed.png - :width: 300 - :align: center - -Immediate types always occupy 1 :ref:`Word `. To know if you found -an immediate, its least-significant 2 bits will have value -``TAG_PRIMARY_IMMED1=3``. - -To know which exactly immediate you've got, see the two following bits -(bit 2 and 3): -``_TAG_IMMED1_PID=0``, -``_TAG_IMMED1_PORT=1``, -``_TAG_IMMED1_SMALL=3``. -This leaves remaining :ref:`Word-size ` minus 4 bits for the -actual value. - -If the bits 2 and 3 contained ``_TAG_IMMED1_IMMED2=2`` then two more bits -(bit 4 and 5) are taken and interpreted. -They can be -``_TAG_IMMED2_ATOM=0``, -``_TAG_IMMED2_CATCH=1`` -``_TAG_IMMED2_NIL=3``, -which leaves remaining :ref:`Word-size ` minus 6 bits for the -actual value. - -This also explains why max small integer range is ``32-4=28``: -``2^27-1`` + one bit sign, because small is an immediate-1 value. -And why max number of atoms can be ``32-6=26`` (2^26=32 million), because -atom is an immediate-2 value. -For compatibility reasons this limit also applies to 64-bit systems. - -Lists (Cons) ------------- - -.. image:: _static/img/memory-layout-list.png - :width: 400 - :align: center - -A list term is boxed value (i.e. contains a pointer to heap). 2 least-significant -bits of list value have ``TAG_PRIMARY_LIST=1``, remaining bits are the pointer. - -A value on heap -contains 2 :ref:`Words ` -- namely CAR (or list head) and -CDR (list tail) (see ``CAR`` and ``CDR`` macros in ``emulator/beam/erl_term.h``). -This pair of words is called "Cons Cell" (terminology from -Lisp and functional programming). Cons cell has no header word stored in memory. - -Each cons cell contains pointer to next cell in CDR (tail). -As this is also visible from Erlang, last cons cell of a list contains ``NIL`` -(a special value for empty list ``[]``) or a non-list :ref:`Term ` -value (this makes *improper* list). - -This structure may look inefficient, but on the other hand it allows -connecting any tail of any list to multiple cons cells to reuse existing data. - -Boxed ------ - -.. image:: _static/img/memory-layout-box.png - :width: 350 - :align: center - -Boxed value is a pointer with 2 least-significant bits tagged with -``TAG_PRIMARY_BOXED=2``. Remaining bits are the pointer. - -A boxed pointer must always point to a :ref:`Header ` -(see explanation of headers below). Boxed values can be found everywhere: -in registers, on stack, on heaps. - -Box always points at a Header (below). -During the garbage collection a Box can point to another Box or to -``THE_NON_VALUE`` to mark a moved object, but never after. - -Headers -------- - -Header tag is placed on any boxed value on heap, also on temporary blocks used -by internal emulator logic, they will be automatically garbage collected later. - -Header values can never be found in register or on stack. This is heap-only data structure. - -Tuple (ARITYVAL=0) -`````````````````` - -.. image:: _static/img/memory-layout-tuple.png - :width: 350 - :align: center - -A tuple has header word tagged with ``TAG_PRIMARY_HEADER`` with ``ARITYVAL_SUBTAG``. -Remaining bits in header word represent tuple arity -(see ``arityval`` and ``make_arityval`` macros). - -Following are tuple elements. This explains, why tuple is very easy to access at -arbitrary index, and very hard to grow. Modification of tuple elements in place -is used as optimization by Erlang compiler if it can prove, that intermediate -tuple value will be dropped. - -Bignum (NEG=2/POS_BIG=3) -```````````````````````` - -.. image:: _static/img/memory-layout-bignum.png - :width: 350 - :align: center - -Bignums have header word tagged with ``TAG_PRIMARY_HEADER`` followed by either -``POS_BIG_SUBTAG`` or ``NEG_BIG_SUBTAG``. Remaining bits in header word are arity, -i.e. how many extra :ref:`Words ` are used by bignum bits. - -Following are bits of the bignum, a :ref:`Word ` at a time. -Most significant word goes first. - -Reference (REF=4) -````````````````` - -.. image:: _static/img/memory-layout-ref.png - :width: 350 - :align: center - -See struct ``RefThing`` in ``emulator/beam/erl_term.h``. -Contains header word tagged with ``TAG_PRIMARY_HEADER`` with ``REF_SUBTAG`` which -also matches the first field of ``RefThing``. - -Following are other ``RefThing`` fields (3 32-bit words or 2 64-bit words) which -have the ref value stored in them. Internal (local) ref layout is explained in -``emulator/beam/erl_term.h`` search for text "Ref layout (internal references)" and -"Ref layout on a 64-bit" (2 comments). - -Fun/Closure (FUN=5) -``````````````````` - -See struct ``ErlFunThing`` in ``erl_fun.h``. -Contains header word tagged with ``TAG_PRIMARY_HEADER`` with ``FUN_SUBTAG`` which -also matches the first field of ``ErlFunThing``. - -This is a closure (a function pointer with frozen variable values). It contains -pointer to function entry, arity, amount -of frozen variables, pid of creator process and array of frozen variables. - -Float (FLOAT=6) -``````````````` - -Contains header word tagged with ``TAG_PRIMARY_HEADER`` with ``FLOAT_SUBTAG``. -Followed by 64 bit of C ``double`` IEEE-754 format. - -Export (EXPORT=7) -````````````````` - -.. image:: _static/img/memory-layout-export.png - :width: 250 - :align: right - -Refers to a ``{Mod, Fun, Arity}``. Contains a pointer to the *export table*. -Always has arity 1 (because only one pointer). - -A record in export table contains: - -* Pointers to all (old and current) versions of the code for the function -* 2 words with ``func_info`` opcode for the function. - Note, that this is executable BEAM code. -* 3 words: Module (atom), Function (atom), Arity (as untagged integer) -* 1 word which is 0 or may contain a apply, call or breakpoint opcode. - Note, that this is executable BEAM code. -* 1 word argument for the previous opcode. May be a pointer to BEAM code, - a pointer to a C BIF function or 0. - -.. seealso:: ``Export`` struct in ``emulator/beam/export.h`` - -Reference-counted Binary (REFC_BINARY=8) -```````````````````````````````````````` - -A pointer to binary on the binary heap. When this is destroyed, the reference -count is reduced (can only happen during GC). -Reference to refc binary is called procbin. -A refc binary whose refc reaches 0 is deleted. - -Heap Binary (HEAP_BINARY=9) -``````````````````````````` - -A smaller binary (under 64 bytes) which is directly placed on the process heap. - -Sub-binary (SUB_BINARY=10) -`````````````````````````` - -A temporary pointer to a part of another binary (either heap or refcounted, -but never into another sub-binary). -Can be produced by ``split_binary`` function. - -Match context -````````````` - -Similar to sub-binary but is optimized for binary matching. - -Ext Pid 12 -`````````` - -Pid containing node name. Refers to a process on another node. - -Ext Port 13 -``````````` - -Port containing node name. Refers to a port on another node. - -Ext Ref (EXTERNAL_REF=14) -````````````````````````` - -External ref format is explained in ``erl_term.h`` search for "External thing layout". diff --git a/docs/build/html/_sources/index.rst.txt b/docs/build/html/_sources/index.rst.txt deleted file mode 100644 index 5643391..0000000 --- a/docs/build/html/_sources/index.rst.txt +++ /dev/null @@ -1,64 +0,0 @@ -.. BEAM VM Wisdoms documentation master file - -Welcome, adventurer! -==================== - -This is the collection of easy to read (ELI5) articles as well as in-depth -knowledge such as VM internals, memory layout, opcodes etc. -The project is work in progress, so come back soon! -Github repository for pages https://github.com/kvakvs/beam-wisdoms - -Latest -`````` - -* 2023-06-18 Leave readthedocs and migrate to Github pages. -* 2019-03-03 Binary match opcodes added to the instruction list. -* 2018-12-30 Try/catch opcodes added to the instruction list. - -ELI5 Section (Explain Me Like I'm Five) ---------------------------------------- - -.. toctree:: - :maxdepth: 1 - - eli5-vm - eli5-atoms - eli5-processes - eli5-process-heap - eli5-io - eli5-tracing - eli5-bif-nif - eli5-types - eli5-etf - eli5-property-based - eli5-efficiency - eli5-efficiency-memory-perf - - -Deeper Knowledge Section ------------------------- - -.. toctree:: - :maxdepth: 2 - - definitions - indepth-memory-layout - indepth-data-sizes - indepth-heap-layout - interfacing - indepth-beam-file - indepth-beam-instructions - indepth-io - -.. todo:: - More details from ELI5 articles; - IO and ports; - Links and monitors; - ETS?; - BIFs, traps; - Process: Exceptions; - Ext term format - -Smaller things you would've never noticed otherwise. OTP C source-related. - -:doc:`otp-c-style-guide`, :doc:`otp-cpp-ramblings`, :doc:`otp-c-refactor-todo` diff --git a/docs/build/html/_sources/interfacing.rst.txt b/docs/build/html/_sources/interfacing.rst.txt deleted file mode 100644 index 0ffb6ae..0000000 --- a/docs/build/html/_sources/interfacing.rst.txt +++ /dev/null @@ -1,92 +0,0 @@ -Interfacing Erlang with the Outer World -======================================= - -Native Libraries ----------------- - -.. note:: - This page was created between 2016 and 2018, more changes might have - happened since. - -There are plenty of different approaches on integrating NIFs written in other -languages: - -C -```` - -* `edtk, a port driver toolkit `_ -* `dryverl `_ (license BSD) -* `C/C++ Generic Erlang Port Driver `_ - (license MIT) -* `Nifty, a NIF wrapper generator `_ - -C++ -```` - -* `EPI `_ (license LGPL) -* `eixx `_ (license Apache2) -* `C/C++ Generic Erlang Port Driver `_ - (license MIT) -* `C++11 NIFPP `_ (license Boost) - -Lua -```` - -* erlua -* `erlualib `_ (license MIT) - -Python -`````` - -* `Pyrlang `_ (Erlang node written in asyncio) (license Apache2) -* ErlPort (see below in "Ports") -* `erlang_py `_ (license MIT) -* py_interface - `Website `_, - `Github `_ - (license LGPL) -* PyErl `Github `_ (license MPL) - -Ruby -```` - -* ErlPort (see below in "Ports") -* `Erlang Term Format (Ruby) `_ (MIT) - -PHP -```` - -* `Erlang Term Format (PHP) `_ (MIT) - - -Rust -```` - -* `Rustler `_ (license Apache, MIT) -* `erlang-rust-nif `_ - -Nim -```` - -* `nimler `_ (MIT) - -Javascript -`````````` - -* `Erlang Term Format (Javascript) `_ (MIT) - -Perl -```` - -* `Erlang Term Format (Perl) `_ (MIT) - -Ports and Network ------------------ - -For the situations when you still need the speed and can tolerate some call -latency over, but don't want to risk crashing your node: choose interaction over -network or a port. - -* `Erlport `_ -* `CloudI, A private cloud engine `_ - (C/C++, Erlang/Elixir, Java, JavaScript/node.js, Perl, PHP, Python and Ruby) diff --git a/docs/build/html/_sources/otp-c-refactor-todo.rst.txt b/docs/build/html/_sources/otp-c-refactor-todo.rst.txt deleted file mode 100644 index ed76896..0000000 --- a/docs/build/html/_sources/otp-c-refactor-todo.rst.txt +++ /dev/null @@ -1,5 +0,0 @@ -Things to Refactor in OTP -========================= - -``Export`` structure leaks complexity which should be moved to ``export.h`` -or hidden. diff --git a/docs/build/html/_sources/otp-c-style-guide.rst.txt b/docs/build/html/_sources/otp-c-style-guide.rst.txt deleted file mode 100644 index 7c17090..0000000 --- a/docs/build/html/_sources/otp-c-style-guide.rst.txt +++ /dev/null @@ -1,108 +0,0 @@ -Erlang/OTP Source Style Guide -============================= - -General -------- - -Source language is C89. - -Source uses mix of tabs and spaces. Tab equals 8 spaces, indent is 4 spaces. -It seems that spaces are rather accepted way to indent contributions. - -Version Control System ----------------------- - -Erlang/OTP uses Git as its version control system. - -Commits should have max 60 characters in the first line. Long commit description -follows after one empty line. - -The source tree perfectly should be compilable at any time between commits (it does -not have to pass all tests between commits though), to simplify git bisect searches. - -Headers -------- - -The #define Guard -````````````````` - -All headers should have #define guards to prevent multiple inclusion. The format of -the symbol name is ``__MODULENAME_H__`` or ``__MODULENAME_H``. -Pragma once is not accepted as of Sept 2016. - -Naming Macros -````````````` - -All macro names are defined using uppercase letters, numbers and underscores. - -For new macros a general suggestion for type safety is: if it's possible to write -it as inline function, one should not create a macro and use inline -(``ERTS_INLINE`` or ``ERTS_FORCE_INLINE``) instead. - -Prefer to not convert existing macros to inline without a reason (they are well -tested as is now and their compiled representation may slightly change with -inline, that is not always desirable). -Also when going from a macro to a function, its name should be changed -accordingly (lowercase + prefix), this may have some undesired consequences -for dependent modules and external code using Erlang API. - -Naming Types -```````````` - -A new type should be named in CamelCase. A publicly visible type must have -longer prefix. For example garbage collection functions have prefix ``erts_*``, -``erts_gc_*``, and types have prefix ``ErtsGC*`` - -Do not rename existing types without a good reason, especially if it was a -part of the public API. - -Naming Functions -```````````````` - -Functions are named using lowercase letters, numbers and underscores. - -Function arguments are named using lowercase letters, numbers and underscores. - -A globally visible non-inline function should have an ``erts_`` prefix to its -name. - -All inline functions should use ``ERTS_INLINE`` or ``ERTS_FORCE_INLINE`` macro. - -A local function inside module should be declared ``static``. - -Naming Variables -```````````````` - -Local variables are named using lowercase letters, numbers and underscores. - -It is suggested to have local variables defined as close to their first use as -possible. -A new variable can be declared at the beginning of any scope -(inside an ``if``, ``for``, ``do`` etc), not just at the start of the function -body. - -Consider using ``const`` if variable is only set once at the moment of its -declaration. - -Consider using a strict sized type (``Uint64`` or ``Uint32`` for example) when -you definitely know limits of your data. Otherwise consider using sizable -(``Word``) and similar. - -Coding conventions ------------------- - -Argument Passing -```````````````` - -If a function takes a pointer to a memory block, consider using ``const`` -pointer type to pass it as read only (``const char *`` as a mutable pointer -to an immutable array of ``char``). - -If a function should return more than one value, pass pointer to the -container for the result or pass values using their address. -It is suggested to either mark such arguments in comment as ``in/out`` or have a -prefix ``_out``. - -To avoid mistakes, try not having similar types following each other in -argument list. -This way you'll get compiler warning if you miss one argument position. diff --git a/docs/build/html/_sources/otp-cpp-ramblings.rst.txt b/docs/build/html/_sources/otp-cpp-ramblings.rst.txt deleted file mode 100644 index a3d333d..0000000 --- a/docs/build/html/_sources/otp-cpp-ramblings.rst.txt +++ /dev/null @@ -1,162 +0,0 @@ -How OTP Source Would Benefit from C++ -===================================== - -Here are my personal thoughts + results of my experiments with transferring -OTP C source to C++ and listing benefits of doing so for real. - -Here is a brilliant case study on converting a C library to C++ with benefits -listed: -J. Daniel Garcia and B. Stroustrup: -`Improving performance and maintainability through refactoring in C++11 `_. -Isocpp.org. August 2015. They managed to reduce instruction count, improve -branch miss ratio, thus improving the performance. - -Another success story: Porting MAME (multiple arcade machine emulator) from C to modern C++ https://www.youtube.com/watch?v=wAUnUWYaA5s -The intro to what is MAME and why it is so huge goes till 26min then the conversion story begins. - -Portability Benefits --------------------- - -Currently compiling Erlang/OTP on Windows is pain. It is built using MSVC for -the C89 part, except that ``beam_emu.c`` is built using GCC. -This is happening because "jump to label address" extension is not supported on -MSVC which falls back to switch dispatch and creates much slower code. - -Microsoft stated, that they will not be investing any time into supporting -modern C standards with MSVC. -So there are only two ways out: use another compiler on Windows (gcc or Clang) -or switch to C++ and use MSVC natively. - -Code Benefits -------------- - -Compatible with C -````````````````` - -C runs perfectly fine when compiled as C++, the transition can happen gradually. -Does not have to use certain features like RTTI and exceptions, they can be -disabled at compiler-level. - -Compile-Time Everywhere -``````````````````````` - -Macros with code should be replaced with typed inlines or ``constexpr``. -This helps with type checking and debuggability. -Stepping into a function in a debugger works much better than into a macro. -Also type safety applies. [Better view in debugger] - -Macros with numbers should be replaced with ``const`` and ``constexpr``. -This way they will have a type, a namespace, and possibly may change into -an enum. -[Type checking = less bugs] - -Abusive prefixing on ``enum`` should be replaced with ``enum class`` -and namespaces. Moving enums with smaller scope into relevant structs and -classes (serves as a namespace). -[Less collisions and confusions in naming] - -Type Safety -``````````` - -C++ is more strict about types, pointer types and alignment. Example: Assigning -an ``Eterm*`` to a ``char*`` will change alignment requirement from 8 to 1, -possibly hiding a bug. [Prevents accidents] - -Size types can be tagged: word and byte counts can be made incompatible to -reduce confusion and bugs, with conversion functions. -[Less word-byte-confusion-related bugs] - -To develop the idea of tagging further, memory pointer types can be tagged -(making them incompatible with other pointer types to reduce confusion -when passing them as arguments). -[Less memory-type related bugs] - -Things like ``memcpy`` invite errors, you have to be mindful about types and -sizes. C++ allows to rewrite this in a safe way, they even have ``std::copy`` -that does the same in a safe way (often this compiles into a ``memcpy`` -but with correct sizes and bounds). -The C alternative having a function per type with separate names is highly -impractical. [Safer memory bounds] - -Things like ``erts_alloc`` invite errors because you have to remember data -sizes. C++ can make sizes deducted automatically and return a correct -pointer type. [Safer memory allocations] -[Safer deallocations if they check types too] - -Divide and Rule -``````````````` - -Abusive prefixing on types and function names should go into namespaces. -Structs and classes also serve as namespaces (unlike in C). - -Benefits are immense: names become shorter at the cost of specifying namespace -at the beginning of module or a scope (``using namespace X`` or -``namespace X = Y::Z``). -[Shorter names easier to read] - -Hiding a lot of small macros with short nondescript names and abstracting -away things. Example: ``erl_term.h`` and all the macros in it can be -generalized, grouped under the name of eterm and type checked. -In modern C++ all functions in the class header file are implicitly inline. -[Fast code at no cost] - -Generic Code -```````````` - -Code duplication can be reduced by moving code into templated functions. -Long functions can and should be broken into smaller, reducing the variable -scope and amount of code to read. -Example: Garbage collection sweeps are generic, before R20 they were -duplicated code. -[Less mistakes with copies of almost identical code] - -This applies to all the aggressively macroed code, again. -[Stricter type control, less bugs, code is as fast as before] - -"Zero abstraction cost" is the ground C++ principle. -Much work can be done at the compile-time, based on type checking, inlining -and optimization. **Amount of abstractions used should have little impact on -resulting machine code**. -[Code is fast as in C] - -For example: wrapping ``Eterm`` into a class will -not affect its memory and code footprint, but give full control to the developer -on how the type is convertable, what goes in and how it comes out, how to copy -it, what to do when the type is destroyed, also will allow to group all tool -macros and functions inside that class. -[Code is as fast as in C] - -Many loops can be remade generic using higher order functions. -C++ compiler often is smart enough to inline them without degrading machine -code quality. -[Code is as fast as in C] [Less bugs when using generic algorithms] - -Performance and Safety -``````````````````````` - -Smart pointers and RAII should be used for temporary memory (resource) -allocations reducing manual resource management. Let compiler remember, when -you have to reduce that refcount or free that temporary buffer. -[Automatic resource management at little to no cost] - -With const-correctness we gain better control on what can be changed where. -Current OTP source is not const-correct and safety is enforced through -convoluted locking and thorough thinking + debugging. -Const-correct code is transparent on what memory it touches, and is -easier to parallellize. Pure const-correct code is even better. -[Harder to create bad code] - -How Hard Is To Migrate ----------------------- - -I've done several attempts with varying degree of success. -One must fix all C++ keywords used as variable and argument names (easy). - -Because C++ is stricter to pointers and type casts, one must revisit all places, -where ``erts_alloc/realloc`` are happening and fix the type casts there. - -Generated tables also use pointer conversion and the generation scripts must be -mended (several lines changes in few places). - -Note: https://www.youtube.com/watch?v=w5Z4JlMJ1VQ -CppCon 2016: Tim Haines “Improving Performance Through Compiler Switches..." diff --git a/docs/build/html/_static/alabaster.css b/docs/build/html/_static/alabaster.css deleted file mode 100644 index 517d0b2..0000000 --- a/docs/build/html/_static/alabaster.css +++ /dev/null @@ -1,703 +0,0 @@ -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: Georgia, serif; - font-size: 17px; - background-color: #fff; - color: #000; - margin: 0; - padding: 0; -} - - -div.document { - width: 940px; - margin: 30px auto 0 auto; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 220px; -} - -div.sphinxsidebar { - width: 220px; - font-size: 14px; - line-height: 1.5; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #fff; - color: #3E4349; - padding: 0 30px 0 30px; -} - -div.body > .section { - text-align: left; -} - -div.footer { - width: 940px; - margin: 20px auto 30px auto; - font-size: 14px; - color: #888; - text-align: right; -} - -div.footer a { - color: #888; -} - -p.caption { - font-family: inherit; - font-size: inherit; -} - - -div.relations { - display: none; -} - - -div.sphinxsidebar a { - color: #444; - text-decoration: none; - border-bottom: 1px dotted #999; -} - -div.sphinxsidebar a:hover { - border-bottom: 1px solid #999; -} - -div.sphinxsidebarwrapper { - padding: 18px 10px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 0; - margin: -10px 0 0 0px; - text-align: center; -} - -div.sphinxsidebarwrapper h1.logo { - margin-top: -10px; - text-align: center; - margin-bottom: 5px; - text-align: left; -} - -div.sphinxsidebarwrapper h1.logo-name { - margin-top: 0px; -} - -div.sphinxsidebarwrapper p.blurb { - margin-top: 0; - font-style: normal; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: Georgia, serif; - color: #444; - font-size: 24px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 20px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p.logo a, -div.sphinxsidebar h3 a, -div.sphinxsidebar p.logo a:hover, -div.sphinxsidebar h3 a:hover { - border: none; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar ul li.toctree-l1 > a { - font-size: 120%; -} - -div.sphinxsidebar ul li.toctree-l2 > a { - font-size: 110%; -} - -div.sphinxsidebar input { - border: 1px solid #CCC; - font-family: Georgia, serif; - font-size: 1em; -} - -div.sphinxsidebar hr { - border: none; - height: 1px; - color: #AAA; - background: #AAA; - - text-align: left; - margin-left: 0; - width: 50%; -} - -div.sphinxsidebar .badge { - border-bottom: none; -} - -div.sphinxsidebar .badge:hover { - border-bottom: none; -} - -/* To address an issue with donation coming after search */ -div.sphinxsidebar h3.donation { - margin-top: 10px; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: Georgia, serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #DDD; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #EAEAEA; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - margin: 20px 0px; - padding: 10px 30px; - background-color: #EEE; - border: 1px solid #CCC; -} - -div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fafafa; -} - -div.admonition p.admonition-title { - font-family: Georgia, serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight { - background-color: #fff; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.warning { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.danger { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.error { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.caution { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.attention { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.important { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.note { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.tip { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.hint { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.seealso { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.topic { - background-color: #EEE; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt, code { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.9em; -} - -.hll { - background-color: #FFC; - margin: 0 -12px; - padding: 0 12px; - display: block; -} - -img.screenshot { -} - -tt.descname, tt.descclassname, code.descname, code.descclassname { - font-size: 0.95em; -} - -tt.descname, code.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #EEE; - background: #FDFDFD; - font-size: 0.9em; -} - -table.footnote + table.footnote { - margin-top: -15px; - border-top: none; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.field-list p { - margin-bottom: 0.8em; -} - -/* Cloned from - * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 - */ -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -table.footnote td.label { - width: .1px; - padding: 0.3em 0 0.3em 0.5em; -} - -table.footnote td { - padding: 0.3em 0.5em; -} - -dl { - margin-left: 0; - margin-right: 0; - margin-top: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -blockquote { - margin: 0 0 0 30px; - padding: 0; -} - -ul, ol { - /* Matches the 30px from the narrow-screen "li > ul" selector below */ - margin: 10px 0 10px 30px; - padding: 0; -} - -pre { - background: #EEE; - padding: 7px 30px; - margin: 15px 0px; - line-height: 1.3em; -} - -div.viewcode-block:target { - background: #ffd; -} - -dl pre, blockquote pre, li pre { - margin-left: 0; - padding-left: 30px; -} - -tt, code { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, code.xref, a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fff; -} - -a.reference { - text-decoration: none; - border-bottom: 1px dotted #004B6B; -} - -/* Don't put an underline on images */ -a.image-reference, a.image-reference:hover { - border-bottom: none; -} - -a.reference:hover { - border-bottom: 1px solid #6D4100; -} - -a.footnote-reference { - text-decoration: none; - font-size: 0.7em; - vertical-align: top; - border-bottom: 1px dotted #004B6B; -} - -a.footnote-reference:hover { - border-bottom: 1px solid #6D4100; -} - -a:hover tt, a:hover code { - background: #EEE; -} - - -@media screen and (max-width: 870px) { - - div.sphinxsidebar { - display: none; - } - - div.document { - width: 100%; - - } - - div.documentwrapper { - margin-left: 0; - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - } - - div.bodywrapper { - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - margin-left: 0; - } - - ul { - margin-left: 0; - } - - li > ul { - /* Matches the 30px from the "ul, ol" selector above */ - margin-left: 30px; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .bodywrapper { - margin: 0; - } - - .footer { - width: auto; - } - - .github { - display: none; - } - - - -} - - - -@media screen and (max-width: 875px) { - - body { - margin: 0; - padding: 20px 30px; - } - - div.documentwrapper { - float: none; - background: #fff; - } - - div.sphinxsidebar { - display: block; - float: none; - width: 102.5%; - margin: 50px -30px -20px -30px; - padding: 10px 20px; - background: #333; - color: #FFF; - } - - div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, - div.sphinxsidebar h3 a { - color: #fff; - } - - div.sphinxsidebar a { - color: #AAA; - } - - div.sphinxsidebar p.logo { - display: none; - } - - div.document { - width: 100%; - margin: 0; - } - - div.footer { - display: none; - } - - div.bodywrapper { - margin: 0; - } - - div.body { - min-height: 0; - padding: 0; - } - - .rtd_doc_footer { - display: none; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .footer { - width: auto; - } - - .github { - display: none; - } -} - - -/* misc. */ - -.revsys-inline { - display: none!important; -} - -/* Make nested-list/multi-paragraph items look better in Releases changelog - * pages. Without this, docutils' magical list fuckery causes inconsistent - * formatting between different release sub-lists. - */ -div#changelog > div.section > ul > li > p:only-child { - margin-bottom: 0; -} - -/* Hide fugly table cell borders in ..bibliography:: directive output */ -table.docutils.citation, table.docutils.citation td, table.docutils.citation th { - border: none; - /* Below needed in some edge cases; if not applied, bottom shadows appear */ - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - - -/* relbar */ - -.related { - line-height: 30px; - width: 100%; - font-size: 0.9rem; -} - -.related.top { - border-bottom: 1px solid #EEE; - margin-bottom: 20px; -} - -.related.bottom { - border-top: 1px solid #EEE; -} - -.related ul { - padding: 0; - margin: 0; - list-style: none; -} - -.related li { - display: inline; -} - -nav#rellinks { - float: right; -} - -nav#rellinks li+li:before { - content: "|"; -} - -nav#breadcrumbs li+li:before { - content: "\00BB"; -} - -/* Hide certain items when printing */ -@media print { - div.related { - display: none; - } -} \ No newline at end of file diff --git a/docs/build/html/_static/basic.css b/docs/build/html/_static/basic.css deleted file mode 100644 index 7577acb..0000000 --- a/docs/build/html/_static/basic.css +++ /dev/null @@ -1,903 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li p.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 360px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, figure.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, figure.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, figure.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, figure.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar, -aside.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} - -nav.contents, -aside.topic, -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ - -nav.contents, -aside.topic, -div.topic { - border: 1px solid #ccc; - padding: 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -aside.sidebar > :last-child, -nav.contents > :last-child, -aside.topic > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -aside.sidebar::after, -nav.contents::after, -aside.topic::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure, figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption, figcaption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number, -figcaption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text, -figcaption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - -/* -- object description styles --------------------------------------------- */ - -.sig { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; -} - -.sig-name, code.descname { - background-color: transparent; - font-weight: bold; -} - -.sig-name { - font-size: 1.1em; -} - -code.descname { - font-size: 1.2em; -} - -.sig-prename, code.descclassname { - background-color: transparent; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.sig-param.n { - font-style: italic; -} - -/* C++ specific styling */ - -.sig-inline.c-texpr, -.sig-inline.cpp-texpr { - font-family: unset; -} - -.sig.c .k, .sig.c .kt, -.sig.cpp .k, .sig.cpp .kt { - color: #0033B3; -} - -.sig.c .m, -.sig.cpp .m { - color: #1750EB; -} - -.sig.c .s, .sig.c .sc, -.sig.cpp .s, .sig.cpp .sc { - color: #067D17; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} - -aside.footnote > span, -div.citation > span { - float: left; -} -aside.footnote > span:last-of-type, -div.citation > span:last-of-type { - padding-right: 0.5em; -} -aside.footnote > p { - margin-left: 2em; -} -div.citation > p { - margin-left: 4em; -} -aside.footnote > p:last-of-type, -div.citation > p:last-of-type { - margin-bottom: 0em; -} -aside.footnote > p:last-of-type:after, -div.citation > p:last-of-type:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0 0.5em; - content: ":"; - display: inline-block; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; - white-space: nowrap; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -span.linenos, -div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; - -webkit-user-select: text; /* Safari fallback only */ - -webkit-user-select: none; /* Chrome/Safari */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE10+ */ -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - margin: 1em 0; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: absolute; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/docs/build/html/_static/custom.css b/docs/build/html/_static/custom.css deleted file mode 100644 index 2a924f1..0000000 --- a/docs/build/html/_static/custom.css +++ /dev/null @@ -1 +0,0 @@ -/* This file intentionally left blank. */ diff --git a/docs/build/html/_static/doctools.js b/docs/build/html/_static/doctools.js deleted file mode 100644 index d06a71d..0000000 --- a/docs/build/html/_static/doctools.js +++ /dev/null @@ -1,156 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Base JavaScript utilities for all Sphinx HTML documentation. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ -"use strict"; - -const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ - "TEXTAREA", - "INPUT", - "SELECT", - "BUTTON", -]); - -const _ready = (callback) => { - if (document.readyState !== "loading") { - callback(); - } else { - document.addEventListener("DOMContentLoaded", callback); - } -}; - -/** - * Small JavaScript module for the documentation. - */ -const Documentation = { - init: () => { - Documentation.initDomainIndexTable(); - Documentation.initOnKeyListeners(); - }, - - /** - * i18n support - */ - TRANSLATIONS: {}, - PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), - LOCALE: "unknown", - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext: (string) => { - const translated = Documentation.TRANSLATIONS[string]; - switch (typeof translated) { - case "undefined": - return string; // no translation - case "string": - return translated; // translation exists - default: - return translated[0]; // (singular, plural) translation tuple exists - } - }, - - ngettext: (singular, plural, n) => { - const translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated !== "undefined") - return translated[Documentation.PLURAL_EXPR(n)]; - return n === 1 ? singular : plural; - }, - - addTranslations: (catalog) => { - Object.assign(Documentation.TRANSLATIONS, catalog.messages); - Documentation.PLURAL_EXPR = new Function( - "n", - `return (${catalog.plural_expr})` - ); - Documentation.LOCALE = catalog.locale; - }, - - /** - * helper function to focus on search bar - */ - focusSearchBar: () => { - document.querySelectorAll("input[name=q]")[0]?.focus(); - }, - - /** - * Initialise the domain index toggle buttons - */ - initDomainIndexTable: () => { - const toggler = (el) => { - const idNumber = el.id.substr(7); - const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); - if (el.src.substr(-9) === "minus.png") { - el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; - toggledRows.forEach((el) => (el.style.display = "none")); - } else { - el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; - toggledRows.forEach((el) => (el.style.display = "")); - } - }; - - const togglerElements = document.querySelectorAll("img.toggler"); - togglerElements.forEach((el) => - el.addEventListener("click", (event) => toggler(event.currentTarget)) - ); - togglerElements.forEach((el) => (el.style.display = "")); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); - }, - - initOnKeyListeners: () => { - // only install a listener if it is really needed - if ( - !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && - !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS - ) - return; - - document.addEventListener("keydown", (event) => { - // bail for input elements - if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; - // bail with special keys - if (event.altKey || event.ctrlKey || event.metaKey) return; - - if (!event.shiftKey) { - switch (event.key) { - case "ArrowLeft": - if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; - - const prevLink = document.querySelector('link[rel="prev"]'); - if (prevLink && prevLink.href) { - window.location.href = prevLink.href; - event.preventDefault(); - } - break; - case "ArrowRight": - if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; - - const nextLink = document.querySelector('link[rel="next"]'); - if (nextLink && nextLink.href) { - window.location.href = nextLink.href; - event.preventDefault(); - } - break; - } - } - - // some keyboard layouts may need Shift to get / - switch (event.key) { - case "/": - if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; - Documentation.focusSearchBar(); - event.preventDefault(); - } - }); - }, -}; - -// quick alias for translations -const _ = Documentation.gettext; - -_ready(Documentation.init); diff --git a/docs/build/html/_static/documentation_options.js b/docs/build/html/_static/documentation_options.js deleted file mode 100644 index 5bef6f4..0000000 --- a/docs/build/html/_static/documentation_options.js +++ /dev/null @@ -1,14 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '1.1', - LANGUAGE: 'en', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false, - SHOW_SEARCH_SUMMARY: true, - ENABLE_SEARCH_SHORTCUTS: true, -}; \ No newline at end of file diff --git a/docs/build/html/_static/file.png b/docs/build/html/_static/file.png deleted file mode 100644 index a858a41..0000000 Binary files a/docs/build/html/_static/file.png and /dev/null differ diff --git a/docs/build/html/_static/img/Beam Wisdoms Logo.svg b/docs/build/html/_static/img/Beam Wisdoms Logo.svg deleted file mode 100644 index 5928fa8..0000000 --- a/docs/build/html/_static/img/Beam Wisdoms Logo.svg +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - BEAM Wisdoms - - - - - - diff --git a/docs/build/html/_static/img/bw_logo.png b/docs/build/html/_static/img/bw_logo.png deleted file mode 100644 index e3508bb..0000000 Binary files a/docs/build/html/_static/img/bw_logo.png and /dev/null differ diff --git a/docs/build/html/_static/img/eli5-atom-tab.png b/docs/build/html/_static/img/eli5-atom-tab.png deleted file mode 100644 index 3aedff0..0000000 Binary files a/docs/build/html/_static/img/eli5-atom-tab.png and /dev/null differ diff --git a/docs/build/html/_static/img/eli5-atom-tab.svg b/docs/build/html/_static/img/eli5-atom-tab.svg deleted file mode 100644 index 3ab3ee2..0000000 --- a/docs/build/html/_static/img/eli5-atom-tab.svg +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - DOWNUPallocandasyncbandbsr... - - a Term (machine Word) - - Tag marks Atom - index in the atom table - - - - Value - - - Value and Tag are invisible toyour program - - diff --git a/docs/build/html/_static/img/eli5-process-mqueue.png b/docs/build/html/_static/img/eli5-process-mqueue.png deleted file mode 100644 index 2d9be17..0000000 Binary files a/docs/build/html/_static/img/eli5-process-mqueue.png and /dev/null differ diff --git a/docs/build/html/_static/img/eli5-process-mqueue.svg b/docs/build/html/_static/img/eli5-process-mqueue.svg deleted file mode 100644 index 58cc2b1..0000000 --- a/docs/build/html/_static/img/eli5-process-mqueue.svg +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A process - Current message pointer - Queue head - - diff --git a/docs/build/html/_static/img/eli5-process-sched.png b/docs/build/html/_static/img/eli5-process-sched.png deleted file mode 100644 index 2ef161e..0000000 Binary files a/docs/build/html/_static/img/eli5-process-sched.png and /dev/null differ diff --git a/docs/build/html/_static/img/eli5-process-sched.svg b/docs/build/html/_static/img/eli5-process-sched.svg deleted file mode 100644 index a8d6b10..0000000 --- a/docs/build/html/_static/img/eli5-process-sched.svg +++ /dev/null @@ -1,479 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/build/html/_static/img/eli5-process-stack.png b/docs/build/html/_static/img/eli5-process-stack.png deleted file mode 100644 index 63a952e..0000000 Binary files a/docs/build/html/_static/img/eli5-process-stack.png and /dev/null differ diff --git a/docs/build/html/_static/img/eli5-process-stack.svg b/docs/build/html/_static/img/eli5-process-stack.svg deleted file mode 100644 index 6bdd1d4..0000000 --- a/docs/build/html/_static/img/eli5-process-stack.svg +++ /dev/null @@ -1,253 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - heap start - heap top - heap grows - - - - - heap end - - - - - - - - - - - - - stack top - - - - - stack grows - - - - diff --git a/docs/build/html/_static/img/eli5-section.png b/docs/build/html/_static/img/eli5-section.png deleted file mode 100644 index 4975439..0000000 Binary files a/docs/build/html/_static/img/eli5-section.png and /dev/null differ diff --git a/docs/build/html/_static/img/eli5-section.svg b/docs/build/html/_static/img/eli5-section.svg deleted file mode 100644 index 4c23989..0000000 --- a/docs/build/html/_static/img/eli5-section.svg +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/build/html/_static/img/memory-layout-bignum.png b/docs/build/html/_static/img/memory-layout-bignum.png deleted file mode 100644 index 87ff7bc..0000000 Binary files a/docs/build/html/_static/img/memory-layout-bignum.png and /dev/null differ diff --git a/docs/build/html/_static/img/memory-layout-bignum.svg b/docs/build/html/_static/img/memory-layout-bignum.svg deleted file mode 100644 index 31a616c..0000000 --- a/docs/build/html/_static/img/memory-layout-bignum.svg +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - TAG_PRIMARY_BOXED - Word - Pointer - - - - - - - - - - - - - Arity=N - - 0x11223344 - - 0x5566 - - - - Word - Word - Word - - TAG_PRIMARY_HEADER - POS| - - Displaying a bignum 0x112233445566for a 32-bit Word size - NEG_BIG_SUBTAG - + - - - - diff --git a/docs/build/html/_static/img/memory-layout-box.png b/docs/build/html/_static/img/memory-layout-box.png deleted file mode 100644 index 3d1d978..0000000 Binary files a/docs/build/html/_static/img/memory-layout-box.png and /dev/null differ diff --git a/docs/build/html/_static/img/memory-layout-box.svg b/docs/build/html/_static/img/memory-layout-box.svg deleted file mode 100644 index 234fd26..0000000 --- a/docs/build/html/_static/img/memory-layout-box.svg +++ /dev/null @@ -1,320 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - TAG_PRIMARY_BOX - 32 or 64bit Word - Pointer to the heap - - - Remainingbits — arity - 32 or 64bit Word - 32 or 64bit Word[] array - - - TAG_PRIMARY_HEADER - - - - - - - - - - - SUBTAG - - - - - - - 'Arity' words of content - - diff --git a/docs/build/html/_static/img/memory-layout-export.png b/docs/build/html/_static/img/memory-layout-export.png deleted file mode 100644 index 2a7eb84..0000000 Binary files a/docs/build/html/_static/img/memory-layout-export.png and /dev/null differ diff --git a/docs/build/html/_static/img/memory-layout-export.svg b/docs/build/html/_static/img/memory-layout-export.svg deleted file mode 100644 index 896f321..0000000 --- a/docs/build/html/_static/img/memory-layout-export.svg +++ /dev/null @@ -1,256 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - TAG_PRIMARY_BOXED - Word - Pointer - - - - - - - - - - Arity=1 - Word - - EXPORT_SUBTAG - - - - Raw Export * pointer - - diff --git a/docs/build/html/_static/img/memory-layout-immed.png b/docs/build/html/_static/img/memory-layout-immed.png deleted file mode 100644 index 52cef19..0000000 Binary files a/docs/build/html/_static/img/memory-layout-immed.png and /dev/null differ diff --git a/docs/build/html/_static/img/memory-layout-immed.svg b/docs/build/html/_static/img/memory-layout-immed.svg deleted file mode 100644 index b615b13..0000000 --- a/docs/build/html/_static/img/memory-layout-immed.svg +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - TAG_PRIMARY_IMMED1 - immed1 tag - - - - - immed2 tag - 32 or 64bit Word - - - diff --git a/docs/build/html/_static/img/memory-layout-list.png b/docs/build/html/_static/img/memory-layout-list.png deleted file mode 100644 index a8c5e37..0000000 Binary files a/docs/build/html/_static/img/memory-layout-list.png and /dev/null differ diff --git a/docs/build/html/_static/img/memory-layout-list.svg b/docs/build/html/_static/img/memory-layout-list.svg deleted file mode 100644 index 6c05c11..0000000 --- a/docs/build/html/_static/img/memory-layout-list.svg +++ /dev/null @@ -1,385 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - TAG_PRIMARY_LIST - 32 or 64bit Word - Pointer to the heap - - - CAR (or the head) - CDR (or the tail) - 32 or 64bit Word - 32 or 64bit Word - - - - - - - - Pointer to another cons - - This may have listtag again! - - - - - - - Pointer to another cons - - - - - - - NIL - - - - - - diff --git a/docs/build/html/_static/img/memory-layout-ref.png b/docs/build/html/_static/img/memory-layout-ref.png deleted file mode 100644 index 1db6465..0000000 Binary files a/docs/build/html/_static/img/memory-layout-ref.png and /dev/null differ diff --git a/docs/build/html/_static/img/memory-layout-ref.svg b/docs/build/html/_static/img/memory-layout-ref.svg deleted file mode 100644 index a795851..0000000 --- a/docs/build/html/_static/img/memory-layout-ref.svg +++ /dev/null @@ -1,554 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - TAG_PRIMARY_BOXED - Word - Pointer - - - - - - - - - Arity=3 - 32-bit Words - - TAG_PRIMARY_HEADER - REF_SUBTAG - - - - - - Data2 (32 bit) - Data1 (32 bit) - Data0 (18 bit) - - - - - - - - Arity=2 - 64-bit Little Endian - - TAG_PRIMARY_HEADER - REF_SUBTAG - - - - Data2 - Data1 - Data0 - ERTS_REF_NUMBERS=3 - - 0 - 31 - 63 - 31 - 0 - - - - - - diff --git a/docs/build/html/_static/img/memory-layout-tuple.png b/docs/build/html/_static/img/memory-layout-tuple.png deleted file mode 100644 index 10bfbd2..0000000 Binary files a/docs/build/html/_static/img/memory-layout-tuple.png and /dev/null differ diff --git a/docs/build/html/_static/img/memory-layout-tuple.svg b/docs/build/html/_static/img/memory-layout-tuple.svg deleted file mode 100644 index 99e0b8e..0000000 --- a/docs/build/html/_static/img/memory-layout-tuple.svg +++ /dev/null @@ -1,321 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - TAG_PRIMARY_BOXED - Word - Pointer - - - - - - - - - - - - - Arity=N - - Element 1 - - Elem. N - - - - Word - Word - Word - - - TAG_PRIMARY_HEADER - ARITYVAL_SUBTAG - - diff --git a/docs/build/html/_static/language_data.js b/docs/build/html/_static/language_data.js deleted file mode 100644 index 250f566..0000000 --- a/docs/build/html/_static/language_data.js +++ /dev/null @@ -1,199 +0,0 @@ -/* - * language_data.js - * ~~~~~~~~~~~~~~~~ - * - * This script contains the language-specific data used by searchtools.js, - * namely the list of stopwords, stemmer, scorer and splitter. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; - - -/* Non-minified version is copied as a separate JS file, is available */ - -/** - * Porter Stemmer - */ -var Stemmer = function() { - - var step2list = { - ational: 'ate', - tional: 'tion', - enci: 'ence', - anci: 'ance', - izer: 'ize', - bli: 'ble', - alli: 'al', - entli: 'ent', - eli: 'e', - ousli: 'ous', - ization: 'ize', - ation: 'ate', - ator: 'ate', - alism: 'al', - iveness: 'ive', - fulness: 'ful', - ousness: 'ous', - aliti: 'al', - iviti: 'ive', - biliti: 'ble', - logi: 'log' - }; - - var step3list = { - icate: 'ic', - ative: '', - alize: 'al', - iciti: 'ic', - ical: 'ic', - ful: '', - ness: '' - }; - - var c = "[^aeiou]"; // consonant - var v = "[aeiouy]"; // vowel - var C = c + "[^aeiouy]*"; // consonant sequence - var V = v + "[aeiou]*"; // vowel sequence - - var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 - var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 - var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 - var s_v = "^(" + C + ")?" + v; // vowel in stem - - this.stemWord = function (w) { - var stem; - var suffix; - var firstch; - var origword = w; - - if (w.length < 3) - return w; - - var re; - var re2; - var re3; - var re4; - - firstch = w.substr(0,1); - if (firstch == "y") - w = firstch.toUpperCase() + w.substr(1); - - // Step 1a - re = /^(.+?)(ss|i)es$/; - re2 = /^(.+?)([^s])s$/; - - if (re.test(w)) - w = w.replace(re,"$1$2"); - else if (re2.test(w)) - w = w.replace(re2,"$1$2"); - - // Step 1b - re = /^(.+?)eed$/; - re2 = /^(.+?)(ed|ing)$/; - if (re.test(w)) { - var fp = re.exec(w); - re = new RegExp(mgr0); - if (re.test(fp[1])) { - re = /.$/; - w = w.replace(re,""); - } - } - else if (re2.test(w)) { - var fp = re2.exec(w); - stem = fp[1]; - re2 = new RegExp(s_v); - if (re2.test(stem)) { - w = stem; - re2 = /(at|bl|iz)$/; - re3 = new RegExp("([^aeiouylsz])\\1$"); - re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); - if (re2.test(w)) - w = w + "e"; - else if (re3.test(w)) { - re = /.$/; - w = w.replace(re,""); - } - else if (re4.test(w)) - w = w + "e"; - } - } - - // Step 1c - re = /^(.+?)y$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(s_v); - if (re.test(stem)) - w = stem + "i"; - } - - // Step 2 - re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - suffix = fp[2]; - re = new RegExp(mgr0); - if (re.test(stem)) - w = stem + step2list[suffix]; - } - - // Step 3 - re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - suffix = fp[2]; - re = new RegExp(mgr0); - if (re.test(stem)) - w = stem + step3list[suffix]; - } - - // Step 4 - re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; - re2 = /^(.+?)(s|t)(ion)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(mgr1); - if (re.test(stem)) - w = stem; - } - else if (re2.test(w)) { - var fp = re2.exec(w); - stem = fp[1] + fp[2]; - re2 = new RegExp(mgr1); - if (re2.test(stem)) - w = stem; - } - - // Step 5 - re = /^(.+?)e$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(mgr1); - re2 = new RegExp(meq1); - re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); - if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) - w = stem; - } - re = /ll$/; - re2 = new RegExp(mgr1); - if (re.test(w) && re2.test(w)) { - re = /.$/; - w = w.replace(re,""); - } - - // and turn initial Y back to y - if (firstch == "y") - w = firstch.toLowerCase() + w.substr(1); - return w; - } -} - diff --git a/docs/build/html/_static/minus.png b/docs/build/html/_static/minus.png deleted file mode 100644 index d96755f..0000000 Binary files a/docs/build/html/_static/minus.png and /dev/null differ diff --git a/docs/build/html/_static/plus.png b/docs/build/html/_static/plus.png deleted file mode 100644 index 7107cec..0000000 Binary files a/docs/build/html/_static/plus.png and /dev/null differ diff --git a/docs/build/html/_static/pygments.css b/docs/build/html/_static/pygments.css deleted file mode 100644 index 691aeb8..0000000 --- a/docs/build/html/_static/pygments.css +++ /dev/null @@ -1,74 +0,0 @@ -pre { line-height: 125%; } -td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -.highlight .hll { background-color: #ffffcc } -.highlight { background: #eeffcc; } -.highlight .c { color: #408090; font-style: italic } /* Comment */ -.highlight .err { border: 1px solid #FF0000 } /* Error */ -.highlight .k { color: #007020; font-weight: bold } /* Keyword */ -.highlight .o { color: #666666 } /* Operator */ -.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ -.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #007020 } /* Comment.Preproc */ -.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ -.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ -.highlight .gd { color: #A00000 } /* Generic.Deleted */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #FF0000 } /* Generic.Error */ -.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #333333 } /* Generic.Output */ -.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #0044DD } /* Generic.Traceback */ -.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #007020 } /* Keyword.Pseudo */ -.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #902000 } /* Keyword.Type */ -.highlight .m { color: #208050 } /* Literal.Number */ -.highlight .s { color: #4070a0 } /* Literal.String */ -.highlight .na { color: #4070a0 } /* Name.Attribute */ -.highlight .nb { color: #007020 } /* Name.Builtin */ -.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ -.highlight .no { color: #60add5 } /* Name.Constant */ -.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ -.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ -.highlight .ne { color: #007020 } /* Name.Exception */ -.highlight .nf { color: #06287e } /* Name.Function */ -.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ -.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ -.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #bb60d5 } /* Name.Variable */ -.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ -.highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.highlight .mb { color: #208050 } /* Literal.Number.Bin */ -.highlight .mf { color: #208050 } /* Literal.Number.Float */ -.highlight .mh { color: #208050 } /* Literal.Number.Hex */ -.highlight .mi { color: #208050 } /* Literal.Number.Integer */ -.highlight .mo { color: #208050 } /* Literal.Number.Oct */ -.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ -.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ -.highlight .sc { color: #4070a0 } /* Literal.String.Char */ -.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ -.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ -.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ -.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ -.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ -.highlight .sx { color: #c65d09 } /* Literal.String.Other */ -.highlight .sr { color: #235388 } /* Literal.String.Regex */ -.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ -.highlight .ss { color: #517918 } /* Literal.String.Symbol */ -.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ -.highlight .fm { color: #06287e } /* Name.Function.Magic */ -.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ -.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ -.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ -.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ -.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/build/html/_static/searchtools.js b/docs/build/html/_static/searchtools.js deleted file mode 100644 index 97d56a7..0000000 --- a/docs/build/html/_static/searchtools.js +++ /dev/null @@ -1,566 +0,0 @@ -/* - * searchtools.js - * ~~~~~~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for the full-text search. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ -"use strict"; - -/** - * Simple result scoring code. - */ -if (typeof Scorer === "undefined") { - var Scorer = { - // Implement the following function to further tweak the score for each result - // The function takes a result array [docname, title, anchor, descr, score, filename] - // and returns the new score. - /* - score: result => { - const [docname, title, anchor, descr, score, filename] = result - return score - }, - */ - - // query matches the full name of an object - objNameMatch: 11, - // or matches in the last dotted part of the object name - objPartialMatch: 6, - // Additive scores depending on the priority of the object - objPrio: { - 0: 15, // used to be importantResults - 1: 5, // used to be objectResults - 2: -5, // used to be unimportantResults - }, - // Used when the priority is not in the mapping. - objPrioDefault: 0, - - // query found in title - title: 15, - partialTitle: 7, - // query found in terms - term: 5, - partialTerm: 2, - }; -} - -const _removeChildren = (element) => { - while (element && element.lastChild) element.removeChild(element.lastChild); -}; - -/** - * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping - */ -const _escapeRegExp = (string) => - string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string - -const _displayItem = (item, searchTerms) => { - const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; - const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; - const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; - const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; - const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; - - const [docName, title, anchor, descr, score, _filename] = item; - - let listItem = document.createElement("li"); - let requestUrl; - let linkUrl; - if (docBuilder === "dirhtml") { - // dirhtml builder - let dirname = docName + "/"; - if (dirname.match(/\/index\/$/)) - dirname = dirname.substring(0, dirname.length - 6); - else if (dirname === "index/") dirname = ""; - requestUrl = docUrlRoot + dirname; - linkUrl = requestUrl; - } else { - // normal html builders - requestUrl = docUrlRoot + docName + docFileSuffix; - linkUrl = docName + docLinkSuffix; - } - let linkEl = listItem.appendChild(document.createElement("a")); - linkEl.href = linkUrl + anchor; - linkEl.dataset.score = score; - linkEl.innerHTML = title; - if (descr) - listItem.appendChild(document.createElement("span")).innerHTML = - " (" + descr + ")"; - else if (showSearchSummary) - fetch(requestUrl) - .then((responseData) => responseData.text()) - .then((data) => { - if (data) - listItem.appendChild( - Search.makeSearchSummary(data, searchTerms) - ); - }); - Search.output.appendChild(listItem); -}; -const _finishSearch = (resultCount) => { - Search.stopPulse(); - Search.title.innerText = _("Search Results"); - if (!resultCount) - Search.status.innerText = Documentation.gettext( - "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." - ); - else - Search.status.innerText = _( - `Search finished, found ${resultCount} page(s) matching the search query.` - ); -}; -const _displayNextItem = ( - results, - resultCount, - searchTerms -) => { - // results left, load the summary and display it - // this is intended to be dynamic (don't sub resultsCount) - if (results.length) { - _displayItem(results.pop(), searchTerms); - setTimeout( - () => _displayNextItem(results, resultCount, searchTerms), - 5 - ); - } - // search finished, update title and status message - else _finishSearch(resultCount); -}; - -/** - * Default splitQuery function. Can be overridden in ``sphinx.search`` with a - * custom function per language. - * - * The regular expression works by splitting the string on consecutive characters - * that are not Unicode letters, numbers, underscores, or emoji characters. - * This is the same as ``\W+`` in Python, preserving the surrogate pair area. - */ -if (typeof splitQuery === "undefined") { - var splitQuery = (query) => query - .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) - .filter(term => term) // remove remaining empty strings -} - -/** - * Search Module - */ -const Search = { - _index: null, - _queued_query: null, - _pulse_status: -1, - - htmlToText: (htmlString) => { - const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); - htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); - const docContent = htmlElement.querySelector('[role="main"]'); - if (docContent !== undefined) return docContent.textContent; - console.warn( - "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." - ); - return ""; - }, - - init: () => { - const query = new URLSearchParams(window.location.search).get("q"); - document - .querySelectorAll('input[name="q"]') - .forEach((el) => (el.value = query)); - if (query) Search.performSearch(query); - }, - - loadIndex: (url) => - (document.body.appendChild(document.createElement("script")).src = url), - - setIndex: (index) => { - Search._index = index; - if (Search._queued_query !== null) { - const query = Search._queued_query; - Search._queued_query = null; - Search.query(query); - } - }, - - hasIndex: () => Search._index !== null, - - deferQuery: (query) => (Search._queued_query = query), - - stopPulse: () => (Search._pulse_status = -1), - - startPulse: () => { - if (Search._pulse_status >= 0) return; - - const pulse = () => { - Search._pulse_status = (Search._pulse_status + 1) % 4; - Search.dots.innerText = ".".repeat(Search._pulse_status); - if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); - }; - pulse(); - }, - - /** - * perform a search for something (or wait until index is loaded) - */ - performSearch: (query) => { - // create the required interface elements - const searchText = document.createElement("h2"); - searchText.textContent = _("Searching"); - const searchSummary = document.createElement("p"); - searchSummary.classList.add("search-summary"); - searchSummary.innerText = ""; - const searchList = document.createElement("ul"); - searchList.classList.add("search"); - - const out = document.getElementById("search-results"); - Search.title = out.appendChild(searchText); - Search.dots = Search.title.appendChild(document.createElement("span")); - Search.status = out.appendChild(searchSummary); - Search.output = out.appendChild(searchList); - - const searchProgress = document.getElementById("search-progress"); - // Some themes don't use the search progress node - if (searchProgress) { - searchProgress.innerText = _("Preparing search..."); - } - Search.startPulse(); - - // index already loaded, the browser was quick! - if (Search.hasIndex()) Search.query(query); - else Search.deferQuery(query); - }, - - /** - * execute search (requires search index to be loaded) - */ - query: (query) => { - const filenames = Search._index.filenames; - const docNames = Search._index.docnames; - const titles = Search._index.titles; - const allTitles = Search._index.alltitles; - const indexEntries = Search._index.indexentries; - - // stem the search terms and add them to the correct list - const stemmer = new Stemmer(); - const searchTerms = new Set(); - const excludedTerms = new Set(); - const highlightTerms = new Set(); - const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); - splitQuery(query.trim()).forEach((queryTerm) => { - const queryTermLower = queryTerm.toLowerCase(); - - // maybe skip this "word" - // stopwords array is from language_data.js - if ( - stopwords.indexOf(queryTermLower) !== -1 || - queryTerm.match(/^\d+$/) - ) - return; - - // stem the word - let word = stemmer.stemWord(queryTermLower); - // select the correct list - if (word[0] === "-") excludedTerms.add(word.substr(1)); - else { - searchTerms.add(word); - highlightTerms.add(queryTermLower); - } - }); - - if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js - localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) - } - - // console.debug("SEARCH: searching for:"); - // console.info("required: ", [...searchTerms]); - // console.info("excluded: ", [...excludedTerms]); - - // array of [docname, title, anchor, descr, score, filename] - let results = []; - _removeChildren(document.getElementById("search-progress")); - - const queryLower = query.toLowerCase(); - for (const [title, foundTitles] of Object.entries(allTitles)) { - if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { - for (const [file, id] of foundTitles) { - let score = Math.round(100 * queryLower.length / title.length) - results.push([ - docNames[file], - titles[file] !== title ? `${titles[file]} > ${title}` : title, - id !== null ? "#" + id : "", - null, - score, - filenames[file], - ]); - } - } - } - - // search for explicit entries in index directives - for (const [entry, foundEntries] of Object.entries(indexEntries)) { - if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { - for (const [file, id] of foundEntries) { - let score = Math.round(100 * queryLower.length / entry.length) - results.push([ - docNames[file], - titles[file], - id ? "#" + id : "", - null, - score, - filenames[file], - ]); - } - } - } - - // lookup as object - objectTerms.forEach((term) => - results.push(...Search.performObjectSearch(term, objectTerms)) - ); - - // lookup as search terms in fulltext - results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); - - // let the scorer override scores with a custom scoring function - if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); - - // now sort the results by score (in opposite order of appearance, since the - // display function below uses pop() to retrieve items) and then - // alphabetically - results.sort((a, b) => { - const leftScore = a[4]; - const rightScore = b[4]; - if (leftScore === rightScore) { - // same score: sort alphabetically - const leftTitle = a[1].toLowerCase(); - const rightTitle = b[1].toLowerCase(); - if (leftTitle === rightTitle) return 0; - return leftTitle > rightTitle ? -1 : 1; // inverted is intentional - } - return leftScore > rightScore ? 1 : -1; - }); - - // remove duplicate search results - // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept - let seen = new Set(); - results = results.reverse().reduce((acc, result) => { - let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); - if (!seen.has(resultStr)) { - acc.push(result); - seen.add(resultStr); - } - return acc; - }, []); - - results = results.reverse(); - - // for debugging - //Search.lastresults = results.slice(); // a copy - // console.info("search results:", Search.lastresults); - - // print the results - _displayNextItem(results, results.length, searchTerms); - }, - - /** - * search for object names - */ - performObjectSearch: (object, objectTerms) => { - const filenames = Search._index.filenames; - const docNames = Search._index.docnames; - const objects = Search._index.objects; - const objNames = Search._index.objnames; - const titles = Search._index.titles; - - const results = []; - - const objectSearchCallback = (prefix, match) => { - const name = match[4] - const fullname = (prefix ? prefix + "." : "") + name; - const fullnameLower = fullname.toLowerCase(); - if (fullnameLower.indexOf(object) < 0) return; - - let score = 0; - const parts = fullnameLower.split("."); - - // check for different match types: exact matches of full name or - // "last name" (i.e. last dotted part) - if (fullnameLower === object || parts.slice(-1)[0] === object) - score += Scorer.objNameMatch; - else if (parts.slice(-1)[0].indexOf(object) > -1) - score += Scorer.objPartialMatch; // matches in last name - - const objName = objNames[match[1]][2]; - const title = titles[match[0]]; - - // If more than one term searched for, we require other words to be - // found in the name/title/description - const otherTerms = new Set(objectTerms); - otherTerms.delete(object); - if (otherTerms.size > 0) { - const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); - if ( - [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) - ) - return; - } - - let anchor = match[3]; - if (anchor === "") anchor = fullname; - else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; - - const descr = objName + _(", in ") + title; - - // add custom score for some objects according to scorer - if (Scorer.objPrio.hasOwnProperty(match[2])) - score += Scorer.objPrio[match[2]]; - else score += Scorer.objPrioDefault; - - results.push([ - docNames[match[0]], - fullname, - "#" + anchor, - descr, - score, - filenames[match[0]], - ]); - }; - Object.keys(objects).forEach((prefix) => - objects[prefix].forEach((array) => - objectSearchCallback(prefix, array) - ) - ); - return results; - }, - - /** - * search for full-text terms in the index - */ - performTermsSearch: (searchTerms, excludedTerms) => { - // prepare search - const terms = Search._index.terms; - const titleTerms = Search._index.titleterms; - const filenames = Search._index.filenames; - const docNames = Search._index.docnames; - const titles = Search._index.titles; - - const scoreMap = new Map(); - const fileMap = new Map(); - - // perform the search on the required terms - searchTerms.forEach((word) => { - const files = []; - const arr = [ - { files: terms[word], score: Scorer.term }, - { files: titleTerms[word], score: Scorer.title }, - ]; - // add support for partial matches - if (word.length > 2) { - const escapedWord = _escapeRegExp(word); - Object.keys(terms).forEach((term) => { - if (term.match(escapedWord) && !terms[word]) - arr.push({ files: terms[term], score: Scorer.partialTerm }); - }); - Object.keys(titleTerms).forEach((term) => { - if (term.match(escapedWord) && !titleTerms[word]) - arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); - }); - } - - // no match but word was a required one - if (arr.every((record) => record.files === undefined)) return; - - // found search word in contents - arr.forEach((record) => { - if (record.files === undefined) return; - - let recordFiles = record.files; - if (recordFiles.length === undefined) recordFiles = [recordFiles]; - files.push(...recordFiles); - - // set score for the word in each file - recordFiles.forEach((file) => { - if (!scoreMap.has(file)) scoreMap.set(file, {}); - scoreMap.get(file)[word] = record.score; - }); - }); - - // create the mapping - files.forEach((file) => { - if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) - fileMap.get(file).push(word); - else fileMap.set(file, [word]); - }); - }); - - // now check if the files don't contain excluded terms - const results = []; - for (const [file, wordList] of fileMap) { - // check if all requirements are matched - - // as search terms with length < 3 are discarded - const filteredTermCount = [...searchTerms].filter( - (term) => term.length > 2 - ).length; - if ( - wordList.length !== searchTerms.size && - wordList.length !== filteredTermCount - ) - continue; - - // ensure that none of the excluded terms is in the search result - if ( - [...excludedTerms].some( - (term) => - terms[term] === file || - titleTerms[term] === file || - (terms[term] || []).includes(file) || - (titleTerms[term] || []).includes(file) - ) - ) - break; - - // select one (max) score for the file. - const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); - // add result to the result list - results.push([ - docNames[file], - titles[file], - "", - null, - score, - filenames[file], - ]); - } - return results; - }, - - /** - * helper function to return a node containing the - * search summary for a given text. keywords is a list - * of stemmed words. - */ - makeSearchSummary: (htmlText, keywords) => { - const text = Search.htmlToText(htmlText); - if (text === "") return null; - - const textLower = text.toLowerCase(); - const actualStartPosition = [...keywords] - .map((k) => textLower.indexOf(k.toLowerCase())) - .filter((i) => i > -1) - .slice(-1)[0]; - const startWithContext = Math.max(actualStartPosition - 120, 0); - - const top = startWithContext === 0 ? "" : "..."; - const tail = startWithContext + 240 < text.length ? "..." : ""; - - let summary = document.createElement("p"); - summary.classList.add("context"); - summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; - - return summary; - }, -}; - -_ready(Search.init); diff --git a/docs/build/html/_static/sphinx_highlight.js b/docs/build/html/_static/sphinx_highlight.js deleted file mode 100644 index aae669d..0000000 --- a/docs/build/html/_static/sphinx_highlight.js +++ /dev/null @@ -1,144 +0,0 @@ -/* Highlighting utilities for Sphinx HTML documentation. */ -"use strict"; - -const SPHINX_HIGHLIGHT_ENABLED = true - -/** - * highlight a given string on a node by wrapping it in - * span elements with the given class name. - */ -const _highlight = (node, addItems, text, className) => { - if (node.nodeType === Node.TEXT_NODE) { - const val = node.nodeValue; - const parent = node.parentNode; - const pos = val.toLowerCase().indexOf(text); - if ( - pos >= 0 && - !parent.classList.contains(className) && - !parent.classList.contains("nohighlight") - ) { - let span; - - const closestNode = parent.closest("body, svg, foreignObject"); - const isInSVG = closestNode && closestNode.matches("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.classList.add(className); - } - - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - parent.insertBefore( - span, - parent.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling - ) - ); - node.nodeValue = val.substr(0, pos); - - if (isInSVG) { - const rect = document.createElementNS( - "http://www.w3.org/2000/svg", - "rect" - ); - const bbox = parent.getBBox(); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute("class", className); - addItems.push({ parent: parent, target: rect }); - } - } - } else if (node.matches && !node.matches("button, select, textarea")) { - node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); - } -}; -const _highlightText = (thisNode, text, className) => { - let addItems = []; - _highlight(thisNode, addItems, text, className); - addItems.forEach((obj) => - obj.parent.insertAdjacentElement("beforebegin", obj.target) - ); -}; - -/** - * Small JavaScript module for the documentation. - */ -const SphinxHighlight = { - - /** - * highlight the search words provided in localstorage in the text - */ - highlightSearchWords: () => { - if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight - - // get and clear terms from localstorage - const url = new URL(window.location); - const highlight = - localStorage.getItem("sphinx_highlight_terms") - || url.searchParams.get("highlight") - || ""; - localStorage.removeItem("sphinx_highlight_terms") - url.searchParams.delete("highlight"); - window.history.replaceState({}, "", url); - - // get individual terms from highlight string - const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); - if (terms.length === 0) return; // nothing to do - - // There should never be more than one element matching "div.body" - const divBody = document.querySelectorAll("div.body"); - const body = divBody.length ? divBody[0] : document.querySelector("body"); - window.setTimeout(() => { - terms.forEach((term) => _highlightText(body, term, "highlighted")); - }, 10); - - const searchBox = document.getElementById("searchbox"); - if (searchBox === null) return; - searchBox.appendChild( - document - .createRange() - .createContextualFragment( - '" - ) - ); - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords: () => { - document - .querySelectorAll("#searchbox .highlight-link") - .forEach((el) => el.remove()); - document - .querySelectorAll("span.highlighted") - .forEach((el) => el.classList.remove("highlighted")); - localStorage.removeItem("sphinx_highlight_terms") - }, - - initEscapeListener: () => { - // only install a listener if it is really needed - if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; - - document.addEventListener("keydown", (event) => { - // bail for input elements - if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; - // bail with special keys - if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; - if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { - SphinxHighlight.hideSearchWords(); - event.preventDefault(); - } - }); - }, -}; - -_ready(SphinxHighlight.highlightSearchWords); -_ready(SphinxHighlight.initEscapeListener); diff --git a/docs/build/html/definitions.html b/docs/build/html/definitions.html deleted file mode 100644 index 0fd3c47..0000000 --- a/docs/build/html/definitions.html +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - - BEAM Definitions — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

BEAM Definitions

-

For specific constant values, bit positions and bit sizes please always -refer to original beam sources, file: erl_term.h

-
-
Boxed Value

A term value, whose primary tag is -(TAG_PRIMARY_BOXED=2), contains a pointer to data on heap.

-

The first word of the box always has header tag (TAG_PRIMARY_HEADER=0) -in its 2 least-significant bits. Then goes the subtag (following 4 bits) -which determines type of the value inside the box. Knowing this allows -scanning heap and interpreting found data.

-

VM uses boxes to store larger values, which do not fit into -Word size minus 4 bits (immediate-1) -or Word size minus 6 bits -(for immediate-2).

-

Examples of box: -bigint, float, fun, export, heap and refcounted binary, -external ports and pids (with host name in them).

-
-
-
-
Cache Locality

A mythical creature used to scare naughty developers. It may have either -huge impact on your code performance or very little. Always run -performance tests before you start optimizing for this.

-
-
Context

Virtual machine context is a small structure which contains a copy of -active registers, instruction pointer, few other pointers from the -currently running process. It is stored in CPU registers or on stack -(based on C compiler judgement when building the emulator).

-

When a process is ready to run, its fields are copied into the context, -i.e. swapped in. -When a process is suspended or scheduled out, the context is stored back -into the process. This operation is called swapping out. -This is not a cheap operation, so VM tries to minimize context switches.

-

A context switch is also performed when changing from BEAM code to native -compiled code by HiPE or JIT. This is why mixing HiPE and normal Erlang -code in your program, which calls each other, is an expensive luxury.

-
-
-
-
CP, Continuation pointer

A raw pointer to a location in prepared BEAM code. -It is used as a return value or as a label offset. -CP and can only be found on the stack, never in registers or on heap.

-
-
-
-
Header tag

When a box is referenced or when a block of memory is stored in heap, -its first Word usually has few least-significant bits -reserved (currently 6). First goes the primary tag (2 bits of -TAG_PRIMARY_HEADER=0). Then follows the header tag (4 bits) which -defines the type of contents. Remaining bits may hold other information, -often these bits store the arity (contents size).

-
-
-
-
Immediate

A term value, whose primary tag is -TAG_PRIMARY_IMMED1=3 contains an immediate value. Two bits follow the -primary tag and determine the value type (TAG_IMMED1_* macros). -If the immediate-1 tag equals TAG_IMMED1_IMMED2=2 then two more bits -are used to interpret the value type (TAG_IMMED2_* macros).

-

Examples of immediate: -small integers, local pids and ports, atoms, -empty list NIL. -An immediate value fits into one Word -and does not reference any memory.

-
-
-
-
Heap

Dynamically allocated block of Words used by a process. -Heap can be resized with help of either ERTS_REALLOC* macro or by -allocating a new fragment and moving data there using garbage collector. -Data is placed onto heap sequentially from its start.

-
-
-
-
Port

A special value which you receive when you call erlang:open_port. -It is hooked to a port driver (built-in or custom). You can send it commands -and receive messages from it, you can close it, link to it and monitor it -(monitoring added in v.19).

-

A port driver manages some resource, such as a file, a socket, a ZIP -archive etc. Ports provide your process with a stream of events from -some resource, and you can write commands and data to them as well.

-
-
-
-
Primary Tag

When a term value is encoded, several least-significant bits (currently -2 bits) are reserved to represent type of contained term.

-

Term tag can be: -a box (TAG_PRIMARY_BOXED=2), -a list (TAG_PRIMARY_LIST=1), -a header (TAG_PRIMARY_HEADER=0) -or an immediate (TAG_PRIMARY_IMMED1=3).

-
-
-
-
Reduction

Each instruction or a call has a cost, it uses imaginary units called -reductions, where 1 reduction is approximately one function call. -Cost of other calls and operations is derived from this approximately.

-
-
-
-
Registers

An array of Words used to pass arguments in a function -call. When a recursive call is made, affected registers are also saved onto -the stack.

-
-
-
-
Roots

During garbage collection, the roots are all known to be live values, -they are collected from:

-
    -
  • the stack

  • -
  • the live registers

  • -
  • the process dictionary

  • -
  • the message queue

  • -
  • the group leader and the exception reason fields.

  • -
-

Anything that can be traced by following references from the roots is -considered to be reachable data. -This data is moved to the new heap. -Previous heap is discarded, because no data can be reached on it anymore.

-
-
-
-
Scheduler

Scheduler is a loop which runs on a fixed CPU core and it either fetches -and executes next instruction based on instruction pointer in current -process, or takes next process in the queue. As soon as a process has been -running for certain number of reductions (say 2000 -but number may change), it is scheduled out and put to sleep, and next -process takes its place and continues running where it left off. This allows -some sort of fair scheduling where everyone is guaranteed a slice of time, -no matter how busy some processes are.

-
-
Slot

A special tagged value which points at a register, float register, or a -stack slot. It is used internally by instructions and never appears in -Erlang programs as data.

-
-
-
-
Stack

A section of young heap of a process, which is used as temporary storage and -return stack by a process. A new process creates a stack which has zero size -and begins at the heap_end. -Stack grows back (decrementing memory address) until it meets -heap write position (heap_top). Then heap is considered full -and garbage collection will trigger.

-

Data on stack is grouped into Stack Frames.

-
-
-
-
Stack Frame

Functions can create a stack frame by pushing a CP value -and reserving several extra words on stack. Sometimes, when code throws an -exception, VM scans the stack to build a stacktrace and uses these CP values -as markers.

-

Each frame corresponds to a function call. A frame always begins with a -CP value which marks a return address can be used to find a frame boundary. -Rest of the frame is used to store any temporary variables and register -values between the calls.

-
-
-
-
Term

A term is any value in Erlang. Internally a term is a Word -with few least-significant bits reserved (2 to 6 bits depending on the value) -which define its type. Remaining bits either contain the value itself (for -immediate values) or a pointer to data on heap -(box values).

-
-
-
-
Terminating a Process

An exit or kill signal is sent to a process which works similar to an -exception. If process was able to catch an exit signal (trap_exit), then -nothing else happens.

-

Process that is going to die will free its memory, trigger all monitors -and links, leave the process queue and get unregistered from the process -registry.

-
-
-
-
THE_NON_VALUE

Internal value used by emulator, you will never be able to see it from Erlang. -It marks exception or special type of return value from BIF functions, also -it used to mark memory during garbage collection.

-

Depending on whether DEBUG macro is set and HiPE is enabled, -THE_NON_VALUE takes value of primary float header -(6 least-significant bits are 0110-00) with remaining bits set -to either all 0 or all 1. Or it is all zero-bits Word -(marking a zero arity tuple on Heap), which never can appear in a register, -thus marking it useful to be the special return value.

-
-
-
-
Word

Machine-dependent register-sized unsigned integer. This will have width of -32 bits on 32-bit architecture, and 64 on a 64-bit architecture. -In BEAM source code Word can be unsigned (UWord) or signed (SWord).

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-atoms.html b/docs/build/html/eli5-atoms.html deleted file mode 100644 index b36512a..0000000 --- a/docs/build/html/eli5-atoms.html +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - - Atoms ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Atoms ELI5

-_images/eli5-atom-tab.png -

Atom table is a global table which maps internal atom value (an integer) to a -string. There is also the opposite lookup table, which maps a string to an -internal value. Atom table has a hard size limit: 1048576. If it is ever -reached, the node will crash — this is why creating atoms in runtime is a -risky idea. Atom table size is set with +t flag for erl.

-

Atom is a symbol which does not change its value in runtime. When a new atom -is created, it gets a unique value for this node used as its value. -Internally atoms are just integer values referring to atom table. This is why -atoms operations are cheap.

-

BEAM loader routine reads atom values and looks them up in atom table. It -replaces atom names with their integer values, tagged as Atom -immediate. Henceforth the code manipulates immediate integer -values instead of names.

-

These internal values cannot leave the node (over the network or on disk) as -integers. This is because another node will have different numeric values -for atoms. Thus when leaving the node atoms are always converted to strings. -This affects BEAM files, external pids, external ports, atoms in Mnesia/DETS -and so on. This is the reason why sometimes developers prefer short atom names -for database field names — they will appear as strings in database data.

-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-bif-nif.html b/docs/build/html/eli5-bif-nif.html deleted file mode 100644 index f53e65f..0000000 --- a/docs/build/html/eli5-bif-nif.html +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - BIF and NIF functions ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

BIF and NIF functions ELI5

-
-

BIF Functions

-

Unless you work on OTP C source, you will never have to create own BIF function. -If you want to implement own native function for your project, -check out the next section about NIFs!

-

In the standard Erlang library most functions are implemented in Erlang. But -many features of the virtual machine and internal functions are impossible -to reach from pure Erlang. So they were written in C and are exported as BIF -— built-in functions. -BIFs are used in standard Erlang libraries and are statically built into -emulator during compile-time.

-

When reading Erlang standard library modules you often can see functions -with a single call to erlang:nif_error(...). -These are BIF stubs. -BEAM loader finds the native library and replaces these stubs with references -to native implementation in C. -You can also create BIF or NIF functions in other languages like C++ or Rust. -You should also register a new BIF in a special file, called bif.tab which -connects module:function name and the BIF when you build the emulator.

-

If you are curious, search for some function in OTP C source, for example: -lists_reverse_2 in erl_bif_lists.c. -A BIF function takes Process pointer and a pointer to registers, where it -can access as many Term (Eterm C type) registers as it needs. -A BIF must return a Term value or a THE_NON_VALUE -for special execution control features like traps, yields and exceptions.

-
-
-

NIF Functions

-

NIFs are a different way of making native functions, more suited for separate -compilation and to be loaded by user modules. -NIF interface and type system is also simplified — they abstract away and -hide many internal types, bits and fields of the emulator.

-

There is a good NIF tutorial in standard documentation and about a million -of NIF functions written by users and available in various Github projects.

-

Still even if it is simplified, one must be careful! A badly written NIF is -able to tip over the whole virtual machine or hog the resources and slow the -execution to a grind.

-
-

See also

-

BEAM Wisdoms: Interfacing Erlang with the Outer World for a list of NIF, interoperability -libraries, and port drivers for different programming languages.

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-efficiency-memory-perf.html b/docs/build/html/eli5-efficiency-memory-perf.html deleted file mode 100644 index 730328f..0000000 --- a/docs/build/html/eli5-efficiency-memory-perf.html +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - - - Memory Performance ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Memory Performance ELI5

-
-

Data Locality

-

In recent decades performance of computer memory did not grow as fast as -performance of CPUs has improved. -To offset impact of memory low performance several levels of CPU caches -are used which store recently accessed data closer to the CPU. -When you access any byte in memory, larger blocks of data are loaded to -cache or flushed at once (these are called cache rows).

-

The general rule of gaining best performance is to store relevant data close -together. From Erlang point of view it means also creating all -relevant data together which will place them together in process heap.

-

If the data is large, it should be grouped to allow sequential -processing. And the cost of memory access can be so high that some values -are cheaper to calculate instead of loading them from some cold -(uncached and rarely read) memory location.

-

Hot (often accessed) memory is a welcome place to store -your variables and working data, for C and C++ programs this is program stack -and for C++ this would be fields of your current class object, because it -always was accessed recently. It is harder to say which memory is hot for -Erlang, as we don’t control much of its behaviour, but there are some tricks -that affect data placement on heap and how it will perform after.

-
-
-

Cache Miss

-

A “cache miss” is a special situation which occurs when CPU accesses some data -and the data wasn’t in cache. A cache row (64 bytes) of data are requested -from main RAM. CPU is forced to wait for the data. If possible the CPU -will try and do some other work by reordering machine instructions, but -this does not always happen and just assume that it is waiting for the data.

-

Typical cost of a cache miss is ~100 CPU cycles. This is a lot of time, -many simpler values can be calculated without accessing memory and save -significant time with not reading the main RAM.

-

Even worse if your program runs on a large production server with hundreds -GB of memory, then most likely it uses non-uniform memory architecture (NUMA) -and the memory is divided between CPU cores. The cost of a cache miss on -such machines is even higher, especially if accessing part of RAM “owned” -by another CPU core. Erlang and BEAM VM is aware about this and does its -best to preserve the core locality of used memory.

-

So when you are optimizing your awesome algorithm which now is perfect and -doesn’t run any better no matter the effort, have a look at how it works with -memory. The reward for using memory efficiently is your code running -much faster!

-
-
-

Data Types

-
-

Note

-

Major garbage collection of a process will order its data in -memory by placing all list cells together, and tuple values will follow the -tuple in memory. This is very good for memory locality although moving all -this data might be super expensive.

-
-
-

Note

-

For memory-heavy operations -consider owning the data in the process which does the work instead of -requesting it from ETS or database while doing the work. -Keeping at most one memory-intensive process per available CPU core is -welcome, let the BEAM VM do the rest for you. -Also consider doing a major GC on your worker process before running a -big calculation (see erlang:garbage_collect).

-
-
-

Immediate Values

-

These values are smallest, they always fit into a CPU register and there is -not much you can do to make them work any faster. They are atoms, -small integers, local pids etc.

-
-
-

Lists

-

Lists in BEAM are represented as single-linked lists of value pairs (cells). -If a list is created in a complex algorithm slowly, its cells might be sparsely -distributed in memory interleaved with other data created at the same time. -This may lead to inefficient CPU cache usage. A way to offset this -is to create your large working lists in tight loops while not creating other -unnecessary data. This will place list cells tightly together with their values. -When it is not possible, you can always invoke a major garbage collection and -have everything sorted for you (at a cost).

-
-
-

Tuples

-

As tuples are stored as arrays, they are cache friendly. If a tuple contains -other data structures such as lists or tuples, the data will be stored somewhere -else on heap and the tuple will only contain pointers to it. -Even better if a major garbage collection was performed recently which sorts -your data in memory and groups it together.

-
-
-

Floats

-

Even if a floating point value fits into a CPU register and has same size as -an immediate value (small integer or atom etc), actually they are -stored on-heap with a header word marking their presence. This makes floats -consume double the memory and each access to them will dereference a pointer -to a possibly cold memory location where no other floats are stored.

-

Best you can do here is to create your arrays or lists of floating point values -in tight loop together, which will maximize how many floats are cached when -a single cache row of 64 bytes is loaded. -Or run a major GC to group them automatically.

-
-
-

ETS Tables

-

There is not much you can do to affect ETS table memory behaviour, so here -you are at the mercy of BEAM VM developers.

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-efficiency.html b/docs/build/html/eli5-efficiency.html deleted file mode 100644 index 61b44a4..0000000 --- a/docs/build/html/eli5-efficiency.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - Efficiency ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Efficiency ELI5

-
-

Data copying

-

Here are general rules regarding data copying and performance.

-
    -
  • Data is stored in process heap most of the time.

  • -
  • As long as data is moved inside the owning process, it is not copied, -only a pointer is passed.

  • -
  • If the data ever leaves the process, a message for example, it will be -copied to its new owner.

  • -
  • If the data is moved to or from ETS, it behaves similarly, it will be -copied (ETS has own heap separate from any process).

  • -
  • If the data is moved between a process and a port, it will be copied -(ports behave similar to processes, and own resources in a similar way).

  • -
  • Large binaries >64 bytes are never copied, instead they are reference -counted and reference is shared between processes. This is why you want to -GC periodically all processes which have touched a large binary, otherwise it -may take a long time before the binary is freed.

  • -
-
-
-

Literals (Constants)

-

All Erlang values in your module (literals) are saved in the module file and -then loaded when your module loads. -These values are stored in special memory area called constant pool and later -when you reload your code the garbage collector will move old constants to your -process heap (see note below, this has changed in OTP 20.0).

-

Accessing a literal value of any size is cheap. You can use this trick to define -large constant structures, lookup tuples with cheap element access, -store large binaries in code etc.

-
-

Note

-

In Erlang versions prior to 20.0 a constant value will be copied when -crossing process boundary (explained above in “Data Copying”). This has changed -in version 20.0 -(OTP-13529 in Release Notes )

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-etf.html b/docs/build/html/eli5-etf.html deleted file mode 100644 index 227ec6b..0000000 --- a/docs/build/html/eli5-etf.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - External Term Format ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

External Term Format ELI5

-

To communicate with the outer world and other Erlang nodes, also to save things -on disk, Erlang uses special encoding — External Term Format.

-

The main requirements to the format:

-
    -
  • Easy for human and machine to see an encoded term and what it is. An external -term always starts with byte 131 (0x83).

  • -
  • Compact with optional compression. -A tag 131 (0x83), 80 (0x50), U32/big length marks a compressed term.

  • -
  • Cross-platform, all integers are encoded as -big endian (from most -significant bytes to least), -floats use big endian -IEEE encoding, -text uses UTF-8 or ISO-8859-1 (ASCII superset).

  • -
-

To encode a term see erlang:term_to_binary and the opposite operation is -erlang:binary_to_term.

-

Decoding a crafted binary allows us to construct terms which are impossible to -make with standard library functions, such as non-existing ports and pids.

-

Usually atoms are encoded as strings. -But in the distributed mode (over the network) to further reduce the protocol -size a distribution header can be added. -It contains a table of atom names which are included in the encoded message. -Atoms in the message are placed in this table and their occurences are replaced -with indexes.

-

It is impossible to encode internal VM value types which never appear in -Erlang programs, such as THE_NON_VALUE, references to registers, CP -(continuation pointer) etc.

-
-

See also

-

External Term Format -documentation.

-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-io.html b/docs/build/html/eli5-io.html deleted file mode 100644 index 2b7f754..0000000 --- a/docs/build/html/eli5-io.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - Input/Output and Ports ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Input/Output and Ports ELI5

-

A main reason why people run computer programs is to have side effects. A pure -program without side effects will consume watts of power, warm up -your room and do nothing else. To connect programs to the outer world, there are -input and output features in every language. For example: reading and writing -files, accessing hardware ports or interacting with OS drivers, drawing on -screen and so on.

-

Erlang does this with ports, driven by small C modules, called port drivers. -Some drivers are built into Erlang, and some you will have to create yourself, -or pay someone to do it for you. For many port problems there may already be a -solution on Github (Unix pipes as example).

-

When you connect to a resource to start using it, you receive a -Port value back. It behaves similar to a process: it consumes -CPU time to process your data, you can send messages to it, also it can send -messages back to you. You can link to a port or monitor a port (monitors added -since v.19).

-
-

Port Tasks

-

Each port similar to processes gets assigned to one scheduler. -Every scheduler on each CPU core will periodically check assigned ports and -perform polling and maintenance (this is called running port tasks). -This gives CPU time to port drivers to perform actual IO and deliver results -to the processes who are waiting.

-

To improve this situation and to separate port tasks from schedulers, so that -they don’t affect main code, Async Threads have been invented. -VM creates extra CPU threads which have only one primary goal — -to serve IO tasks.

-

This can be controlled with +A<number> command line flag. -Default value is 10 async threads.

-
-
-

Port Driver

-

A C module can be registered by name as a port driver. You can specify, which -driver to invoke, when opening a port. -Port driver performs several basic commands as opening, closing a port, sending -data to it or reading from it. Socket interface, OS process spawning – for -example they are implemented as port drivers.

-
-

See also

-

Technical details IO in Erlang

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-process-heap.html b/docs/build/html/eli5-process-heap.html deleted file mode 100644 index 6db55ec..0000000 --- a/docs/build/html/eli5-process-heap.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - - - Process Heaps ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Process Heaps ELI5

-

Everything in Erlang is a Term.

-

A heap of the process is an array of Terms. A stack is -another array of Terms. Stack is located inside the heap. -Registers — are array of Terms too! -Things on the heap are mostly arrays of Terms, but tagged -with header tag (see Data Types Memory Layout).

-
-

Heap Carriers

-

Allocation in Erlang happens inside so called “carriers”. They look like -“zone memory”, used by games — big chunks of system heap pre-allocated -beforehand. Inside carriers the real allocation is happening. For simplicity -you can imagine simple malloc/realloc, that’s how its done.

-

This complication is done to fight memory fragmentation and is not important -for the understanding. -You can see erts/emulator/beam/erl_*alloc.c (many those files, one per -strategy of allocation). Emulator has command line flags, which control -allocation strategies (see http://erlang.org/doc/man/erts_alloc.html flags -section).

-
-
-

Allocating Inside Heap

-

When a process needs some memory, its heap_top is incremented and memory -under it is ready to use. Some activities may want to allocate on other -process’ heaps, for example sending a message will perform a copy to the -receiving process.

-

No bookkeeping is happening inside a process heap. -There is no tracking which word belongs where, but it is possible to know -what is stored in each memory cell by looking at the tag bits.

-
-
-

Garbage Collection

-

Garbage collector traces known live values from registers and stack and saves -them, then drops everything else.

-

When a heap comes to its capacity threshold (something like 75%), the process -triggers garbage collection. A new bigger heap may be allocated. -Scanning generational garbage collection algorithm runs on the heap. -The algorithm takes the “roots” and moves them to the -new heap. -Then it scans the remaining parts of source heap -and extracts more values, referred by the roots. After the scanning, source -heap contains only dead values and algorithm drops it.

-

“Scanning” means, that garbage collector follows the data -roots from the start to the end, parsing everything it meets. -“Generational” means, that algorithm splits data into young and old generation, -assuming that data often dies young, and old data is less likely to be freed. -Also the algorithm remembers the old position (mature), where the previous -scanning has finished. -Any data below it is guaranteed to have not updated since the last scan. -This trick reduces amount of scanning and speeds up the algorithm.

-

In reality the picture is a bit more complicated. There can be one or two -heaps with different placement logic applied to them.

-

Having garbage collector run per process heap allows Erlang to keep -collection latency low. Also it doesn’t pause or affect other processes on -other schedulers. This is not a simple topic, but theory is all here: -http://gchandbook.org/

-
-

See also

-

BEAM Wisdoms: In depth: Process Heap Layout.

-

BEAM Wisdoms: In depth: Data Types Memory Layout.

-

Garbage Collector in Erlang 19

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-processes.html b/docs/build/html/eli5-processes.html deleted file mode 100644 index 693721c..0000000 --- a/docs/build/html/eli5-processes.html +++ /dev/null @@ -1,275 +0,0 @@ - - - - - - - - Processes ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Processes ELI5

-

This is a high level overview for how processes are made and how they work.

-
-

General overview

-

A process is a simple C structure, which contains -a heap, -a stack, -registers, -and an instruction pointer. Also, there are some extra fields for exception -handling, tracing etc. A new process is this structure created with a minimal -size heap.

-
-

Spawning a new Process (Actor)

-

When you call spawn or spawn_link, the VM allocates a small piece of memory -with a new process header (approx 200-300 bytes) and the {heap with the stack} -(they live together and take about 1kb initially). A new process is granted a -new unique PID, which won’t repeat for a fair amount of days or months after its -death, and is registered in a process lookup table.

-

There are no messages involved in process creation only a couple of memory -allocations.

-

So the newly created process is not known to any scheduler yet. It is then -placed into a run queue for its priority (99.99% of processes run as normal), -where one of schedulers is able to pick it up and begin executing. Newer -versions of Erlang have run queues one per scheduler, but the principle is -the same.

-
-
-

Stack

-_images/eli5-process-stack.png -

Stack is an array of memory on the young heap used as return -stack and temporary storage for variables. Stack begins at the end of the heap -and grows back (downwards). -The data on stack is grouped into Stack Frames.

-

When a function needs some temporary memory, it allocates several words on the -stack and marks the 0-th word with special CP value. Later it can be used -as return address and to find out where next stack frame begins. This temporary -memory is also used to preserve registers during recursive calls (thus growing -the stack).

-

Tail-recursive calls avoid keeping this temporary data or free it before -recursing. They pass arguments in a smarter way that does not require saving -them on stack and does not grow it.

-
-
-

Execution

-

Every new process is assigned to a Scheduler. -Scheduler picks one process from the queue and takes its instruction pointer. -Then scheduler executes one instruction and loops. After certain amount of work -done (reductions) scheduler will place the current -process to the back of the queue and select another one. This allows some sort -of fair scheduling: every process gets CPU time no matter how busy were other -processes in the queue.

-
-
-

Killing and Exiting

-

Killing a process is like sending it an exit exception. The process wakes up -from sleep, receives CPU time, and discovers an exception. Then it will either -terminate or catch the exception and process it like -a regular value. An unconditional kill signal works similarly except that -Erlang code cannot catch it.

-
-
-
-

Scheduling and Load balancing

-_images/eli5-process-sched.png -

By default BEAM VM starts one Erlang scheduler per CPU core. Processes get a -scheduler assigned to them in some manner (for simplicity you can say it is -random). You can configure schedulers using flags +S and +SP. Schedulers -can be bound to cores in different ways (+sbt flag).

-

There are 4 process priorities: low, normal, high and max. -Process at max always runs first making everything else wait. -High runs approximately 8 times much often than normal (the number -is implementation dependent). -Low runs when there is no other work to do.

-

At runtime schedulers will compare their process queue with the other (namely -the previous one in scheduler array). If the other queue is longer, the -scheduler will steal one or more processes from it. This is the default -behaviour which can be changed. The balancing strategy and can be configured -with VM flags +S and +scl. You could want to use as few cores as -possible to let other CPU cores sleep and save energy. Or you could prefer -equal spread of processes to cut the latency.

-

Stealing is as easy as moving a pointer from one array to another. This may -affect cache locality when an active process -jumps CPU core.

-
-
-

Process Registry

-

A global process table maps process identifier (pid) to a Process structure. -To know a pid of a process, refer to its Process.common.id field. A process -is uniquely identified by its local pid. Remote pids contain more information: -a node name and internal node id. Remote pids have to be resolved on the node -which owns them.

-

Another global table (process registry) maps names to pid. You can reach it -from Erlang by using erlang:register, erlang:unregister and -erlang:whereis BIFs.

-
-
-

Message Queues

-_images/eli5-process-mqueue.png -

Messages are stored on the heap or in heap fragments, and are chained together -using a single linked list. Message queue is a C structure which belongs in -Process struct and it contains Terms sent to the process. -Boxed data for larger or nested terms is located on the heap. -A pointer to position in the queue exists, and it is advanced with BEAM -opcodes which scan the mailbox. -When scan pointer reaches the end of the mailbox, the process is put to -receive sleep. -The pointer is reset to the beginning of the queue only if a message was matched. -This is why selective receive on large mailbox queues is slow.

-
-

Sending a Message

-

Sending a message to a process is simple — this is how VM does it:

-
    -
  1. Lock the process mailbox (or don’t, if running on a single core).

  2. -
  3. Copy message to destination process heap.

  4. -
  5. Add the resulting term to process mailbox.

  6. -
  7. Unlock the mailbox.

  8. -
  9. If the process was sleeping in a receive, it would return back to -scheduling queue and wake up when possible.

  10. -
-

A process waiting for a message (in receive operator) is never queued for -execution until a message arrives. This is why millions of idle processes can -exist on a single machine without it breaking a sweat.

-
-
-
-

Traps

-

Traps are a feature of the VM loop which allow to interrupt long running BIFs -temporarily. State is saved in temporary memory block and control returns to -the scheduler. Process sets its instruction pointer to the special trap -instruction and the BIF returns.

-

During the trap the current process is placed to the back of the process queue -which allows other processes to run. When the time comes again, the VM loop -encounters the trap instruction and jumps back to the long running BIF.

-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-property-based.html b/docs/build/html/eli5-property-based.html deleted file mode 100644 index 0bd7e33..0000000 --- a/docs/build/html/eli5-property-based.html +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - Property Based Testing ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Property Based Testing ELI5

-

Assume you know about regular unit testing, possibly you’ve heard about the -common test. -There is another way to check your system, different from ordinary testing -methods. It is called property based testing.

-

To make a test one should define types and ranges for the input data, -which the system will take under the test. -Definition of input data looks like a tuple with type and range argument -descriptions. They are data, and you build this data before the test.

-

Then the test engine will call your code with random combinations of defined -input data. -Test engine tries to observe if the system under test still shows the -defined properties.

-

If at some moment the required property is not observed, test will stop and -engine will try to shrink the input. -This is an attempt to find simplest input data which still breaks the test. -Test engine will try to reduce complexity for as many parameters as possible.

-
-

See also

-

Libraries which offer property based testing: -PropEr and -Quviq QuickCheck (commercial) -(note that QuickCheck also exists for other languages!)

-
-
-

Example

-

Imagine that your boss asked you to write a fizz_buzz function. -From the documentation it is clear, that a good fizz_buzz takes an integer -argument between 1 and 100. -Also it will return fizz for arguments that are divisible by 3, -buzz for arguments that are divisible by 5, -fizbuzz for arguments divisible by both 3 and 5.

-

So the input range: it is an integer between 1 and 100.

-

And 3 properties we want to observe:

-
    -
  1. When X rem 15 =:= 0 we want to see fizzbuzz as return value.

  2. -
  3. When X rem 3 =:= 0 we want to see fizz.

  4. -
  5. When X rem 5 =:= 0 we want to see buzz.

  6. -
-
-

Note

-

Please consult actual documentation for the selected test library. -The syntax of the library calls differs.

-
-

Test engine will apply random combinations of values from the defined input range. -Test engine will ensure that all 3 properties are observed during the run.

-
-

Note

-

You can test any black box system this way, without knowing its internals. -The system under test can be a C program or even a real piece of hardware!

-

It is also possible to run parallel tests -(ensure that a parallel system doesn’t break when things happen in parallel) -and state machine tests -(ensure that a state machine doesn’t break under the random input).

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-tracing.html b/docs/build/html/eli5-tracing.html deleted file mode 100644 index 71ef0b9..0000000 --- a/docs/build/html/eli5-tracing.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - Tracing ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Tracing ELI5

-

How does Erlang VM perform tracing of calls, messages, processes spawning and -passing away?

-

Tracing is a VM mode, that can be toggled on and off, and starts producing a -stream of events. -A call to dbg:tracer() starts a process which will receive this stream. -You can create your own tracer with its own state and feed events to it.

-

Tracing is able to produce overwhelming amount of irrelevant data. -To limit this data a trace filter is applied with dbg:tp/4 (and similar).

-

When everything is prepared: a tracer and a filter, it is time to open the -valve. A call to dbg:p/2 (and similar) sets the trace target (a process, -a port, spawn and exit events, everything, and so on). -It will start sending everything that matches trace target and the filter -you’ve set to the tracer process.

-
-

Inner Workings of the Tracing

-

Simple things, like process lifetime events or messages have tracer checks -in place everywhere in the virtual machine’s C code. If tracing is enabled, -then a message is sent to the current tracer.

-

Tracing calls and returns from BIF functions is a bit more complex. Because BIF -are not real Erlang code, they have to be wrapped in a tracing code somehow. -This is done by replacing BIF table with BIF entry function addresses with -another table. -Each entry in this new table is a simple call to erts_bif_trace with a -function name and arguments. -This function performs the real call and sends trace messages.

-

At certain moments, when we want to trace a BIF trapping and returning to -execution later, another trick is used. -Address to a special BEAM opcode is pushed onto the stack before the BIF is -finished. This allows to catch up when trap continues execution and will send -the trace event correctly when the BIF was finished.

-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-types.html b/docs/build/html/eli5-types.html deleted file mode 100644 index 0e4cc1f..0000000 --- a/docs/build/html/eli5-types.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - Types ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Types ELI5

-

Erlang is dynamically typed language. It means that any variable, -field or function argument can contain any allowed value.

-
-

Type Specs

-

There is the type description language, which you can use to -describe what YOU think your functions should take and return. -These type specs are optional and the compiler will run your program like -nothing happened even if a type violation exists. -To ensure that your type specs do not contradict each other, there is -another tool called Dialyzer.

-

A type spec is a directive in source ERL file, which looks like

-
-spec func_name(Arg :: integer(), _, Y :: any()) -> float().
-
-
-

Type specs are not code, they neither run nor prevent your program from compiling.

-
-

See also

-

You can read more about specifying types of your program in -Typespec Reference Manual -and other existing books, such as -Learn You Some Erlang

-
-
-
-

Dialyzer

-

Dialyzer takes compiled BEAM or ERL source files as input, then -tries to guess types (type inference).

-
-

How This Works

-

Say you have written a function, f which takes one argument X and -returns something. -Dialyzer first does a general assumption that f is a fun(), which -takes any value (X :: any()) and returns whatever (any()). -This is what Dialyzer guesses initially:

-
-spec f(X :: any()) -> any().
-
-
-

Any() is the widest type possible which covers any value. -Then Dialyzer analyzes usage of this function and its code and -tries to reduce argument and return types to more narrow -specific set of types.

-

For example, if Dialyzer discovers that the only two places -which call your function f pass an integer or an atom -argument, then X’s type is reduced to integer()|atom() -(a set of two types). This is what Dialyzer may possibly calculate:

-
-spec f(X :: integer() | atom()) -> any().
-
-
-

If Dialyzer finds a contradiction, i.e. some types collapse to an empty type -(none()) or incompatible types are found, Dialyzer reports an error. -These errors may look confusing, but they often (always?) point to an -existing problem in the code.

-
-
-
-

Typer

-

Typer is another optional tool, found in your OTP distribution. -Using same algorithm as Dialyzer, it infers the types for a given module and -prints them. You can take them and insert into your program for future use -or to better document a large legacy project.

-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/eli5-vm.html b/docs/build/html/eli5-vm.html deleted file mode 100644 index f900477..0000000 --- a/docs/build/html/eli5-vm.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - BEAM VM ELI5 — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

BEAM VM ELI5

-

BEAM got its name from Bogdan/Björn Erlang Abstract machine. This is register -VM, but it also has a stack.

-
-

Registers and Calls

-

Being a register VM means that stack is not used to pass arguments -between calls, but registers are. They are not same registers as one would -expect to see in a CPU architecture, but rather just an array of -Term values. There are 1024 registers but functions of such -arity are rare, so usually VM only uses first 3 to 10 registers.

-

For example, when a call to a function of arity 3 is made: registers x0, x1, -and x2 are set to function arguments. If we ever need to make a recursive -call, we will have to overwrite registers and lose the original values in -them. In this situation, we will need to save old values on the stack. There -is no dynamic stack allocation other than stack frame, determined by the -compiler.

-

Each process has own set of registers.

-
-
-

Instructions

-

BEAM instruction set contains approximately 158 basic instructions, most of them -can be visible if you dump assembly by calling erlc -S yourfile.erl. Each -instruction has 0 or more arguments. Different tricks are used to encode -arguments in a portable and compact way. For example locations in code (so called -labels) are encoded by their index, and code loader later translates them to -memory addresses.

-

During BEAM code loading, some combinations of opcodes are replaced with a -faster opcode. This is optimisation trick called superinstruction. -For each opcode, there is a piece of C code in beam_emu.c which has a -C label. An array of C labels is stored at the end of the same VM loop routine -and is used as the lookup table.

-
-

See also

-

BEAM Wisdoms: In depth: BEAM File Format.

-

BEAM Wisdoms: In depth: BEAM Instruction Codes.

-
-
-
-

Threaded VM Loop

-

VM emulator loop in emulator/beam/beam_emu.s contains a lot of small -pieces of code, each having a label and handling one BEAM instruction. -They all belong to one very long function. -A table of labels is stored in the same function which is used as lookup table.

-

After the loading opcodes are replaced with such label addresses, followed by -arguments. For example, for opcode #1, an element with index 1 from labels -array is placed in the code memory.

-

This way it is easy to jump to a location in C code which handles next opcode. -Just read a void* pointer and do a goto *p. This feature is an -extension to C and C++ compilers. This type of VM loop is called -direct-threaded dispatch virtual machine loop.

-

Other types of VM loops are:

- -
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/genindex.html b/docs/build/html/genindex.html deleted file mode 100644 index 0be1e2d..0000000 --- a/docs/build/html/genindex.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - - Index — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/build/html/indepth-beam-file.html b/docs/build/html/indepth-beam-file.html deleted file mode 100644 index a87bea1..0000000 --- a/docs/build/html/indepth-beam-file.html +++ /dev/null @@ -1,476 +0,0 @@ - - - - - - - - BEAM File Format — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

BEAM File Format

-

BEAM file format is binary chunked file format, which contains multiple named -sections and has a header.

-
    -
  • Read 4 bytes of a .beam file: 'FOR1' -(marks IFF container).

  • -
  • Read U32/big length (so many more bytes must be available in the file)

  • -
  • Read 4 bytes 'BEAM' marking a BEAM file section of an IFF file.

  • -
-
-

Sections

-

Repeat until end of file:

-
    -
  • Read 4 bytes chunk name (for example can be: Atom, Code, CatT, FunT, ExpT, -LitT, StrT, ImpT, Line, Abst and possibly other chunks). -Do a sanity check: Must contain ASCII letters.

  • -
  • Read U32/big chunk length. This is the data size.

  • -
  • Perform chunk-dependent reading (see subsections below)

  • -
  • To find next chunk, pad the length to the multiple of ALIGN=4

    -
    file_pos += ALIGN * ((chunk_length + ALIGN - 1) / ALIGN);
    -
    -
    -
  • -
-
-

“Atom” and “AtU8” - Atoms Table

-

Both tables have same format and same limitations (256 bytes max length) -except that bytes in strings are treated either as latin1 or utf8.

-
    -
  • Read U32/big atoms count.

  • -
  • For each atom: read byte length, followed by characters

  • -
-

Atoms[0] is a module name from -module(M). attribute.

-
-
-

“Code” - Compiled Bytecode

-
    -
  • Read U32/big code version (must match emulator’s own version)

  • -
  • Read U32/big max opcode, U32/big label count, U32/big fun count

  • -
  • Read the code as a block. Format is discussed at BEAM Code Section Format.

  • -
-
-
-

“Abst” - Abstract Syntax Tree

-

Optional section which contains term_to_binary encoded AST tree.

-

A quick way to get Abst section (if it exists):

-
get_abst(Filename) ->
-    Chunks = beam_lib:all_chunks(Filename),
-    Abst = proplists:get_value("Abst", element(3, Chunks)),
-    binary_to_term(Abst).
-
-
-
-
-

“CatT” - Catch Table

-

Contains catch labels nicely lined up and marking try/catch blocks. -This section description is INCOMPLETE and UNTESTED.

-
    -
  • Read U32/big count

  • -
  • Read array of count U32/big offsets or labels (not sure).

  • -
-
-
-

“FunT” - Function/Lambda Table

-

Contains pointers to functions in the module.

-
    -
  • Read U32/big count

  • -
-

Until the count do:

-
    -
  • Read U32/big fun_atom_index (name by index from atom table), -U32/big arity, -U32/big offset (code position), -U32/big index, -U32/big nfree (frozen values for closures), -U32/big ouniq. Sanity check: fun_Atom_index must be in atom table range.

  • -
-
-
-

“ExpT” - Exports Table

-

Encodes exported functions and arity in the -export([]). attribute.

-
    -
  • Read U32/big count

  • -
-

Until the count do:

-
    -
  • Read U32/big export name atom index. Sanity check: atom table range.

  • -
  • Read U32/big arity, U32/big label (offset in BEAM code section, should -be translated into the loaded code offset).

  • -
-
-
-

“LitT” - Literals Table

-

Contains all the constants in file which are larger than 1 machine Word. -It is compressed using zip Deflate.

-
    -
  • Read U32/big uncompressed size (prepare output buffer of this size). Run -zip inflate (uncompress) on the data.

  • -
-

Inside the uncompressed data:

-
    -
  • Read U32/big value count

  • -
-

Until the value count do:

-
    -
  • Skip U32/big

  • -
  • Read byte ext term format marker (must be 131)

  • -
  • Read tag byte, … (follow the documentation)

  • -
-

Values are encoded using the external term format. -A better reference is in the -standard documentation

-
-
-

“ImpT” - Imports Table

-

Encodes functions from other modules invoked by the current module.

-
    -
  • Read U32/big count

  • -
-

Until the count do:

-
    -
  • Read U32/big module atom index, U32/big function atom index, U32/big arity

  • -
-
-
-

“LocT” - Local Functions

-

Essentially same as the export table format ExpT for local functions.

-
    -
  • Read U32/big count

  • -
-

Until the count do:

-
    -
  • Read U32/big func atom index, U32/big arity, U32/big location (label)

  • -
-
-
-

“Line” - Line Numbers Table

-

Encodes line numbers mapping to give better error reporting and code navigation -for the program user.

-
    -
  • Read U32/big version (must match emulator’s own version 0).

  • -
  • Skip U32/big flags

  • -
  • Read U32/big line_instr_count, U32/big num_line_refs, U32/big num_filenames

  • -
  • Store invalid location const as Word[] linerefs first element which points -at file #0, line 0.

  • -
  • Set fname_index = 0, this is index in file name table, empty now

  • -
-

Until the num_line_refs do:

-
    -
  • Parse term at read position (see BEAM Term format)

  • -
  • If the term is a small integer, push a pair of (fname_index, value) to -the linerefs array.

  • -
  • If the term is an atom, use its numeric value as new fname_index. Sanity -check: value must be under num_filenames.

  • -
-

Until the num_filenames do (fill the file names table):

-
    -
  • Read U16/big name size

  • -
  • Read string of bytes

  • -
  • Convert string to an atom and push into file names table

  • -
-
-
-

“StrT” - Strings Table

-

This is a huge binary with all concatenated strings from the Erlang parsed AST -(syntax tree). Everything {string, X} goes here. There are no size markers -or separators between strings, so opcodes that need these values (e.g. bs_put_string) -must provide an index and a string length to extract what they need out of this -chunk.

-

Consider compiler application in standard library, files: -beam_asm, beam_dict (record #asm{} field strings), and -beam_disasm.

-
-
-

“Attr” - Attributes

-

Contains two parts: a proplist of module attributes, encoded as External Term -Format, and a compiler info (options and version) encoded similarly.

-
-
-
-

BEAM Compact Term Encoding

-

BEAM file uses a special encoding to store simple terms in BEAM file in -a space-efficient way. -It is different from memory term layout, used by BEAM VM.

-

The idea is to stick as many type and value data into the 1st byte as possible:

-
7 6 5 4 3 | 2 1 0
-----------+------
-          | 0 0 0 — Literal
-          | 0 0 1 — Integer
-          | 0 1 0 — Atom
-          | 0 1 1 — X Register
-          | 1 0 0 — Y Register
-          | 1 0 1 — Label
-          | 1 1 0 — Character
-0 0 0 1 0 | 1 1 1 — Extended — Float
-0 0 1 0 0 | 1 1 1 — Extended — List
-0 0 1 1 0 | 1 1 1 — Extended — Floating point register
-0 1 0 0 0 | 1 1 1 — Extended — Allocation list
-0 1 0 1 0 | 1 1 1 — Extended — Literal
-
-
-
-

Note

-

In OTP 20 the Floats are encoded as literals, and every other extended code -is shifted, i.e. List becomes 1 (0b10111), Float register becomes 2 (0b100111), -alloc list becomes 3 (0b110111) and literal becomes 4 (0b1000111).

-
-

It uses first 3 bits of a first byte as a tag to specify the type of the -following value. -If the bits were all 1 (special value 7), then few more bits are used.

-

For values under 16 the value is placed entirely into bits 4-5-6-7 having bit -3 set to 0:

-
7 6 5 4 | 3 | 2 1 0
---------+---+------
-Value>> | 0 | Tag>>
-
-
-

For values under 16#800 (2048) bit 3 is set to 1, marks that 1 continuation -byte will be used and 3 most significant bits of the value will extend into -this byte’s bits 5-6-7:

-
7 6 5 | 4 3 | 2 1 0
-------+-----+------
-Value | 0 1 | Tag>>
-
-
-

Larger and negative values are first converted to bytes. -Then if the value takes 2..8 bytes, bits 3-4 will be set to 1, and bits -5-6-7 will contain the (Bytes-2) size for the value, which follows:

-
7  6  5 | 4 3 | 2 1 0
---------+-----+------
-Bytes-2 | 1 1 | Tag>>
-
-
-

If the following value is greater than 8 bytes, then all bits 3-4-5-6-7 -will be set to 1, followed by a nested encoded unsigned ?tag_u value -of (Bytes-9):8, and then the data:

-
7 6 5 4 3 | 2 1 0
-----------+------ Followed by nested encoded int (Size-9)
-1 1 1 1 1 | Tag>>
-
-
-
-

See also

-

Refer to beam_asm:encode/2 in the compiler application for -details about how this is encoded. Tag values are presented in this -section, but also can be found in compiler/src/beam_opcodes.hrl.

-
-
-

Base and Extended Tag

-

Let’s parse the value of tag:

-
    -
  • Read a byte and extract its least 3 bits. This is the base tag. -It can be Literal=0, Integer=1, Atom=2, XRegister=3, YRegister=4, Label=5, -Character=6, Extended=7.

  • -
  • If the base tag was Extended=7, then bits 4-5-6-7 PLUS 7 will become -the extended tag. It can have values -Float=8, List=9, FloatReg=10, AllocList=11, Literal=12.

  • -
-

A badly written and incomplete -Github example of reading signed word -routine used to read signed words later:

-

A badly written and incomplete -Github example of parsing a small integer: -(used to read SmallInt values later).

-
-
-

Reading the Value

-

This is the logic, as was decoded from source code of BEAM VM and Ling VM. -It looks at the bits in slightly different order.

-
    -
  • Look into the first byte read, bit 3:

    -
      -
    • Bit 3 is 1, so look into bit 4:

      -
      -
        -
      • -
        Bit is 1: Use remaining 3 bits of the byte as byte length

        (if under 7 - read N+2 bytes into signed words, -if the value is 7 - then length is larger than that and we -have to read length first – it follows as ?tag_u=0 -(Literal) nested unsigned value)

        -
        -
        -
      • -
      • Bit 4 is 0: use remaining 3 bits + 8 more bits of the following byte

      • -
      -
      -
    • -
    • Bit #3 = 0: Use remaining 4 bits

    • -
    -
  • -
-

Now how to parse an encoded term:

-
    -
  • Read a SmallInt, case tag of:

    -
      -
    • Tag=Integer: use the value (signed?)

    • -
    • Tag=Literal: use smallint value as index in LitT table.

    • -
    • Tag=Atom: use smallint value MINUS 1 as index in the atom table. -0 smallint means NIL [].

    • -
    • Tag=Label: use as label index, or 0 means invalid value.

    • -
    • Tag=XRegister, Tag=YRegister: use as register index.

    • -
    • Tag=Character (an Unicode symbol): use val as unsigned.

    • -
    • Tag=Extended List: contains pairs of terms. -Read smallint Size. Create tuple of Size, which will contain -Size/2 values. -For Size/2 do: -read and parse a term (case of value), -read a small int (label index), place them into the tuple.

    • -
    -
  • -
-
-
-
-

BEAM Code Section Format

-

Code section in BEAM file contains list of instructions and arguments. -To read an encoded term see BEAM Term format.

-
    -
  • Read a byte, this is opcode (R19 has 158 base opcodes). -Opcode is converted into a label address (for threaded interpreter) or -a pointer to handler function.

  • -
  • Query opcode table and get arity for this opcode.

  • -
  • Until arity: parse term and put it into the output one term or word at -a time. VM loop will read the opcode later and expect that arity -args will follow it.

  • -
  • If any of the parsed terms was a label value, remember its output position -to later revisit it and overwrite with actual label address in memory -(it is not known until code parsing is done).

  • -
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/indepth-beam-instructions.html b/docs/build/html/indepth-beam-instructions.html deleted file mode 100644 index 358e355..0000000 --- a/docs/build/html/indepth-beam-instructions.html +++ /dev/null @@ -1,523 +0,0 @@ - - - - - - - - BEAM Instruction Codes — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

BEAM Instruction Codes

-

BEAM file stores code in Code section, using 1 byte for opcode, and encoding -arguments one after one using compact term encoding. -Opcode table defines arity, or how many arguments each opcode can take.

-

The table is not complete, for details on remaining opcodes please refer to -LING VM opcode table or to the source -beam_emu.c. Also see the opcode rules table ops.tab, which defines -special opcodes and rules to to create superinstructions. -Superinstructions bundle several often used instructions into one and try to -optimize for specific argument types.

-

As of R19 there are 158 base opcodes and several hundreds of superinstructions.

-
-

Opcode Table

-

Search for “#N” to find opcode N.

-

Slots are special values marking stack cell or a register. They can be -used to point at the data source or move destination. There are several -values of secondary tag which denote them.

-
-

#2 func_info

-

Func_info is located at the beginning of every function, but execution -always begins at the next label. -If all function clauses have failed guard checks, VM will jump to this -instruction. -It raises function_clause error with appropriate line number.

-
-
-

#4 call

-

Spec: call Arity Label

-

Saves current IP to CP (return address) and jumps to the Label, -which usually is a function entry point.

-
-
-

#5 call_last

-

Spec: call_last Arity Label Deallocate

-

Deallocates Deallocate words on stack and does a tail recursive call (jump) -to the function at Label. -Does not update the CP register with a return -address, making return bypass current code location.

-
-
-

#6 call_only

-

Spec: call_only Arity Label

-

Performs tail recursive call of a function at Label. -Does not update the CP register with a return -address, making return bypass current code location.

-
-
-

#7 call_ext

-

Spec: call_ext Arity Destination::mfarity()

-

Performs call to an external Destination mfarity (a tuple {Mod, Fun, Arity}) -which can point to an exported function or a BIF. -Return address is saved in CP.

-
-
-

#8 call_ext_last

-

Spec: call_ext_last Arity Destination::mfarity() Deallocate

-

Deallocates Deallocate words from stack and performs a tail recursive -call to an external Destination mfarity (a tuple {Mod, Fun, Arity}) -which can point to an exported function or a BIF. -Does not update the CP register with a return -address, making return bypass current code location.

-
-
-

#9 bif0

-

Spec: bif0 ImportIndex Dst::mfarity() (note no fail label)

-

Looks up BIF with zero arguments by Dst mfarity (a tuple {Mod, Fun, Arity}) and calls it. -Cannot silently fail by jumping to a label and will always throw an exception.

-
-
-

#10 bif1 #11 bif2 #152 bif3

-

Spec: bif1 Fail::label() ImportIndex Arg1 Dst::mfarity()

-

Spec: bif2 Fail::label() ImportIndex Arg1 Arg2 Dst::mfarity()

-

Spec: bif3 Fail::label() ImportIndex Arg1 Arg2 Arg3 Dst::mfarity()

-

Looks up BIF with 1, 2 or 3 arguments by Dst mfarity (a tuple {Mod, Fun, Arity}) -and calls it. -If Fail label is valid (not 0?), VM will jump to the label on error, -otherwise will throw an exception.

-
-
-

#12 allocate #14 allocate_zero

-

Spec: allocate StackNeed Live

-

Spec: allocate_zero StackNeed Live

-

Allocates StackNeed words on the stack (a stack frame). -Live defines how many X registers are currently in use (for GC call). -Current CP value is saved on top of the stack. -Allocate_zero writes NIL to all new stack cells, while allocate may -or may not do this.

-
-
-

#13 allocate_heap #15 allocate_heap_zero

-

Spec: allocate_heap StackNeed HeapNeed Live

-

Spec: allocate_heap_zero StackNeed HeapNeed Live

-

Allocates StackNeed words on the stack and ensures that there are -HeapNeed available words on the heap. -Live defines how many X registers are currently in use (for GC call). -Current CP value is saved on top of the stack. -Allocate_heap_zero writes NIL to all new stack (possibly heap too?) cells, -while allocate_heap may or may not do this.

-
-
-

#16 test_heap

-

Spec: test_heap Need Live

-

Ensures there are at least Need words on the heap. If needed, GC is -performed using Live values from registers array.

-
-
-

#17 init

-

Spec: init Y

-

Clears Y+1-th stack word by writing NIL. Offset by one is there because -CP is also stored on stack but it is not considered an Y cell.

-
-
-

#18 deallocate

-

Spec: deallocate N

-

Restores CP from stack and deallocates N+1 words from stack (one extra for -the CP).

-
-
-

#19 return

-

Jumps to current value of CP register. Sets CP to 0.

-
-
-

#20 send

-

Sends value X[1] to the process specified by X[0]. X[1] becomes -the result of the operation (is moved to X[0]).

-
-
-

#21 remove_message

-

Unlinks current message from the message queue. Message is moved to X[0]. -Current means that there is a movable pointer to a message in the linked list.

-
-
-

#23 loop_rec

-

Spec: loop_rec Label Source

-

Picks up next message in the queue and places it into X[0]. If there is no -message, jumps to Label which points to a wait or wait_timeout -instruction.

-
-
-

#24 loop_rec_end

-

Spec: loop_rec_end Label

-

Advances message pointer to the next message, then jump to Label which -points to a loop_rec instruction.

-
-
-

#25 wait

-

Spec: wait Label

-

Jumps to the Label and immediately suspends the process (wait for event).

-
-
-

Comparisons

-

Spec: <opcode> Label Arg1 Arg2

-

Performs a comparison and jumps to Label if false.

-
    -
  • #39 is_lt - is less

  • -
  • #40 is_ge - is greater or equal

  • -
  • #41 is_eq - equal ==

  • -
  • #42 is_ne - not equal /=

  • -
  • #43 is_eq_exact - exactly equal =:=

  • -
  • #44 is_ne_exact - exactly not equal =/=

  • -
  • #58 test_arity - checks if Arg1 is a tuple of size Arg2

  • -
  • #115 is_function2 - checks if Arg1 is a fun of arity Arg2

  • -
-
-
-

Guards as Opcodes

-

Spec: <opcode> Label Arg

-

Some guards are implemented as opcodes. -Performs a check and jumps to Label if false.

-
    -
  • #45 is_integer - is small or bignum

  • -
  • #46 is_float

  • -
  • #47 is_number - is small or bignum or float

  • -
  • #48 is_atom

  • -
  • #49 is_pid

  • -
  • #50 is_reference

  • -
  • #51 is_port

  • -
  • #52 is_nil

  • -
  • #53 is_binary

  • -
  • #54 is_constant - possibly checks if term belongs to literal area of a module?

  • -
  • #55 is_list - term is a NIL or points to a cons cell

  • -
  • #56 is_nonempty_list - term points to a cons cell

  • -
  • #57 is_tuple

  • -
  • #77 is_function

  • -
  • #114 is_boolean

  • -
-
-
-

#59 select_val

-

Spec: select_val Arg FailLabel Destinations

-

Scans Destinations even elements (0, 2, 4…) and compares with Arg. -If match is found, jumps to the label in the next odd element (1, 3, 5…) -otherwise jumpts to FailLabel. -By “match” naive compare is meant.

-
-
-

#60 select_tuple_arity

-

Spec: select_tuple_arity Tuple FailLabel Destinations

-

Check the arity of the Tuple and jump to the corresponding Destination -label, if no arity matches, jump to FailLabel.

-
-
-

#61 jump

-

Spec: jump Address

-
-
-

#62 catch

-

Spec: catch Y Label

-

Saves a resumption address &CatchEnd in the local frame at position -Y. Increments the process catch counter. The instruction is followed by a -catch_end instruction. By followed we mean that the catch_end -instruction is put after corresponding Erlang expression that is protected -from errors by the catch.

-
-
-

#63 catch_end

-

Spec: catch_end Y

-

Clears a resumption address stored in the local frame at position Y. -Decrements the process catch counter. -This instruction is preceded by a matching catch instruction.

-
-
-

#64 move

-

Spec: move Src Dst

-

Moves value from the Src to the Dst.

-

Src can be a value or a slot. -Dst must be a slot.

-
-
-

#65 get_list

-

Spec: get_list Source Head Tail

-

Gets the head and tail of a list (splits its cons cell) from Source -and puts values into the registers Head and Tail.

-
-
-

#66 get_tuple_element

-

Spec get_tuple_element Source Element Destination::slot()

-

Gets Element-th item from the tuple denoted by Source and puts -it into the Destination slot.

-
-
-

#69 put_list

-

Spec: put_list H T Dst::slot()

-

Creates a cons cell with [H|T] and places the value into Dst.

-
-
-

#70 put_tuple #71 put

-

Spec put_tuple Arity Dst

-

This opcode is followed by Arity repeated put Value opcodes. -Creates an empty tuple of Arity and places pointer to it into Dst. -Then moves instruction pointer forward, while next opcode is put, -reads argument for every put and places it into the next tuple element. -Stops after Arity steps.

-
-
-

#72 badmatch

-

Produces an error.

-
-
-

#73 if_clause

-

Produces an error.

-
-
-

#74 case_clause

-

Produces an error.

-
-
-

#75 call_fun

-

Spec: call_fun Arity

-

Calls a fun or export. -Arguments are in X[0..Arity-1]. -Function object is in X[Arity]. -Return address is saved in CP.

-

Raises badarity if arity does not match the function object. -Raises badfun if object is not callable (not a fun or export).

-
-
-

#76 make_fun

-

Seems to be deprecated, so compiler always generates make_fun2.

-
-
-

#78 call_ext_only

-

Spec: call_ext_only Arity Destination::mfarity()

-

Performs a tail recursive call to a Destination mfarity (a tuple {Mod, Fun, Arity}) -which can point to an exported function or a BIF. -Does not update the CP register with a return -address, making return bypass current code location.

-
-
-

#89 bs_put_integer/5

-

Spec: bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s

-

An integer from src and having bitsize sz is appended to the current -writable binary (stored in the internal state) at the current bit offset -(stored in the state too).

-
-
-

#103 make_fun2

-

Spec: make_fun2 Lambda

-

Produces a callable fun object. Lambda should be resolved at load time -to a function entry. Creates a callable box object on the heap which points -to this fun object and also has space to store frozen values (Free variables).

-
-
-

#104 try/2

-

Spec try Yregister Label

-

Begins a guarded code section by writing a special crafted catch value into the -given Y register. The catch value points to the label in case of exception, where -a try_case instruction is located.

-
-
-

#105 try_end/1

-

Spec: try_end Yregister

-

Ends the guarded section by clearing the catch value on stack with a NIL.

-
-
-

#106 try_case/1

-

Begins investigation of an exception, also clears the catch value on stack. From -here if you need the exception to propagate, you have to raise it again.

-
-
-

#107 try_case_end/1

-
-
-

#108 raise/2

-

Spec: raise Stacktrace ExcValue

-

A legacy instruction which takes error type from the provided stacktrace -object and creates an exception with the exception value (second argument).

-
-
-

#109 bs_init2/6

-

Creates a new writable binary of requested size with some extra words, runs GC -if needed, then the binary is stored in the internal state. Following bs_put* -instructions will add to it. The write bit offset in the internal state is -also reset to 0.

-
-
-

#112 apply #113 apply_last

-

Spec apply Arity

-

Spec apply_last Arity Dealloc

-

Calls function at X[Arity+1] in module X[Arity] -with arguments X[0..Arity-1]. Module is an atom or a tuple. Function is an -atom.

-

Apply saves current instruction pointer into CP and performs a -call to the destination.

-

Apply_last cuts the stack by Dealloc words preserving the CP on top -of the stack, and then jumps to the destination.

-
-
-

#136 trim

-

Spec: trim N _Remaining

-

Drops N words on stack after saved CP, moving it N words up.

-
-
-
-

Binary Matching and Operations

-
-

#119 bs_get_binary2/7

-

Spec: bs_get_binary2 Fail MatchState Live Size Unit Dst

-

For current binary match position (started by bs_start_match*) extract -a sub-binary (a slice) and return it. Live is used for an occasional garbage -collection act if the memory is tight. Size:Unit determines how many bits -go into the result.

-
-
-

#166 bs_start_match3

-

Spec bs_start_match3 Fail Context Live Dst

-

This opcode was introduced in OTP 22 and replaces bs_start_match2.

-

Depending on whether the value in the Context is binary, or an existing match -state, creates a new match state if needed. The position from the match state is used -for binary matching step by step by the following bs_* opcodes.

-
-
-

#121 bs_test_tail2

-

Spec: bs_test_tail2 Fail, MatchState, N

-

Ensures that the match state has N bits remaining for processing. If this is -not true, the VM will jump to the Fail label.

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/indepth-data-sizes.html b/docs/build/html/indepth-data-sizes.html deleted file mode 100644 index 8ce98e7..0000000 --- a/docs/build/html/indepth-data-sizes.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - BEAM Internal data sizes — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

BEAM Internal data sizes

-
-

See also

-

Data sizes in the -Erlang Efficiency Guide <http://erlang.org/doc/efficiency_guide/advanced.html>

-
-

Each boxed term has size described below plus one word for term value -itself which you store somewhere else (be it on heap then you should count size -for this term too, or in register/on stack - then it will not consume heap -memory).

-

For specific bit positions and bit sizes please always refer to original beam -sources, file: erl_term.h

-
-

Immediate

-

All immediate values have size of one Word.

-

They are: local pid, local port, small integer, atom, NIL -(an empty list []) and catch (internal value). CP can -also be considered an immediate although it is a special value which only -appears on stack and never in registers or heap.

-
-
-

List

-

List value is a pointer to cons cell. Cons cell has size of two -Words (one for head, and another for tail). Cons cell can -link to next cons cell and so on, until tail becomes a non-list term (for improper -lists) or NIL (for proper lists).

-

Size of a list is 1 Word (for a pointer) and also on the heap -2*num_cells Words.

-
-
-

Boxed

-

Boxed value is a pointer to the heap or some other area and always takes 1 -Words. -A Box always points to a memory block which starts with a Header (below) -except during GC.

-
- -
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/indepth-heap-layout.html b/docs/build/html/indepth-heap-layout.html deleted file mode 100644 index b2c6c7c..0000000 --- a/docs/build/html/indepth-heap-layout.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - Process Heap Layout — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Process Heap Layout

-

An Erlang process has a young heap (where all new data is placed), old heap -(possibly this one does not exist, contains data which survived previous garbage -collection) and a stack, which is located inside young heap.

-

Also a process has access to read-only literal area, which belongs to one or more -of Erlang modules, it contains constant literals which are found in module code. -At some rare occasions (code upgrade or purge) literal area can be copied to -old heap by means of garbage-collection (see erts_garbage_collect_literals -in erl_gc.c).

-

A process has chain of Off-heap objects (so-called MSO – mark and sweep object -list). The head of the chain is a field in Process struct, and the chain -continues through the heap visiting Header objects such as -refc binaries and fun closures. During garbage collection this chain is followed -and actions can be taken (similar to C++ destructors) when an MSO object is going -to die – for example refc binaries have their refcount reduced and possibly -are freed. MSO objects are strictly sorted from new to old, by the order of their -creation on heap.

-
-

How Heap Grows

-

Additionally heap segments can exist (for situations, when heap is not enough, -but data must be allocated). Heap segments are consolidated before garbage -collection and merged onto heap.

-

Heap top (heap_top) marks current allocation position in heap. When more data -is needed, heap_top is advanced forward and data goes there.

-

Heap always grows forward from heap_start (see erl_process.h, Process -struct, fields heap, old_heap). Stack always grows backwards from -heap_end to heap_top, as soon as stack meets heap top, the young heap -is considered full and garbage collection is triggered.

-

Old heap does not contain a stack. Old heap can only grow during garbage -collection and its future size is precalculated.

-

To minimize memory fragmentation, heap sizes like a puzzle pieces are allocated -following Fibonacci sequence (starting from 12 and 38 Words) -for 23 total steps, after which (at about 1.3 million Words) -sequence continues by adding 20% to the previous value.

-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/indepth-io.html b/docs/build/html/indepth-io.html deleted file mode 100644 index 681c52b..0000000 --- a/docs/build/html/indepth-io.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - IO in Erlang — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

IO in Erlang

-
-

How a Driver Looks Like

-

A port driver is a C module with several functions defined (see ErlDrvEntry -in emulator/beam/erl_driver.h:

-
    -
  • Start/stop, finish, process exit/emergency close functions

  • -
  • IO events (async/input/output)

  • -
  • Timeout handler

  • -
  • Call function, which passes commands to the port

  • -
  • Control function, which changes options in the port

  • -
  • Flush function, which ensures that all data is written

  • -
-
-
-

Making a Port Driver

-

Define an erl_drv_entry variable (a struct) and fill it with pointers to -callback functions. -You will need to cover things such as starting your driver, -stopping it, opening a port, sending commands and receiving data, and few other.

- -

Load your port driver and register it in the system under a name -(add_driver_entry).

- -
-

Todo

-

this goes to indepth section

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/indepth-memory-layout.html b/docs/build/html/indepth-memory-layout.html deleted file mode 100644 index c36907d..0000000 --- a/docs/build/html/indepth-memory-layout.html +++ /dev/null @@ -1,311 +0,0 @@ - - - - - - - - Data Types Memory Layout — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Data Types Memory Layout

-

This describes data format on heap, as seen in C code or from debugger. -You will never be able to see this format from Erlang code.

-
-

Immediate values

-_images/memory-layout-immed.png -

Immediate types always occupy 1 Word. To know if you found -an immediate, its least-significant 2 bits will have value -TAG_PRIMARY_IMMED1=3.

-

To know which exactly immediate you’ve got, see the two following bits -(bit 2 and 3): -_TAG_IMMED1_PID=0, -_TAG_IMMED1_PORT=1, -_TAG_IMMED1_SMALL=3. -This leaves remaining Word-size minus 4 bits for the -actual value.

-

If the bits 2 and 3 contained _TAG_IMMED1_IMMED2=2 then two more bits -(bit 4 and 5) are taken and interpreted. -They can be -_TAG_IMMED2_ATOM=0, -_TAG_IMMED2_CATCH=1 -_TAG_IMMED2_NIL=3, -which leaves remaining Word-size minus 6 bits for the -actual value.

-

This also explains why max small integer range is 32-4=28: -2^27-1 + one bit sign, because small is an immediate-1 value. -And why max number of atoms can be 32-6=26 (2^26=32 million), because -atom is an immediate-2 value. -For compatibility reasons this limit also applies to 64-bit systems.

-
-
-

Lists (Cons)

-_images/memory-layout-list.png -

A list term is boxed value (i.e. contains a pointer to heap). 2 least-significant -bits of list value have TAG_PRIMARY_LIST=1, remaining bits are the pointer.

-

A value on heap -contains 2 Words – namely CAR (or list head) and -CDR (list tail) (see CAR and CDR macros in emulator/beam/erl_term.h). -This pair of words is called “Cons Cell” (terminology from -Lisp and functional programming). Cons cell has no header word stored in memory.

-

Each cons cell contains pointer to next cell in CDR (tail). -As this is also visible from Erlang, last cons cell of a list contains NIL -(a special value for empty list []) or a non-list Term -value (this makes improper list).

-

This structure may look inefficient, but on the other hand it allows -connecting any tail of any list to multiple cons cells to reuse existing data.

-
-
-

Boxed

-_images/memory-layout-box.png -

Boxed value is a pointer with 2 least-significant bits tagged with -TAG_PRIMARY_BOXED=2. Remaining bits are the pointer.

-

A boxed pointer must always point to a Header -(see explanation of headers below). Boxed values can be found everywhere: -in registers, on stack, on heaps.

-

Box always points at a Header (below). -During the garbage collection a Box can point to another Box or to -THE_NON_VALUE to mark a moved object, but never after.

-
-
-

Headers

-

Header tag is placed on any boxed value on heap, also on temporary blocks used -by internal emulator logic, they will be automatically garbage collected later.

-

Header values can never be found in register or on stack. This is heap-only data structure.

-
-

Tuple (ARITYVAL=0)

-_images/memory-layout-tuple.png -

A tuple has header word tagged with TAG_PRIMARY_HEADER with ARITYVAL_SUBTAG. -Remaining bits in header word represent tuple arity -(see arityval and make_arityval macros).

-

Following are tuple elements. This explains, why tuple is very easy to access at -arbitrary index, and very hard to grow. Modification of tuple elements in place -is used as optimization by Erlang compiler if it can prove, that intermediate -tuple value will be dropped.

-
-
-

Bignum (NEG=2/POS_BIG=3)

-_images/memory-layout-bignum.png -

Bignums have header word tagged with TAG_PRIMARY_HEADER followed by either -POS_BIG_SUBTAG or NEG_BIG_SUBTAG. Remaining bits in header word are arity, -i.e. how many extra Words are used by bignum bits.

-

Following are bits of the bignum, a Word at a time. -Most significant word goes first.

-
-
-

Reference (REF=4)

-_images/memory-layout-ref.png -

See struct RefThing in emulator/beam/erl_term.h. -Contains header word tagged with TAG_PRIMARY_HEADER with REF_SUBTAG which -also matches the first field of RefThing.

-

Following are other RefThing fields (3 32-bit words or 2 64-bit words) which -have the ref value stored in them. Internal (local) ref layout is explained in -emulator/beam/erl_term.h search for text “Ref layout (internal references)” and -“Ref layout on a 64-bit” (2 comments).

-
-
-

Fun/Closure (FUN=5)

-

See struct ErlFunThing in erl_fun.h. -Contains header word tagged with TAG_PRIMARY_HEADER with FUN_SUBTAG which -also matches the first field of ErlFunThing.

-

This is a closure (a function pointer with frozen variable values). It contains -pointer to function entry, arity, amount -of frozen variables, pid of creator process and array of frozen variables.

-
-
-

Float (FLOAT=6)

-

Contains header word tagged with TAG_PRIMARY_HEADER with FLOAT_SUBTAG. -Followed by 64 bit of C double IEEE-754 format.

-
-
-

Export (EXPORT=7)

-_images/memory-layout-export.png -

Refers to a {Mod, Fun, Arity}. Contains a pointer to the export table. -Always has arity 1 (because only one pointer).

-

A record in export table contains:

-
    -
  • Pointers to all (old and current) versions of the code for the function

  • -
  • 2 words with func_info opcode for the function. -Note, that this is executable BEAM code.

  • -
  • 3 words: Module (atom), Function (atom), Arity (as untagged integer)

  • -
  • 1 word which is 0 or may contain a apply, call or breakpoint opcode. -Note, that this is executable BEAM code.

  • -
  • 1 word argument for the previous opcode. May be a pointer to BEAM code, -a pointer to a C BIF function or 0.

  • -
-
-

See also

-

Export struct in emulator/beam/export.h

-
-
-
-

Reference-counted Binary (REFC_BINARY=8)

-

A pointer to binary on the binary heap. When this is destroyed, the reference -count is reduced (can only happen during GC). -Reference to refc binary is called procbin. -A refc binary whose refc reaches 0 is deleted.

-
-
-

Heap Binary (HEAP_BINARY=9)

-

A smaller binary (under 64 bytes) which is directly placed on the process heap.

-
-
-

Sub-binary (SUB_BINARY=10)

-

A temporary pointer to a part of another binary (either heap or refcounted, -but never into another sub-binary). -Can be produced by split_binary function.

-
-
-

Match context

-

Similar to sub-binary but is optimized for binary matching.

-
-
-

Ext Pid 12

-

Pid containing node name. Refers to a process on another node.

-
-
-

Ext Port 13

-

Port containing node name. Refers to a port on another node.

-
-
-

Ext Ref (EXTERNAL_REF=14)

-

External ref format is explained in erl_term.h search for “External thing layout”.

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/index.html b/docs/build/html/index.html deleted file mode 100644 index 04369c2..0000000 --- a/docs/build/html/index.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - Welcome, adventurer! — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Welcome, adventurer!

-

This is the collection of easy to read (ELI5) articles as well as in-depth -knowledge such as VM internals, memory layout, opcodes etc. -The project is work in progress, so come back soon! -Github repository for pages https://github.com/kvakvs/beam-wisdoms

-
-

Latest

-
    -
  • 2023-06-18 Leave readthedocs and migrate to Github pages.

  • -
  • 2019-03-03 Binary match opcodes added to the instruction list.

  • -
  • 2018-12-30 Try/catch opcodes added to the instruction list.

  • -
-
-

ELI5 Section (Explain Me Like I’m Five)

- -
-
-

Deeper Knowledge Section

- -
-

Todo

-

More details from ELI5 articles; -IO and ports; -Links and monitors; -ETS?; -BIFs, traps; -Process: Exceptions; -Ext term format

-
-

Smaller things you would’ve never noticed otherwise. OTP C source-related.

-

Erlang/OTP Source Style Guide, How OTP Source Would Benefit from C++, Things to Refactor in OTP

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/interfacing.html b/docs/build/html/interfacing.html deleted file mode 100644 index 3ee3131..0000000 --- a/docs/build/html/interfacing.html +++ /dev/null @@ -1,245 +0,0 @@ - - - - - - - - Interfacing Erlang with the Outer World — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Interfacing Erlang with the Outer World

-
-

Native Libraries

-
-

Note

-

This page was created between 2016 and 2018, more changes might have -happened since.

-
-

There are plenty of different approaches on integrating NIFs written in other -languages:

-
-

C

- -
-
-

C++

- -
-
-

Lua

- -
-
-

Python

-
    -
  • Pyrlang (Erlang node written in asyncio) (license Apache2)

  • -
  • ErlPort (see below in “Ports”)

  • -
  • erlang_py (license MIT)

  • -
  • py_interface -Website, -Github -(license LGPL)

  • -
  • PyErl Github (license MPL)

  • -
-
-
-

Ruby

- -
-
-

PHP

- -
-
-

Rust

- -
-
-

Nim

- -
-
-

Javascript

- -
-
-

Perl

- -
-
-
-

Ports and Network

-

For the situations when you still need the speed and can tolerate some call -latency over, but don’t want to risk crashing your node: choose interaction over -network or a port.

- -
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/objects.inv b/docs/build/html/objects.inv deleted file mode 100644 index 378ee83..0000000 Binary files a/docs/build/html/objects.inv and /dev/null differ diff --git a/docs/build/html/otp-c-refactor-todo.html b/docs/build/html/otp-c-refactor-todo.html deleted file mode 100644 index b0ad6bf..0000000 --- a/docs/build/html/otp-c-refactor-todo.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - Things to Refactor in OTP — BEAM VM Wisdoms - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Things to Refactor in OTP

-

Export structure leaks complexity which should be moved to export.h -or hidden.

-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/otp-c-style-guide.html b/docs/build/html/otp-c-style-guide.html deleted file mode 100644 index fcd0aa3..0000000 --- a/docs/build/html/otp-c-style-guide.html +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - - Erlang/OTP Source Style Guide — BEAM VM Wisdoms - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Erlang/OTP Source Style Guide

-
-

General

-

Source language is C89.

-

Source uses mix of tabs and spaces. Tab equals 8 spaces, indent is 4 spaces. -It seems that spaces are rather accepted way to indent contributions.

-
-
-

Version Control System

-

Erlang/OTP uses Git as its version control system.

-

Commits should have max 60 characters in the first line. Long commit description -follows after one empty line.

-

The source tree perfectly should be compilable at any time between commits (it does -not have to pass all tests between commits though), to simplify git bisect searches.

-
-
-

Headers

-
-

The #define Guard

-

All headers should have #define guards to prevent multiple inclusion. The format of -the symbol name is __MODULENAME_H__ or __MODULENAME_H. -Pragma once is not accepted as of Sept 2016.

-
-
-

Naming Macros

-

All macro names are defined using uppercase letters, numbers and underscores.

-

For new macros a general suggestion for type safety is: if it’s possible to write -it as inline function, one should not create a macro and use inline -(ERTS_INLINE or ERTS_FORCE_INLINE) instead.

-

Prefer to not convert existing macros to inline without a reason (they are well -tested as is now and their compiled representation may slightly change with -inline, that is not always desirable). -Also when going from a macro to a function, its name should be changed -accordingly (lowercase + prefix), this may have some undesired consequences -for dependent modules and external code using Erlang API.

-
-
-

Naming Types

-

A new type should be named in CamelCase. A publicly visible type must have -longer prefix. For example garbage collection functions have prefix erts_*, -erts_gc_*, and types have prefix ErtsGC*

-

Do not rename existing types without a good reason, especially if it was a -part of the public API.

-
-
-

Naming Functions

-

Functions are named using lowercase letters, numbers and underscores.

-

Function arguments are named using lowercase letters, numbers and underscores.

-

A globally visible non-inline function should have an erts_ prefix to its -name.

-

All inline functions should use ERTS_INLINE or ERTS_FORCE_INLINE macro.

-

A local function inside module should be declared static.

-
-
-

Naming Variables

-

Local variables are named using lowercase letters, numbers and underscores.

-

It is suggested to have local variables defined as close to their first use as -possible. -A new variable can be declared at the beginning of any scope -(inside an if, for, do etc), not just at the start of the function -body.

-

Consider using const if variable is only set once at the moment of its -declaration.

-

Consider using a strict sized type (Uint64 or Uint32 for example) when -you definitely know limits of your data. Otherwise consider using sizable -(Word) and similar.

-
-
-
-

Coding conventions

-
-

Argument Passing

-

If a function takes a pointer to a memory block, consider using const -pointer type to pass it as read only (const char * as a mutable pointer -to an immutable array of char).

-

If a function should return more than one value, pass pointer to the -container for the result or pass values using their address. -It is suggested to either mark such arguments in comment as in/out or have a -prefix _out.

-

To avoid mistakes, try not having similar types following each other in -argument list. -This way you’ll get compiler warning if you miss one argument position.

-
-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/otp-cpp-ramblings.html b/docs/build/html/otp-cpp-ramblings.html deleted file mode 100644 index b37a39a..0000000 --- a/docs/build/html/otp-cpp-ramblings.html +++ /dev/null @@ -1,270 +0,0 @@ - - - - - - - - How OTP Source Would Benefit from C++ — BEAM VM Wisdoms - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

How OTP Source Would Benefit from C++

-

Here are my personal thoughts + results of my experiments with transferring -OTP C source to C++ and listing benefits of doing so for real.

-

Here is a brilliant case study on converting a C library to C++ with benefits -listed: -J. Daniel Garcia and B. Stroustrup: -Improving performance and maintainability through refactoring in C++11. -Isocpp.org. August 2015. They managed to reduce instruction count, improve -branch miss ratio, thus improving the performance.

-

Another success story: Porting MAME (multiple arcade machine emulator) from C to modern C++ https://www.youtube.com/watch?v=wAUnUWYaA5s -The intro to what is MAME and why it is so huge goes till 26min then the conversion story begins.

-
-

Portability Benefits

-

Currently compiling Erlang/OTP on Windows is pain. It is built using MSVC for -the C89 part, except that beam_emu.c is built using GCC. -This is happening because “jump to label address” extension is not supported on -MSVC which falls back to switch dispatch and creates much slower code.

-

Microsoft stated, that they will not be investing any time into supporting -modern C standards with MSVC. -So there are only two ways out: use another compiler on Windows (gcc or Clang) -or switch to C++ and use MSVC natively.

-
-
-

Code Benefits

-
-

Compatible with C

-

C runs perfectly fine when compiled as C++, the transition can happen gradually. -Does not have to use certain features like RTTI and exceptions, they can be -disabled at compiler-level.

-
-
-

Compile-Time Everywhere

-

Macros with code should be replaced with typed inlines or constexpr. -This helps with type checking and debuggability. -Stepping into a function in a debugger works much better than into a macro. -Also type safety applies. [Better view in debugger]

-

Macros with numbers should be replaced with const and constexpr. -This way they will have a type, a namespace, and possibly may change into -an enum. -[Type checking = less bugs]

-

Abusive prefixing on enum should be replaced with enum class -and namespaces. Moving enums with smaller scope into relevant structs and -classes (serves as a namespace). -[Less collisions and confusions in naming]

-
-
-

Type Safety

-

C++ is more strict about types, pointer types and alignment. Example: Assigning -an Eterm* to a char* will change alignment requirement from 8 to 1, -possibly hiding a bug. [Prevents accidents]

-

Size types can be tagged: word and byte counts can be made incompatible to -reduce confusion and bugs, with conversion functions. -[Less word-byte-confusion-related bugs]

-

To develop the idea of tagging further, memory pointer types can be tagged -(making them incompatible with other pointer types to reduce confusion -when passing them as arguments). -[Less memory-type related bugs]

-

Things like memcpy invite errors, you have to be mindful about types and -sizes. C++ allows to rewrite this in a safe way, they even have std::copy -that does the same in a safe way (often this compiles into a memcpy -but with correct sizes and bounds). -The C alternative having a function per type with separate names is highly -impractical. [Safer memory bounds]

-

Things like erts_alloc invite errors because you have to remember data -sizes. C++ can make sizes deducted automatically and return a correct -pointer type. [Safer memory allocations] -[Safer deallocations if they check types too]

-
-
-

Divide and Rule

-

Abusive prefixing on types and function names should go into namespaces. -Structs and classes also serve as namespaces (unlike in C).

-

Benefits are immense: names become shorter at the cost of specifying namespace -at the beginning of module or a scope (using namespace X or -namespace X = Y::Z). -[Shorter names easier to read]

-

Hiding a lot of small macros with short nondescript names and abstracting -away things. Example: erl_term.h and all the macros in it can be -generalized, grouped under the name of eterm and type checked. -In modern C++ all functions in the class header file are implicitly inline. -[Fast code at no cost]

-
-
-

Generic Code

-

Code duplication can be reduced by moving code into templated functions. -Long functions can and should be broken into smaller, reducing the variable -scope and amount of code to read. -Example: Garbage collection sweeps are generic, before R20 they were -duplicated code. -[Less mistakes with copies of almost identical code]

-

This applies to all the aggressively macroed code, again. -[Stricter type control, less bugs, code is as fast as before]

-

“Zero abstraction cost” is the ground C++ principle. -Much work can be done at the compile-time, based on type checking, inlining -and optimization. Amount of abstractions used should have little impact on -resulting machine code. -[Code is fast as in C]

-

For example: wrapping Eterm into a class will -not affect its memory and code footprint, but give full control to the developer -on how the type is convertable, what goes in and how it comes out, how to copy -it, what to do when the type is destroyed, also will allow to group all tool -macros and functions inside that class. -[Code is as fast as in C]

-

Many loops can be remade generic using higher order functions. -C++ compiler often is smart enough to inline them without degrading machine -code quality. -[Code is as fast as in C] [Less bugs when using generic algorithms]

-
-
-

Performance and Safety

-

Smart pointers and RAII should be used for temporary memory (resource) -allocations reducing manual resource management. Let compiler remember, when -you have to reduce that refcount or free that temporary buffer. -[Automatic resource management at little to no cost]

-

With const-correctness we gain better control on what can be changed where. -Current OTP source is not const-correct and safety is enforced through -convoluted locking and thorough thinking + debugging. -Const-correct code is transparent on what memory it touches, and is -easier to parallellize. Pure const-correct code is even better. -[Harder to create bad code]

-
-
-
-

How Hard Is To Migrate

-

I’ve done several attempts with varying degree of success. -One must fix all C++ keywords used as variable and argument names (easy).

-

Because C++ is stricter to pointers and type casts, one must revisit all places, -where erts_alloc/realloc are happening and fix the type casts there.

-

Generated tables also use pointer conversion and the generation scripts must be -mended (several lines changes in few places).

-

Note: https://www.youtube.com/watch?v=w5Z4JlMJ1VQ -CppCon 2016: Tim Haines “Improving Performance Through Compiler Switches…”

-
-
- - - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/search.html b/docs/build/html/search.html deleted file mode 100644 index 9896cce..0000000 --- a/docs/build/html/search.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - Search — BEAM VM Wisdoms - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Search

- - - - -

- Searching for multiple words only shows matches that contain - all words. -

- - -
- - - -
- - - -
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/build/html/searchindex.js b/docs/build/html/searchindex.js deleted file mode 100644 index be449a1..0000000 --- a/docs/build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({"docnames": ["definitions", "eli5-atoms", "eli5-bif-nif", "eli5-efficiency", "eli5-efficiency-memory-perf", "eli5-etf", "eli5-io", "eli5-process-heap", "eli5-processes", "eli5-property-based", "eli5-tracing", "eli5-types", "eli5-vm", "indepth-beam-file", "indepth-beam-instructions", "indepth-data-sizes", "indepth-heap-layout", "indepth-io", "indepth-memory-layout", "index", "interfacing", "otp-c-refactor-todo", "otp-c-style-guide", "otp-cpp-ramblings"], "filenames": ["definitions.rst", "eli5-atoms.rst", "eli5-bif-nif.rst", "eli5-efficiency.rst", "eli5-efficiency-memory-perf.rst", "eli5-etf.rst", "eli5-io.rst", "eli5-process-heap.rst", "eli5-processes.rst", "eli5-property-based.rst", "eli5-tracing.rst", "eli5-types.rst", "eli5-vm.rst", "indepth-beam-file.rst", "indepth-beam-instructions.rst", "indepth-data-sizes.rst", "indepth-heap-layout.rst", "indepth-io.rst", "indepth-memory-layout.rst", "index.rst", "interfacing.rst", "otp-c-refactor-todo.rst", "otp-c-style-guide.rst", "otp-cpp-ramblings.rst"], "titles": ["BEAM Definitions", "Atoms ELI5", "BIF and NIF functions ELI5", "Efficiency ELI5", "Memory Performance ELI5", "External Term Format ELI5", "Input/Output and Ports ELI5", "Process Heaps ELI5", "Processes ELI5", "Property Based Testing ELI5", "Tracing ELI5", "Types ELI5", "BEAM VM ELI5", "BEAM File Format", "BEAM Instruction Codes", "BEAM Internal data sizes", "Process Heap Layout", "IO in Erlang", "Data Types Memory Layout", "Welcome, adventurer!", "Interfacing Erlang with the Outer World", "Things to Refactor in OTP", "Erlang/OTP Source Style Guide", "How OTP Source Would Benefit from C++"], "terms": {"For": [0, 4, 6, 7, 11, 12, 13, 14, 15, 18, 20, 22, 23], "specif": [0, 11, 14, 15], "constant": [0, 13, 16], "valu": [0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 15, 16, 19, 22], "bit": [0, 2, 7, 10, 13, 14, 15, 18], "posit": [0, 7, 8, 13, 14, 15, 16, 22], "size": [0, 1, 3, 4, 5, 8, 13, 14, 16, 18, 19, 22, 23], "pleas": [0, 9, 14, 15], "alwai": [0, 1, 4, 5, 8, 11, 14, 15, 16, 18, 22], "refer": [0, 1, 2, 3, 5, 7, 8, 11, 13, 14, 15], "origin": [0, 12, 15], "sourc": [0, 2, 7, 11, 12, 13, 14, 15, 19], "file": [0, 1, 2, 3, 6, 7, 11, 12, 14, 15, 19, 23], "erl_term": [0, 15, 18, 23], "h": [0, 14, 15, 16, 17, 18, 21, 23], "box": [0, 8, 9, 14, 19], "A": [0, 2, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22], "term": [0, 2, 7, 8, 12, 14, 15, 18, 19, 20], "whose": [0, 18], "primari": [0, 6], "tag": [0, 1, 5, 7, 14, 15, 18, 23], "i": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 22], "tag_primary_box": [0, 18], "2": [0, 10, 13, 15], "contain": [0, 4, 5, 7, 8, 11, 12, 13, 15, 16, 18, 22], "pointer": [0, 2, 3, 4, 5, 8, 12, 13, 14, 15, 17, 18, 22, 23], "data": [0, 1, 6, 7, 8, 9, 10, 13, 14, 16, 17, 19, 22, 23], "heap": [0, 3, 4, 8, 14, 15, 19], "The": [0, 4, 5, 7, 8, 9, 13, 14, 16, 19, 23], "first": [0, 8, 11, 12, 13, 15, 18, 22], "word": [0, 4, 7, 8, 13, 14, 15, 16, 18, 22, 23], "ha": [0, 1, 3, 4, 7, 12, 13, 14, 15, 16, 18], "header": [0, 4, 5, 7, 8, 13, 16, 19, 23], "tag_primary_head": [0, 18], "0": [0, 3, 8, 9, 12, 13, 14], "its": [0, 1, 3, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 22, 23], "least": [0, 5, 13, 14, 18], "signific": [0, 4, 5, 13, 15, 18], "Then": [0, 7, 8, 9, 11, 13, 14], "goe": [0, 13, 16, 17, 18, 23], "subtag": 0, "follow": [0, 4, 7, 12, 13, 14, 15, 16, 18, 22], "4": [0, 8, 10, 13, 15, 22], "which": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 23], "determin": [0, 12, 14], "type": [0, 2, 5, 7, 9, 12, 13, 14, 19], "insid": [0, 3, 13, 16, 22, 23], "know": [0, 7, 8, 9, 18, 22], "thi": [0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23], "allow": [0, 4, 5, 7, 8, 10, 11, 18, 23], "scan": [0, 7, 8, 14], "interpret": [0, 13, 18], "found": [0, 11, 13, 14, 15, 16, 18], "vm": [0, 4, 5, 6, 8, 10, 13, 14, 19], "us": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 18, 22, 23], "store": [0, 3, 4, 7, 8, 12, 13, 14, 15, 18], "larger": [0, 4, 8, 13], "do": [0, 4, 6, 8, 11, 12, 13, 14, 22, 23], "fit": [0, 4], "minu": [0, 13, 18], "immedi": [0, 1, 14, 19], "1": [0, 5, 9, 12, 13, 15, 16, 18, 23], "6": [0, 13], "exampl": [0, 2, 3, 6, 7, 11, 12, 13, 16, 22, 23], "bigint": [0, 15], "float": [0, 5, 11, 13, 14], "fun": [0, 11, 13, 14, 15, 16], "export": [0, 2, 14, 15, 21], "refcount": [0, 15, 16, 18, 23], "binari": [0, 3, 5, 13, 15, 16, 19], "extern": [0, 1, 13, 14, 15, 18, 19, 22], "port": [0, 1, 2, 3, 5, 10, 15, 19, 23], "pid": [0, 1, 4, 5, 8, 15], "host": 0, "name": [0, 1, 2, 5, 6, 8, 10, 12, 13, 17, 18, 23], "them": [0, 1, 4, 7, 8, 11, 12, 13, 14, 18, 23], "cach": [0, 8], "local": [0, 8, 14, 15, 18, 22], "mythic": 0, "creatur": 0, "scare": 0, "naughti": 0, "develop": [0, 1, 4, 23], "It": [0, 1, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 18, 22, 23], "mai": [0, 3, 4, 6, 7, 8, 11, 14, 18, 22, 23], "have": [0, 1, 2, 3, 4, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 23], "either": [0, 8, 13, 18, 22], "huge": [0, 13, 23], "impact": [0, 4, 23], "your": [0, 2, 3, 4, 6, 9, 10, 11, 17, 20, 22], "code": [0, 1, 3, 4, 6, 8, 9, 10, 11, 12, 16, 18, 19], "perform": [0, 3, 6, 7, 10, 13, 14, 19], "veri": [0, 4, 12, 18], "littl": [0, 23], "run": [0, 4, 6, 7, 8, 9, 11, 13, 14, 23], "test": [0, 19, 22], "befor": [0, 3, 4, 8, 9, 10, 16, 23], "you": [0, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 14, 15, 17, 18, 19, 20, 22, 23], "start": [0, 5, 6, 7, 8, 10, 14, 15, 16, 17, 22], "optim": [0, 4, 14, 18, 23], "context": [0, 14], "virtual": [0, 2, 10, 12], "machin": [0, 2, 4, 5, 8, 9, 10, 12, 13, 23], "small": [0, 4, 6, 8, 12, 13, 14, 15, 18, 23], "structur": [0, 3, 4, 8, 18, 21], "copi": [0, 7, 8, 16, 23], "activ": [0, 7, 8], "regist": [0, 2, 4, 5, 6, 7, 8, 13, 14, 15, 17, 18], "instruct": [0, 4, 8, 13, 19, 23], "few": [0, 8, 12, 13, 17, 23], "other": [0, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 17, 18, 20, 22, 23], "from": [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 19, 22], "current": [0, 4, 8, 10, 13, 14, 16, 18, 23], "process": [0, 2, 3, 4, 6, 10, 12, 14, 17, 18, 19], "cpu": [0, 4, 6, 8, 12], "stack": [0, 4, 7, 10, 12, 14, 15, 16, 18], "base": [0, 14, 15, 19, 23], "c": [0, 2, 4, 6, 7, 8, 9, 10, 12, 14, 16, 17, 18, 19], "compil": [0, 2, 11, 12, 14, 18, 22], "judgement": 0, "when": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 16, 18, 20, 22, 23], "build": [0, 2, 9], "emul": [0, 2, 7, 12, 13, 17, 18, 23], "readi": [0, 7], "field": [0, 1, 2, 4, 8, 11, 13, 16, 18], "ar": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 23], "e": [0, 11, 13, 18], "swap": 0, "suspend": [0, 14], "schedul": [0, 6, 7], "out": [0, 2, 8, 13, 22, 23], "back": [0, 6, 8, 19, 23], "oper": [0, 1, 4, 5, 8, 19], "call": [0, 2, 3, 4, 6, 7, 8, 9, 10, 11, 16, 17, 18, 20], "cheap": [0, 1, 3], "so": [0, 1, 2, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 19, 23], "tri": [0, 9, 11], "minim": [0, 8, 16], "switch": [0, 12, 23], "also": [0, 1, 2, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 18, 22, 23], "chang": [0, 1, 3, 8, 17, 20, 22, 23], "nativ": [0, 2, 19, 23], "hipe": 0, "jit": 0, "why": [0, 1, 3, 6, 8, 18, 23], "mix": [0, 22], "normal": [0, 8], "erlang": [0, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 23], "program": [0, 2, 4, 5, 6, 9, 11, 13, 18], "each": [0, 4, 6, 7, 10, 11, 12, 13, 14, 15, 18, 22], "an": [0, 1, 4, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 22, 23], "expens": [0, 4], "luxuri": 0, "cp": [0, 5, 8, 14, 15], "continu": [0, 5, 10, 13, 16], "raw": 0, "locat": [0, 4, 7, 8, 12, 13, 14, 16], "prepar": [0, 10, 13], "return": [0, 2, 8, 9, 10, 11, 22, 23], "label": [0, 12, 13, 14, 23], "offset": [0, 4, 13, 14], "can": [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 23], "onli": [0, 3, 4, 6, 7, 8, 11, 12, 15, 16, 18, 22, 23], "never": [0, 2, 3, 5, 8, 15, 18, 19], "referenc": 0, "block": [0, 4, 8, 13, 15, 18, 22], "memori": [0, 3, 7, 8, 12, 13, 14, 15, 16, 19, 22, 23], "usual": [0, 5, 12, 14, 15], "reserv": 0, "defin": [0, 3, 9, 14, 17], "content": 0, "remain": [0, 7, 13, 14, 15, 18], "hold": 0, "inform": [0, 8], "often": [0, 2, 4, 7, 8, 11, 14, 23], "ariti": [0, 12, 13, 14, 15, 18], "tag_primary_immed1": [0, 18], "3": [0, 9, 12, 13, 14, 16], "two": [0, 7, 11, 13, 15, 18, 23], "tag_immed1_": 0, "macro": [0, 15, 18, 23], "If": [0, 1, 2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 18, 22], "equal": [0, 8, 14, 22], "tag_immed1_immed2": 0, "more": [0, 2, 7, 8, 10, 11, 12, 13, 16, 18, 19, 20, 22, 23], "tag_immed2_": 0, "integ": [0, 1, 4, 5, 9, 11, 13, 14, 18], "atom": [0, 4, 5, 11, 14, 15, 18, 19], "empti": [0, 11, 13, 14, 15, 18, 22], "list": [0, 2, 8, 13, 14, 16, 19, 22, 23], "nil": [0, 13, 14, 15, 18], "one": [0, 2, 4, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 18, 22, 23], "doe": [0, 1, 4, 6, 8, 10, 11, 14, 16, 22, 23], "ani": [0, 3, 4, 7, 8, 9, 11, 13, 18, 22, 23], "dynam": [0, 11, 12, 17], "alloc": [0, 8, 12, 13, 16, 23], "resiz": 0, "help": [0, 23], "erts_realloc": 0, "new": [0, 1, 2, 3, 7, 10, 13, 14, 16, 22], "fragment": [0, 7, 8, 16], "move": [0, 3, 4, 7, 8, 18, 21, 23], "garbag": [0, 3, 4, 14, 16, 18, 22, 23], "collector": [0, 3, 7], "place": [0, 4, 5, 8, 10, 11, 12, 13, 14, 16, 18, 23], "onto": [0, 10, 16], "sequenti": [0, 4], "special": [0, 2, 3, 4, 5, 8, 10, 13, 14, 15, 18], "receiv": [0, 6, 7, 8, 10, 17], "open_port": 0, "hook": 0, "driver": [0, 2, 19, 20], "built": [0, 2, 6, 23], "custom": 0, "send": [0, 6, 7, 10, 17], "command": [0, 6, 7, 17], "messag": [0, 3, 5, 6, 7, 10, 14], "close": [0, 4, 6, 17, 22], "link": [0, 4, 6, 8, 14, 15, 19], "monitor": [0, 6, 19], "ad": [0, 5, 6, 16, 19], "v": [0, 6, 23], "19": [0, 6, 7], "manag": [0, 23], "some": [0, 2, 4, 6, 7, 8, 9, 11, 12, 14, 15, 16, 20, 22], "resourc": [0, 2, 3, 6, 23], "socket": [0, 6], "zip": [0, 13], "archiv": 0, "etc": [0, 3, 4, 5, 8, 19, 22], "provid": [0, 13, 14], "stream": [0, 10], "event": [0, 10, 14, 17], "write": [0, 6, 9, 14, 22], "well": [0, 19, 22], "encod": [0, 5, 12, 14, 19], "sever": [0, 4, 6, 8, 14, 17, 23], "repres": [0, 4, 15, 18], "tag_primary_list": [0, 18], "reduct": [0, 8], "cost": [0, 4, 23], "imaginari": 0, "unit": [0, 9, 14], "where": [0, 2, 4, 7, 8, 14, 16, 23], "approxim": [0, 8, 12], "function": [0, 5, 8, 9, 10, 11, 12, 14, 17, 18, 19, 23], "deriv": 0, "arrai": [0, 4, 7, 8, 12, 13, 14, 18, 22], "pass": [0, 3, 8, 10, 11, 12, 17, 23], "argument": [0, 8, 9, 10, 11, 12, 13, 14, 18, 23], "recurs": [0, 8, 12, 14], "made": [0, 8, 12, 23], "affect": [0, 1, 4, 6, 7, 8, 23], "save": [0, 3, 4, 5, 7, 8, 12, 14], "root": [0, 7], "dure": [0, 2, 8, 9, 12, 15, 16, 18], "collect": [0, 4, 14, 16, 18, 19, 22, 23], "all": [0, 3, 4, 5, 7, 9, 12, 13, 14, 15, 16, 17, 18, 22, 23], "known": [0, 7, 8, 13], "live": [0, 7, 8, 14], "thei": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 22, 23], "dictionari": 0, "queue": [0, 14], "group": [0, 4, 8, 23], "leader": 0, "except": [0, 2, 8, 13, 14, 15, 19, 23], "reason": [0, 1, 6, 18, 22], "anyth": 0, "trace": [0, 7, 8, 19], "consid": [0, 4, 13, 14, 15, 16, 22], "reachabl": 0, "previou": [0, 7, 8, 16, 18], "discard": 0, "becaus": [0, 1, 4, 10, 14, 18, 23], "reach": [0, 1, 2, 8, 18], "anymor": 0, "loop": [0, 4, 8, 13, 23], "fix": [0, 23], "core": [0, 4, 6, 8], "fetch": 0, "execut": [0, 2, 10, 14, 18], "next": [0, 2, 8, 12, 13, 14, 15, 18], "take": [0, 2, 3, 7, 8, 9, 11, 13, 14, 15, 22], "As": [0, 3, 4, 14, 18], "soon": [0, 16, 19], "been": [0, 6], "certain": [0, 8, 10, 23], "number": [0, 6, 8, 14, 15, 18, 22, 23], "sai": [0, 4, 8, 11], "2000": 0, "put": [0, 8, 13], "sleep": [0, 8], "left": 0, "off": [0, 10, 16], "sort": [0, 4, 8, 15, 16], "fair": [0, 8], "everyon": 0, "guarante": [0, 7], "slice": [0, 14], "time": [0, 2, 3, 4, 6, 8, 10, 13, 14, 18, 22], "matter": [0, 4, 8], "how": [0, 4, 7, 8, 10, 13, 14, 18, 19], "busi": [0, 8], "slot": [0, 14], "point": [0, 4, 11, 13, 14, 15, 18], "intern": [0, 1, 2, 5, 8, 9, 14, 18, 19], "appear": [0, 1, 5, 15], "section": [0, 2, 7, 14, 17], "young": [0, 7, 8, 16], "temporari": [0, 8, 18, 23], "storag": [0, 8], "creat": [0, 1, 2, 4, 6, 8, 10, 13, 14, 20, 22, 23], "zero": [0, 14, 23], "begin": [0, 8, 14, 15, 22, 23], "heap_end": [0, 16], "grow": [0, 4, 8, 18, 19], "decrement": [0, 14], "address": [0, 8, 10, 12, 13, 14, 22, 23], "until": [0, 8, 13, 15], "meet": [0, 7, 16], "heap_top": [0, 7, 16], "full": [0, 16, 23], "trigger": [0, 7, 16], "frame": [0, 8, 12, 14], "push": [0, 10, 13], "extra": [0, 6, 8, 14, 18], "sometim": [0, 1], "throw": [0, 14], "stacktrac": [0, 14], "marker": [0, 13], "correspond": [0, 14], "mark": [0, 4, 5, 8, 13, 14, 15, 16, 18, 22], "find": [0, 2, 8, 9, 11, 13, 14], "boundari": [0, 3], "rest": [0, 4], "variabl": [0, 4, 8, 11, 14, 15, 17, 18, 23], "between": [0, 3, 4, 9, 12, 13, 20, 22], "depend": [0, 8, 13, 14, 22], "itself": [0, 15], "termin": [0, 8], "exit": [0, 10, 17], "kill": 0, "signal": [0, 8], "sent": [0, 8, 10], "work": [0, 2, 4, 8, 19, 23], "similar": [0, 3, 6, 10, 16, 18, 22], "wa": [0, 4, 8, 10, 13, 14, 20, 22], "abl": [0, 2, 8, 10, 18], "catch": [0, 8, 10, 15, 19], "trap_exit": 0, "noth": [0, 6, 11], "els": [0, 4, 6, 7, 8, 15], "happen": [0, 4, 7, 9, 11, 18, 20, 23], "go": [0, 14, 16, 22, 23], "die": [0, 16], "free": [0, 8, 14, 23], "leav": [0, 1, 3, 18, 19], "get": [0, 1, 6, 8, 13, 14, 22], "unregist": [0, 8], "registri": 0, "the_non_valu": [0, 2, 5, 18], "see": [0, 2, 3, 4, 5, 7, 9, 12, 13, 14, 15, 16, 17, 18, 20], "bif": [0, 8, 10, 14, 18, 19], "whether": [0, 14], "debug": [0, 23], "set": [0, 1, 8, 10, 11, 12, 13, 14, 22], "enabl": [0, 10], "0110": 0, "00": 0, "Or": [0, 4, 8], "tupl": [0, 3, 9, 13, 14], "thu": [0, 1, 8, 15, 23], "unsign": [0, 13], "width": 0, "32": [0, 15, 18], "architectur": [0, 4, 12, 15], "64": [0, 3, 4, 15, 18], "In": [0, 2, 3, 4, 7, 12, 13, 23], "uword": 0, "sign": [0, 13, 15, 18], "sword": 0, "tabl": [1, 5, 8, 10, 12, 18, 19, 23], "global": [1, 8, 22], "map": [1, 8, 13, 15], "string": [1, 5], "There": [1, 2, 4, 7, 8, 9, 11, 12, 13, 14, 20], "opposit": [1, 5], "lookup": [1, 3, 8, 12], "hard": [1, 18], "limit": [1, 10, 13, 18, 22], "1048576": 1, "ever": [1, 3, 12], "node": [1, 5, 8, 18, 20], "crash": [1, 20], "runtim": [1, 8], "riski": 1, "idea": [1, 13, 23], "t": [1, 4, 6, 7, 8, 9, 14, 20], "flag": [1, 6, 7, 8, 13, 14], "erl": [1, 11, 12, 17], "symbol": [1, 13, 22], "uniqu": [1, 8], "just": [1, 4, 12, 22], "beam": [1, 2, 4, 7, 8, 10, 11, 17, 18, 19], "loader": [1, 2, 12, 17], "routin": [1, 12, 13], "read": [1, 2, 4, 6, 11, 12, 14, 16, 19, 22, 23], "look": [1, 4, 7, 9, 11, 13, 14, 18, 19], "up": [1, 6, 7, 8, 10, 13, 14], "replac": [1, 2, 5, 10, 12, 14, 23], "henceforth": 1, "manipul": 1, "instead": [1, 3, 4, 22], "These": [1, 2, 3, 4, 11], "cannot": [1, 8, 14], "over": [1, 2, 5, 20], "network": [1, 5, 19], "disk": [1, 5], "anoth": [1, 4, 7, 8, 9, 10, 11, 15, 18, 23], "differ": [1, 2, 7, 8, 9, 12, 13, 15, 20], "numer": [1, 13], "convert": [1, 13, 22, 23], "mnesia": 1, "det": 1, "prefer": [1, 8, 22], "short": [1, 23], "databas": [1, 4], "unless": 2, "otp": [2, 3, 11, 13, 14, 19], "own": [2, 3, 4, 8, 10, 12, 13], "want": [2, 3, 7, 8, 9, 10, 20], "implement": [2, 6, 8, 14], "project": [2, 11, 19], "check": [2, 6, 9, 10, 13, 14, 23], "about": [2, 4, 8, 9, 11, 13, 16, 23], "standard": [2, 5, 13, 23], "librari": [2, 5, 9, 13, 19, 23], "most": [2, 3, 4, 5, 12, 13, 15, 18], "But": [2, 5], "mani": [2, 4, 6, 7, 9, 13, 14, 18, 23], "featur": [2, 6, 8, 12, 23], "imposs": [2, 5], "pure": [2, 6, 23], "were": [2, 8, 13, 23], "written": [2, 11, 13, 17, 20], "static": [2, 22], "modul": [2, 3, 6, 11, 13, 14, 16, 17, 18, 22, 23], "singl": [2, 4, 8], "nif_error": 2, "stub": 2, "languag": [2, 6, 9, 11, 20, 22], "like": [2, 4, 7, 8, 9, 10, 11, 16, 23], "rust": 2, "should": [2, 4, 9, 11, 13, 14, 15, 21, 22, 23], "tab": [2, 14, 22], "connect": [2, 6, 18], "curiou": 2, "search": [2, 14, 18, 22], "lists_reverse_2": 2, "erl_bif_list": 2, "access": [2, 3, 4, 6, 16, 18], "eterm": [2, 23], "need": [2, 7, 8, 12, 13, 14, 16, 17, 20], "must": [2, 13, 14, 16, 18, 22, 23], "control": [2, 4, 6, 7, 8, 17, 23], "trap": [2, 10, 19], "yield": 2, "wai": [2, 3, 4, 8, 9, 12, 13, 22, 23], "make": [2, 4, 5, 8, 9, 12, 14, 18, 19, 23], "suit": 2, "separ": [2, 3, 6, 13, 15, 23], "load": [2, 3, 4, 12, 13, 14, 17], "user": [2, 13], "interfac": [2, 6, 17, 19], "system": [2, 7, 9, 17, 18], "simplifi": [2, 22], "abstract": [2, 12, 23], "awai": [2, 10, 23], "hide": [2, 15, 23], "good": [2, 4, 9, 22], "tutori": 2, "document": [2, 5, 9, 11, 13, 17], "million": [2, 8, 16, 18], "avail": [2, 4, 13, 14], "variou": 2, "github": [2, 6, 13, 19, 20], "still": [2, 9, 20], "even": [2, 4, 9, 11, 14, 23], "care": 2, "badli": [2, 13], "tip": 2, "whole": 2, "hog": 2, "slow": [2, 8], "grind": 2, "wisdom": [2, 7, 12, 17, 19], "outer": [2, 5, 6, 17, 19], "world": [2, 5, 6, 17, 19], "interoper": 2, "here": [3, 4, 7, 13, 14, 23], "gener": [3, 4, 7, 11, 14, 20], "rule": [3, 4, 14], "regard": 3, "long": [3, 8, 12, 22, 23], "owner": 3, "et": [3, 19], "behav": [3, 6], "similarli": [3, 8, 13], "larg": [3, 4, 8, 11], "byte": [3, 4, 5, 8, 13, 14, 18, 23], "count": [3, 13, 15, 23], "share": 3, "gc": [3, 4, 14, 15, 18], "period": [3, 6], "touch": [3, 23], "otherwis": [3, 14, 19, 22], "freed": [3, 7, 16], "area": [3, 14, 15, 16], "pool": 3, "later": [3, 8, 10, 12, 13, 18], "reload": 3, "old": [3, 7, 12, 16, 18], "note": [3, 9, 14, 18, 23], "below": [3, 7, 13, 15, 18, 20], "20": [3, 12, 13, 16], "trick": [3, 4, 7, 10, 12], "element": [3, 12, 13, 14, 18], "version": [3, 8, 13, 18], "prior": 3, "cross": [3, 5], "explain": [3, 18], "abov": 3, "13529": 3, "releas": 3, "recent": 4, "decad": 4, "comput": [4, 6], "did": 4, "fast": [4, 23], "improv": [4, 6, 23], "To": [4, 5, 6, 8, 9, 10, 11, 13, 16, 18, 22], "low": [4, 7, 8], "level": [4, 8, 23], "closer": 4, "flush": [4, 17], "onc": [4, 22], "row": 4, "gain": [4, 23], "best": 4, "relev": [4, 23], "togeth": [4, 8], "view": [4, 23], "mean": [4, 7, 11, 12, 13, 14, 16], "And": [4, 9, 18], "high": [4, 8], "cheaper": 4, "calcul": [4, 11, 15], "cold": 4, "uncach": 4, "rare": [4, 12, 16], "hot": 4, "welcom": 4, "would": [4, 8, 12, 19], "class": [4, 23], "object": [4, 14, 15, 16, 18], "harder": [4, 23], "we": [4, 9, 10, 12, 13, 14, 23], "don": [4, 6, 8, 20], "much": [4, 8, 23], "behaviour": [4, 8], "placement": [4, 7], "after": [4, 7, 8, 12, 14, 16, 18, 22], "situat": [4, 6, 12, 16, 20], "occur": [4, 5], "wasn": 4, "request": [4, 14], "main": [4, 5, 6], "ram": 4, "forc": 4, "wait": [4, 6, 8], "possibl": [4, 7, 8, 9, 11, 13, 22], "try": [4, 9, 13, 19, 22], "reorder": 4, "assum": [4, 7, 9], "typic": [4, 15], "100": [4, 9], "cycl": 4, "lot": [4, 12, 23], "simpler": 4, "without": [4, 6, 8, 9, 22, 23], "wors": 4, "product": 4, "server": 4, "hundr": [4, 14], "gb": 4, "non": [4, 5, 15, 18, 22], "uniform": 4, "numa": 4, "divid": 4, "higher": [4, 23], "especi": [4, 22], "part": [4, 7, 13, 18, 22, 23], "awar": 4, "preserv": [4, 8, 14], "awesom": 4, "algorithm": [4, 7, 11, 23], "now": [4, 13, 22], "perfect": 4, "doesn": [4, 7, 9], "better": [4, 11, 13, 23], "effort": 4, "reward": 4, "effici": [4, 13, 15, 19], "faster": [4, 12], "major": 4, "order": [4, 13, 16, 23], "cell": [4, 7, 14, 15, 18], "although": [4, 15], "might": [4, 20], "super": 4, "heavi": 4, "while": [4, 14], "keep": [4, 7, 8], "intens": 4, "per": [4, 7, 8, 23], "let": [4, 8, 13, 23], "worker": 4, "big": [4, 5, 7, 13], "garbage_collect": 4, "smallest": 4, "pair": [4, 13, 18], "complex": [4, 9, 10, 21], "slowli": 4, "spars": 4, "distribut": [4, 5, 11], "interleav": 4, "same": [4, 8, 11, 12, 13, 23], "lead": 4, "ineffici": [4, 18], "usag": [4, 11], "tight": [4, 14], "unnecessari": 4, "tightli": 4, "invok": [4, 6, 13], "everyth": [4, 7, 8, 10, 13, 15], "friendli": 4, "somewher": [4, 15], "actual": [4, 6, 9, 13, 18], "presenc": 4, "consum": [4, 6, 15], "doubl": [4, 18], "derefer": 4, "possibli": [4, 9, 11, 13, 14, 16, 23], "maxim": 4, "automat": [4, 18, 23], "merci": 4, "commun": 5, "thing": [5, 7, 9, 10, 17, 18, 19, 23], "requir": [5, 8, 9, 23], "easi": [5, 8, 12, 18, 19, 23], "human": 5, "what": [5, 7, 11, 13, 23], "131": [5, 13], "0x83": 5, "compact": [5, 12, 14, 19], "option": [5, 11, 13, 17], "compress": [5, 13], "80": 5, "0x50": 5, "u32": [5, 13], "length": [5, 13], "platform": 5, "endian": 5, "ieee": [5, 18], "text": [5, 18], "utf": 5, "8": [5, 8, 13, 22, 23], "iso": 5, "8859": 5, "ascii": [5, 13], "superset": 5, "term_to_binari": [5, 13], "binary_to_term": [5, 13], "decod": [5, 13], "craft": [5, 14], "u": [5, 14], "construct": 5, "exist": [5, 8, 9, 11, 13, 14, 16, 18, 22], "mode": [5, 10], "further": [5, 23], "reduc": [5, 7, 9, 11, 16, 18, 23], "protocol": 5, "includ": 5, "index": [5, 12, 13, 18], "peopl": 6, "side": 6, "effect": 6, "watt": 6, "power": 6, "warm": 6, "room": 6, "everi": [6, 8, 13, 14], "hardwar": [6, 9], "interact": [6, 20], "o": 6, "draw": 6, "screen": 6, "driven": 6, "yourself": 6, "pai": 6, "someon": 6, "problem": [6, 11], "alreadi": 6, "solut": 6, "unix": 6, "pipe": 6, "sinc": [6, 7, 20], "assign": [6, 8, 23], "poll": 6, "mainten": 6, "give": [6, 13, 23], "io": [6, 19], "deliv": 6, "result": [6, 8, 14, 22, 23], "who": 6, "async": [6, 17], "thread": [6, 13], "invent": 6, "goal": 6, "serv": [6, 23], "line": [6, 7, 14, 22, 23], "default": [6, 8], "10": [6, 12, 13], "specifi": [6, 11, 13, 14, 23], "open": [6, 10, 17], "basic": [6, 12], "spawn": [6, 10], "technic": 6, "detail": [6, 13, 14, 19], "too": [7, 14, 15, 23], "mostli": 7, "layout": [7, 13, 19], "zone": 7, "game": 7, "chunk": [7, 13], "pre": 7, "beforehand": 7, "real": [7, 9, 10, 23], "simplic": [7, 8], "imagin": [7, 9], "simpl": [7, 8, 10, 13], "malloc": 7, "realloc": [7, 23], "": [7, 8, 10, 11, 12, 13, 14, 22], "done": [7, 8, 10, 13, 23], "complic": 7, "fight": 7, "import": 7, "understand": 7, "ert": 7, "erl_": 7, "those": 7, "strategi": [7, 8], "http": [7, 12, 15, 19, 23], "org": [7, 15, 23], "doc": [7, 15], "man": 7, "erts_alloc": [7, 23], "html": [7, 12, 15], "increment": [7, 14], "under": [7, 9, 13, 17, 18, 23], "No": 7, "bookkeep": 7, "track": 7, "belong": [7, 8, 12, 14, 16], "drop": [7, 14, 18], "come": [7, 8, 19, 23], "capac": 7, "threshold": 7, "someth": [7, 11], "75": 7, "bigger": 7, "extract": [7, 13, 14], "dead": 7, "end": [7, 8, 12, 13, 14], "pars": [7, 13], "split": [7, 14], "di": 7, "less": [7, 14, 23], "rememb": [7, 13, 23], "matur": 7, "finish": [7, 10, 17], "updat": [7, 14], "last": [7, 18], "amount": [7, 8, 10, 18, 23], "speed": [7, 20], "realiti": 7, "pictur": 7, "logic": [7, 13, 18], "appli": [7, 9, 10, 18, 23], "latenc": [7, 8, 20], "paus": 7, "topic": 7, "theori": 7, "gchandbook": 7, "depth": [7, 12, 19], "handl": [8, 12], "spawn_link": 8, "piec": [8, 9, 12, 16], "approx": 8, "200": 8, "300": 8, "1kb": 8, "initi": [8, 11], "grant": 8, "won": 8, "repeat": [8, 13, 14], "dai": 8, "month": 8, "death": 8, "involv": 8, "creation": [8, 16], "coupl": 8, "newli": 8, "yet": 8, "prioriti": 8, "99": 8, "pick": [8, 14], "newer": 8, "principl": [8, 23], "downward": 8, "th": [8, 14], "tail": [8, 14, 15, 18], "avoid": [8, 15, 22], "smarter": 8, "select": [8, 9], "wake": 8, "discov": [8, 11], "regular": [8, 9], "uncondit": 8, "By": [8, 14, 15], "manner": 8, "random": [8, 9], "configur": 8, "sp": 8, "bound": [8, 23], "sbt": 8, "max": [8, 13, 18, 22], "than": [8, 12, 13, 22, 23], "At": [8, 10, 16], "compar": [8, 14], "longer": [8, 22], "steal": 8, "scl": 8, "could": 8, "energi": 8, "spread": 8, "cut": [8, 14], "jump": [8, 12, 23], "identifi": 8, "common": [8, 9], "id": 8, "remot": 8, "resolv": [8, 14], "wherei": 8, "chain": [8, 16], "struct": [8, 16, 17, 18, 23], "nest": [8, 13], "advanc": [8, 14, 15, 16], "opcod": [8, 10, 12, 13, 18, 19], "mailbox": 8, "reset": [8, 14], "match": [8, 10, 13, 19], "lock": [8, 23], "destin": [8, 14], "add": [8, 14], "unlock": 8, "queu": 8, "arriv": 8, "idl": 8, "break": [8, 9], "sweat": 8, "interrupt": 8, "temporarili": 8, "state": [8, 9, 10, 14, 23], "again": [8, 14, 23], "encount": 8, "ve": [9, 10, 18, 19, 23], "heard": 9, "ordinari": 9, "method": 9, "rang": [9, 13, 18], "input": [9, 11, 17, 19], "definit": [9, 19, 22], "descript": [9, 11, 13, 22], "engin": [9, 20], "combin": [9, 12], "observ": 9, "show": 9, "moment": [9, 10, 22], "stop": [9, 14, 17], "shrink": 9, "attempt": [9, 23], "simplest": 9, "paramet": 9, "offer": 9, "proper": [9, 15], "quviq": 9, "quickcheck": 9, "commerci": 9, "boss": 9, "ask": 9, "fizz_buzz": 9, "clear": [9, 14], "fizz": 9, "divis": 9, "buzz": 9, "5": [9, 13], "fizbuzz": 9, "both": [9, 13], "x": [9, 11, 13, 14, 23], "rem": 9, "15": 9, "fizzbuzz": 9, "consult": 9, "syntax": 9, "ensur": [9, 11, 14, 17], "black": 9, "parallel": [9, 23], "toggl": 10, "produc": [10, 14, 18], "dbg": 10, "tracer": 10, "feed": 10, "overwhelm": 10, "irrelev": 10, "filter": 10, "tp": 10, "valv": 10, "p": [10, 12], "target": 10, "lifetim": 10, "everywher": [10, 18], "wrap": [10, 23], "somehow": 10, "entri": [10, 14, 18], "erts_bif_trac": 10, "correctli": 10, "describ": [11, 15, 18], "think": [11, 23], "violat": 11, "contradict": 11, "tool": [11, 23], "direct": [11, 12], "func_nam": 11, "arg": [11, 13, 14], "_": 11, "y": [11, 13, 14, 23], "neither": 11, "nor": 11, "prevent": [11, 22, 23], "typespec": 11, "manual": [11, 23], "book": 11, "learn": 11, "guess": 11, "infer": 11, "f": 11, "assumpt": 11, "whatev": 11, "widest": 11, "cover": [11, 17], "analyz": 11, "narrow": 11, "collaps": 11, "none": 11, "incompat": [11, 23], "report": [11, 13], "error": [11, 13, 14, 23], "confus": [11, 23], "given": [11, 14], "print": 11, "insert": 11, "futur": [11, 16], "legaci": [11, 14], "got": [12, 18], "bogdan": 12, "bj\u00f6rn": 12, "Being": 12, "expect": [12, 13], "rather": [12, 22], "1024": 12, "x0": 12, "x1": 12, "x2": 12, "overwrit": [12, 13], "lose": 12, "158": [12, 13, 14], "visibl": [12, 18, 22], "dump": 12, "assembli": 12, "erlc": 12, "yourfil": 12, "portabl": 12, "translat": [12, 13], "optimis": 12, "superinstruct": [12, 14], "beam_emu": [12, 14, 23], "format": [12, 18, 19, 20, 22], "void": 12, "goto": 12, "extens": [12, 23], "dispatch": [12, 23], "refus": 12, "support": [12, 23], "30": [12, 19], "slower": [12, 23], "exot": 12, "www": [12, 23], "toronto": 12, "edu": 12, "matz": 12, "dissert": 12, "matzdissert": 12, "latex2html": 12, "node6": 12, "multipl": [13, 18, 22, 23], "for1": 13, "iff": 13, "saniti": 13, "letter": [13, 22], "subsect": 13, "pad": 13, "align": [13, 23], "file_po": 13, "chunk_length": 13, "256": 13, "treat": 13, "latin1": 13, "utf8": 13, "charact": [13, 22], "m": 13, "discuss": 13, "ast": 13, "quick": 13, "get_abst": 13, "filenam": 13, "beam_lib": 13, "all_chunk": 13, "proplist": 13, "get_valu": 13, "nice": 13, "incomplet": 13, "untest": 13, "sure": 13, "fun_atom_index": 13, "nfree": 13, "frozen": [13, 14, 15, 18], "closur": [13, 15, 16], "ouniq": 13, "deflat": 13, "uncompress": 13, "output": [13, 17, 19], "buffer": [13, 23], "inflat": 13, "skip": 13, "ext": [13, 19], "essenti": 13, "func": 13, "navig": 13, "line_instr_count": 13, "num_line_ref": 13, "num_filenam": 13, "invalid": 13, "const": [13, 22, 23], "lineref": 13, "fname_index": 13, "fill": [13, 17], "u16": 13, "concaten": 13, "g": 13, "bs_put_str": 13, "applic": 13, "beam_asm": 13, "beam_dict": 13, "record": [13, 18], "asm": 13, "beam_disasm": 13, "info": 13, "space": [13, 14, 22], "stick": 13, "1st": 13, "7": 13, "shift": 13, "becom": [13, 14, 15, 23], "0b10111": 13, "0b100111": 13, "0b110111": 13, "0b1000111": 13, "16": 13, "entir": 13, "800": 13, "2048": 13, "neg": [13, 15], "greater": [13, 14], "tag_u": 13, "9": 13, "int": 13, "present": 13, "src": [13, 14], "beam_opcod": 13, "hrl": 13, "xregist": 13, "yregist": [13, 14], "plu": [13, 15], "floatreg": 13, "alloclist": 13, "11": [13, 20, 23], "12": [13, 16, 19], "smallint": 13, "ling": [13, 14], "slightli": [13, 22], "n": [13, 14], "case": [13, 14, 23], "unicod": 13, "val": 13, "r19": [13, 14], "handler": [13, 17], "queri": 13, "revisit": [13, 23], "complet": 14, "op": 14, "bundl": 14, "secondari": 14, "denot": 14, "bypass": 14, "mfariti": 14, "mod": [14, 18], "claus": 14, "fail": 14, "function_claus": 14, "appropri": 14, "spec": 14, "ip": 14, "importindex": 14, "dst": 14, "silent": 14, "arg1": 14, "arg2": 14, "arg3": 14, "valid": 14, "stackne": 14, "top": [14, 16], "heapne": 14, "restor": 14, "unlink": 14, "movabl": 14, "wait_timeout": 14, "fals": 14, "39": 14, "is_lt": 14, "40": 14, "is_g": 14, "41": 14, "is_eq": 14, "42": 14, "is_n": 14, "43": 14, "is_eq_exact": 14, "exactli": [14, 18], "44": 14, "is_ne_exact": 14, "58": 14, "test_ar": 14, "115": 14, "is_function2": 14, "45": 14, "is_integ": 14, "bignum": 14, "46": 14, "is_float": 14, "47": 14, "is_numb": 14, "48": 14, "is_atom": 14, "49": 14, "is_pid": 14, "50": 14, "is_refer": 14, "51": 14, "is_port": 14, "52": 14, "is_nil": 14, "53": 14, "is_binari": 14, "54": 14, "is_const": 14, "liter": [14, 16], "55": 14, "is_list": 14, "con": [14, 15, 19], "56": 14, "is_nonempty_list": 14, "57": 14, "is_tupl": 14, "77": 14, "is_funct": 14, "114": 14, "is_boolean": 14, "faillabel": 14, "odd": 14, "jumpt": 14, "naiv": 14, "meant": 14, "resumpt": 14, "catchend": 14, "counter": 14, "express": 14, "protect": 14, "preced": 14, "head": [14, 15, 16, 18], "item": 14, "forward": [14, 16], "step": [14, 16, 23], "badar": 14, "badfun": 14, "callabl": 14, "seem": [14, 22], "deprec": 14, "j": [14, 20, 23], "sz": 14, "sq": 14, "bitsiz": 14, "append": 14, "writabl": 14, "lambda": 14, "investig": 14, "propag": 14, "excvalu": 14, "second": 14, "bs_put": 14, "_remain": 14, "matchstat": [14, 15], "bs_start_match": 14, "sub": 14, "occasion": 14, "act": 14, "introduc": 14, "22": 14, "bs_start_match2": 14, "bs_": 14, "true": 14, "guid": [15, 19], "efficiency_guid": 15, "improp": [15, 18], "num_cel": 15, "opaqu": 15, "formula": 15, "map_header_ar": 15, "arityv": 15, "refvalu": 15, "subbinari": 15, "ref": 15, "ceil": 15, "log2": 15, "64bit": 15, "65": 15, "127bit": 15, "On": 15, "cours": 15, "surviv": 16, "occas": 16, "upgrad": 16, "purg": 16, "erts_garbage_collect_liter": 16, "erl_gc": 16, "mso": 16, "sweep": [16, 23], "through": [16, 23], "visit": 16, "refc": [16, 18], "action": 16, "taken": [16, 18], "destructor": 16, "strictli": 16, "addition": 16, "segment": 16, "enough": [16, 23], "consolid": 16, "merg": 16, "heap_start": 16, "erl_process": 16, "old_heap": 16, "backward": 16, "precalcul": 16, "puzzl": 16, "fibonacci": 16, "sequenc": 16, "38": 16, "23": 16, "total": 16, "erldrventri": 17, "erl_driv": 17, "emerg": 17, "timeout": 17, "erl_drv_entri": 17, "callback": 17, "howto": 17, "add_driver_entri": 17, "linker": 17, "indepth": 17, "seen": 18, "debugg": [18, 23], "occupi": 18, "_tag_immed1_pid": 18, "_tag_immed1_port": 18, "_tag_immed1_smal": 18, "_tag_immed1_immed2": 18, "_tag_immed2_atom": 18, "_tag_immed2_catch": 18, "_tag_immed2_nil": 18, "28": 18, "27": 18, "26": 18, "compat": 18, "car": 18, "cdr": 18, "terminologi": 18, "lisp": 18, "hand": 18, "reus": 18, "explan": 18, "arityval_subtag": 18, "make_arityv": 18, "arbitrari": 18, "modif": 18, "prove": 18, "intermedi": 18, "pos_big_subtag": 18, "neg_big_subtag": 18, "refth": 18, "ref_subtag": 18, "comment": [18, 22], "erlfunth": 18, "erl_fun": 18, "fun_subtag": 18, "creator": 18, "float_subtag": 18, "754": 18, "func_info": 18, "untag": 18, "breakpoint": 18, "destroi": [18, 23], "procbin": 18, "delet": 18, "smaller": [18, 19, 23], "directli": 18, "split_binari": 18, "articl": 19, "progress": 19, "repositori": 19, "page": [19, 20], "com": [19, 23], "kvakv": 19, "2019": 19, "03": 19, "2018": [19, 20], "nif": [19, 20], "properti": 19, "notic": 19, "relat": [19, 23], "style": 19, "benefit": 19, "refactor": [19, 23], "plenti": 20, "approach": 20, "integr": 20, "edtk": 20, "toolkit": 20, "dryverl": 20, "licens": 20, "bsd": 20, "mit": 20, "nifti": 20, "wrapper": 20, "epi": 20, "lgpl": 20, "eixx": 20, "apache2": 20, "nifpp": 20, "boost": 20, "erlua": 20, "erlualib": 20, "pyrlang": 20, "gevent": [], "erlport": 20, "erlang_pi": 20, "py_interfac": 20, "websit": 20, "pyerl": 20, "mpl": 20, "rustler": 20, "apach": 20, "nimler": 20, "toler": 20, "risk": 20, "choos": 20, "cloudi": 20, "privat": 20, "cloud": 20, "elixir": 20, "java": 20, "leak": 21, "hidden": 21, "c89": [22, 23], "indent": 22, "accept": 22, "contribut": 22, "git": 22, "commit": 22, "60": 22, "tree": 22, "perfectli": [22, 23], "though": 22, "bisect": 22, "inclus": 22, "__modulename_h__": 22, "__modulename_h": 22, "pragma": 22, "sept": 22, "2016": [20, 22, 23], "uppercas": 22, "underscor": 22, "suggest": 22, "safeti": 22, "inlin": [22, 23], "erts_inlin": 22, "erts_force_inlin": 22, "represent": 22, "desir": 22, "accordingli": 22, "lowercas": 22, "prefix": [22, 23], "undesir": 22, "consequ": 22, "api": 22, "camelcas": 22, "publicli": 22, "erts_": 22, "erts_gc_": 22, "ertsgc": 22, "renam": 22, "public": 22, "declar": 22, "scope": [22, 23], "bodi": 22, "strict": [22, 23], "uint64": 22, "uint32": 22, "sizabl": 22, "char": [22, 23], "mutabl": 22, "immut": 22, "_out": 22, "mistak": [22, 23], "ll": 22, "warn": 22, "miss": [22, 23], "my": 23, "person": 23, "thought": 23, "experi": 23, "transfer": 23, "brilliant": 23, "studi": 23, "daniel": 23, "garcia": 23, "b": 23, "stroustrup": 23, "maintain": 23, "isocpp": 23, "august": 23, "2015": 23, "branch": 23, "ratio": 23, "success": 23, "stori": 23, "mame": 23, "arcad": 23, "modern": 23, "youtub": 23, "watch": 23, "waunuwyaa5": 23, "intro": 23, "till": 23, "26min": 23, "convers": 23, "window": 23, "pain": 23, "msvc": 23, "gcc": 23, "fall": 23, "microsoft": 23, "invest": 23, "clang": 23, "fine": 23, "transit": 23, "gradual": 23, "rtti": 23, "disabl": 23, "constexpr": 23, "namespac": 23, "enum": 23, "bug": 23, "abus": 23, "collis": 23, "accid": 23, "memcpi": 23, "invit": 23, "mind": 23, "rewrit": 23, "safe": 23, "std": 23, "correct": 23, "altern": 23, "highli": 23, "impract": 23, "safer": 23, "deduct": 23, "dealloc": 23, "unlik": 23, "immens": 23, "shorter": 23, "z": 23, "easier": 23, "nondescript": 23, "implicitli": 23, "duplic": 23, "templat": 23, "broken": 23, "r20": 23, "almost": 23, "ident": 23, "aggress": 23, "stricter": 23, "ground": 23, "footprint": 23, "remad": 23, "smart": 23, "degrad": 23, "qualiti": 23, "raii": 23, "With": 23, "enforc": 23, "convolut": 23, "thorough": 23, "transpar": 23, "bad": 23, "vari": 23, "degre": 23, "One": 23, "keyword": 23, "cast": 23, "script": 23, "mend": 23, "w5z4jlmj1vq": 23, "cppcon": 23, "tim": 23, "hain": 23, "2023": 19, "06": 19, "18": 19, "readthedoc": 19, "migrat": 19, "asyncio": 20}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"beam": [0, 12, 13, 14, 15], "definit": 0, "atom": [1, 13], "eli5": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 19], "bif": 2, "nif": 2, "function": [2, 13, 22], "effici": 3, "data": [3, 4, 15, 18], "copi": 3, "liter": [3, 13], "constant": 3, "memori": [4, 18], "perform": [4, 23], "local": [4, 13], "cach": 4, "miss": 4, "type": [4, 11, 18, 22, 23], "immedi": [4, 15, 18], "valu": [4, 13, 18], "list": [4, 15, 18], "tupl": [4, 15, 18], "float": [4, 15, 18], "et": 4, "tabl": [4, 13, 14], "extern": 5, "term": [5, 13], "format": [5, 13], "input": 6, "output": 6, "port": [6, 17, 18, 20], "task": 6, "driver": [6, 17], "process": [7, 8, 16], "heap": [7, 16, 18], "carrier": 7, "alloc": [7, 14], "insid": 7, "garbag": 7, "collect": 7, "gener": [8, 22, 23], "overview": 8, "spawn": 8, "new": 8, "actor": 8, "stack": 8, "execut": 8, "kill": 8, "exit": 8, "schedul": 8, "load": 8, "balanc": 8, "registri": 8, "messag": 8, "queue": 8, "send": [8, 14], "trap": 8, "properti": 9, "base": [9, 13], "test": 9, "exampl": 9, "trace": 10, "inner": 10, "work": [10, 11], "spec": 11, "dialyz": 11, "how": [11, 16, 17, 23], "thi": 11, "typer": 11, "vm": 12, "regist": 12, "call": [12, 14], "instruct": [12, 14], "thread": 12, "loop": 12, "file": 13, "section": [13, 19], "atu8": 13, "code": [13, 14, 22, 23], "compil": [13, 23], "bytecod": 13, "abst": 13, "abstract": 13, "syntax": 13, "tree": 13, "catt": 13, "catch": [13, 14], "funt": 13, "lambda": 13, "expt": 13, "export": [13, 18], "litt": 13, "impt": 13, "import": 13, "loct": 13, "line": 13, "number": 13, "strt": 13, "string": 13, "attr": 13, "attribut": 13, "compact": 13, "encod": 13, "extend": 13, "tag": 13, "read": 13, "opcod": 14, "2": [14, 18], "func_info": 14, "4": [14, 18], "5": [14, 18], "call_last": 14, "6": [14, 18], "call_onli": 14, "7": [14, 18], "call_ext": 14, "8": [14, 18], "call_ext_last": 14, "9": [14, 18], "bif0": 14, "10": [14, 18], "bif1": 14, "11": 14, "bif2": 14, "152": 14, "bif3": 14, "12": [14, 18], "14": [14, 18], "allocate_zero": 14, "13": [14, 18], "allocate_heap": 14, "15": 14, "allocate_heap_zero": 14, "16": 14, "test_heap": 14, "17": 14, "init": 14, "18": 14, "dealloc": 14, "19": 14, "return": 14, "20": 14, "21": 14, "remove_messag": 14, "23": 14, "loop_rec": 14, "24": 14, "loop_rec_end": 14, "25": 14, "wait": 14, "comparison": 14, "guard": [14, 22], "59": 14, "select_v": 14, "60": 14, "select_tuple_ar": 14, "61": 14, "jump": 14, "62": 14, "63": 14, "catch_end": 14, "64": 14, "move": 14, "65": 14, "get_list": 14, "66": 14, "get_tuple_el": 14, "69": 14, "put_list": 14, "70": 14, "put_tupl": 14, "71": 14, "put": 14, "72": 14, "badmatch": 14, "73": 14, "if_claus": 14, "74": 14, "case_claus": 14, "75": 14, "call_fun": 14, "76": 14, "make_fun": 14, "78": 14, "call_ext_onli": 14, "89": 14, "bs_put_integ": 14, "103": 14, "make_fun2": 14, "104": 14, "try": 14, "105": 14, "try_end": 14, "1": 14, "106": 14, "try_cas": 14, "107": 14, "try_case_end": 14, "108": 14, "rais": 14, "109": 14, "bs_init2": 14, "112": 14, "appli": 14, "113": 14, "apply_last": 14, "136": 14, "trim": 14, "binari": [14, 18], "match": [14, 18], "oper": 14, "119": 14, "bs_get_binary2": 14, "166": 14, "bs_start_match3": 14, "121": 14, "bs_test_tail2": 14, "intern": 15, "size": 15, "box": [15, 18], "header": [15, 18, 22], "big": 15, "integ": 15, "layout": [16, 18], "grow": 16, "io": 17, "erlang": [17, 20, 22], "look": 17, "like": [17, 19], "make": 17, "todo": [17, 19], "con": 18, "arityv": 18, "0": 18, "bignum": 18, "neg": 18, "pos_big": 18, "3": 18, "refer": 18, "ref": 18, "fun": 18, "closur": 18, "count": 18, "refc_binari": 18, "heap_binari": 18, "sub": 18, "sub_binari": 18, "context": 18, "ext": 18, "pid": 18, "external_ref": 18, "welcom": 19, "adventur": 19, "latest": 19, "explain": 19, "me": 19, "i": [19, 23], "m": 19, "five": 19, "deeper": 19, "knowledg": 19, "interfac": 20, "outer": 20, "world": 20, "nativ": 20, "librari": 20, "c": [20, 23], "lua": 20, "python": 20, "rubi": 20, "php": 20, "rust": 20, "nim": 20, "javascript": 20, "perl": 20, "network": 20, "thing": 21, "refactor": 21, "otp": [21, 22, 23], "sourc": [22, 23], "style": 22, "guid": 22, "version": 22, "control": 22, "system": 22, "The": 22, "defin": 22, "name": 22, "macro": 22, "variabl": 22, "convent": 22, "argument": 22, "pass": 22, "would": 23, "benefit": 23, "from": 23, "portabl": 23, "compat": 23, "time": 23, "everywher": 23, "safeti": 23, "divid": 23, "rule": 23, "hard": 23, "To": 23, "migrat": 23}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx": 57}, "alltitles": {"BEAM Definitions": [[0, "beam-definitions"]], "Atoms ELI5": [[1, "atoms-eli5"]], "BIF and NIF functions ELI5": [[2, "bif-and-nif-functions-eli5"]], "BIF Functions": [[2, "bif-functions"]], "NIF Functions": [[2, "nif-functions"]], "Efficiency ELI5": [[3, "efficiency-eli5"]], "Data copying": [[3, "data-copying"]], "Literals (Constants)": [[3, "literals-constants"]], "Memory Performance ELI5": [[4, "memory-performance-eli5"]], "Data Locality": [[4, "data-locality"]], "Cache Miss": [[4, "cache-miss"]], "Data Types": [[4, "data-types"]], "Immediate Values": [[4, "immediate-values"]], "Lists": [[4, "lists"]], "Tuples": [[4, "tuples"]], "Floats": [[4, "floats"]], "ETS Tables": [[4, "ets-tables"]], "External Term Format ELI5": [[5, "external-term-format-eli5"]], "Input/Output and Ports ELI5": [[6, "input-output-and-ports-eli5"]], "Port Tasks": [[6, "port-tasks"]], "Port Driver": [[6, "port-driver"]], "Process Heaps ELI5": [[7, "process-heaps-eli5"]], "Heap Carriers": [[7, "heap-carriers"]], "Allocating Inside Heap": [[7, "allocating-inside-heap"]], "Garbage Collection": [[7, "garbage-collection"]], "Processes ELI5": [[8, "processes-eli5"]], "General overview": [[8, "general-overview"]], "Spawning a new Process (Actor)": [[8, "spawning-a-new-process-actor"]], "Stack": [[8, "stack"]], "Execution": [[8, "execution"]], "Killing and Exiting": [[8, "killing-and-exiting"]], "Scheduling and Load balancing": [[8, "scheduling-and-load-balancing"]], "Process Registry": [[8, "process-registry"]], "Message Queues": [[8, "message-queues"]], "Sending a Message": [[8, "sending-a-message"]], "Traps": [[8, "traps"]], "Property Based Testing ELI5": [[9, "property-based-testing-eli5"]], "Example": [[9, "example"]], "Tracing ELI5": [[10, "tracing-eli5"]], "Inner Workings of the Tracing": [[10, "inner-workings-of-the-tracing"]], "Types ELI5": [[11, "types-eli5"]], "Type Specs": [[11, "type-specs"]], "Dialyzer": [[11, "dialyzer"]], "How This Works": [[11, "how-this-works"]], "Typer": [[11, "typer"]], "BEAM VM ELI5": [[12, "beam-vm-eli5"]], "Registers and Calls": [[12, "registers-and-calls"]], "Instructions": [[12, "instructions"]], "Threaded VM Loop": [[12, "threaded-vm-loop"]], "BEAM File Format": [[13, "beam-file-format"]], "Sections": [[13, "sections"]], "\u201cAtom\u201d and \u201cAtU8\u201d - Atoms Table": [[13, "atom-and-atu8-atoms-table"]], "\u201cCode\u201d - Compiled Bytecode": [[13, "code-compiled-bytecode"]], "\u201cAbst\u201d - Abstract Syntax Tree": [[13, "abst-abstract-syntax-tree"]], "\u201cCatT\u201d - Catch Table": [[13, "catt-catch-table"]], "\u201cFunT\u201d - Function/Lambda Table": [[13, "funt-function-lambda-table"]], "\u201cExpT\u201d - Exports Table": [[13, "expt-exports-table"]], "\u201cLitT\u201d - Literals Table": [[13, "litt-literals-table"]], "\u201cImpT\u201d - Imports Table": [[13, "impt-imports-table"]], "\u201cLocT\u201d - Local Functions": [[13, "loct-local-functions"]], "\u201cLine\u201d - Line Numbers Table": [[13, "line-line-numbers-table"]], "\u201cStrT\u201d - Strings Table": [[13, "strt-strings-table"]], "\u201cAttr\u201d - Attributes": [[13, "attr-attributes"]], "BEAM Compact Term Encoding": [[13, "beam-compact-term-encoding"]], "Base and Extended Tag": [[13, "base-and-extended-tag"]], "Reading the Value": [[13, "reading-the-value"]], "BEAM Code Section Format": [[13, "beam-code-section-format"]], "BEAM Instruction Codes": [[14, "beam-instruction-codes"]], "Opcode Table": [[14, "opcode-table"]], "#2 func_info": [[14, "func-info"]], "#4 call": [[14, "call"]], "#5 call_last": [[14, "call-last"]], "#6 call_only": [[14, "call-only"]], "#7 call_ext": [[14, "call-ext"]], "#8 call_ext_last": [[14, "call-ext-last"]], "#9 bif0": [[14, "bif0"]], "#10 bif1 #11 bif2 #152 bif3": [[14, "bif1-11-bif2-152-bif3"]], "#12 allocate #14 allocate_zero": [[14, "allocate-14-allocate-zero"]], "#13 allocate_heap #15 allocate_heap_zero": [[14, "allocate-heap-15-allocate-heap-zero"]], "#16 test_heap": [[14, "test-heap"]], "#17 init": [[14, "init"]], "#18 deallocate": [[14, "deallocate"]], "#19 return": [[14, "return"]], "#20 send": [[14, "send"]], "#21 remove_message": [[14, "remove-message"]], "#23 loop_rec": [[14, "loop-rec"]], "#24 loop_rec_end": [[14, "loop-rec-end"]], "#25 wait": [[14, "wait"]], "Comparisons": [[14, "comparisons"]], "Guards as Opcodes": [[14, "guards-as-opcodes"]], "#59 select_val": [[14, "select-val"]], "#60 select_tuple_arity": [[14, "select-tuple-arity"]], "#61 jump": [[14, "jump"]], "#62 catch": [[14, "catch"]], "#63 catch_end": [[14, "catch-end"]], "#64 move": [[14, "move"]], "#65 get_list": [[14, "get-list"]], "#66 get_tuple_element": [[14, "get-tuple-element"]], "#69 put_list": [[14, "put-list"]], "#70 put_tuple #71 put": [[14, "put-tuple-71-put"]], "#72 badmatch": [[14, "badmatch"]], "#73 if_clause": [[14, "if-clause"]], "#74 case_clause": [[14, "case-clause"]], "#75 call_fun": [[14, "call-fun"]], "#76 make_fun": [[14, "make-fun"]], "#78 call_ext_only": [[14, "call-ext-only"]], "#89 bs_put_integer/5": [[14, "bs-put-integer-5"]], "#103 make_fun2": [[14, "make-fun2"]], "#104 try/2": [[14, "try-2"]], "#105 try_end/1": [[14, "try-end-1"]], "#106 try_case/1": [[14, "try-case-1"]], "#107 try_case_end/1": [[14, "try-case-end-1"]], "#108 raise/2": [[14, "raise-2"]], "#109 bs_init2/6": [[14, "bs-init2-6"]], "#112 apply #113 apply_last": [[14, "apply-113-apply-last"]], "#136 trim": [[14, "trim"]], "Binary Matching and Operations": [[14, "binary-matching-and-operations"]], "#119 bs_get_binary2/7": [[14, "bs-get-binary2-7"]], "#166 bs_start_match3": [[14, "bs-start-match3"]], "#121 bs_test_tail2": [[14, "bs-test-tail2"]], "BEAM Internal data sizes": [[15, "beam-internal-data-sizes"]], "Immediate": [[15, "immediate"]], "List": [[15, "list"]], "Boxed": [[15, "boxed"], [18, "boxed"]], "Header": [[15, "header"]], "Tuple": [[15, "tuple"]], "Float": [[15, "float"]], "Big Integer": [[15, "big-integer"]], "Process Heap Layout": [[16, "process-heap-layout"]], "How Heap Grows": [[16, "how-heap-grows"]], "IO in Erlang": [[17, "io-in-erlang"]], "How a Driver Looks Like": [[17, "how-a-driver-looks-like"]], "Making a Port Driver": [[17, "making-a-port-driver"]], "Todo": [[17, "id1"], [19, "id1"]], "Data Types Memory Layout": [[18, "data-types-memory-layout"]], "Immediate values": [[18, "immediate-values"]], "Lists (Cons)": [[18, "lists-cons"]], "Headers": [[18, "headers"], [22, "headers"]], "Tuple (ARITYVAL=0)": [[18, "tuple-arityval-0"]], "Bignum (NEG=2/POS_BIG=3)": [[18, "bignum-neg-2-pos-big-3"]], "Reference (REF=4)": [[18, "reference-ref-4"]], "Fun/Closure (FUN=5)": [[18, "fun-closure-fun-5"]], "Float (FLOAT=6)": [[18, "float-float-6"]], "Export (EXPORT=7)": [[18, "export-export-7"]], "Reference-counted Binary (REFC_BINARY=8)": [[18, "reference-counted-binary-refc-binary-8"]], "Heap Binary (HEAP_BINARY=9)": [[18, "heap-binary-heap-binary-9"]], "Sub-binary (SUB_BINARY=10)": [[18, "sub-binary-sub-binary-10"]], "Match context": [[18, "match-context"]], "Ext Pid 12": [[18, "ext-pid-12"]], "Ext Port 13": [[18, "ext-port-13"]], "Ext Ref (EXTERNAL_REF=14)": [[18, "ext-ref-external-ref-14"]], "Welcome, adventurer!": [[19, "welcome-adventurer"]], "Latest": [[19, "latest"]], "ELI5 Section (Explain Me Like I\u2019m Five)": [[19, "eli5-section-explain-me-like-i-m-five"]], "Deeper Knowledge Section": [[19, "deeper-knowledge-section"]], "Things to Refactor in OTP": [[21, "things-to-refactor-in-otp"]], "Erlang/OTP Source Style Guide": [[22, "erlang-otp-source-style-guide"]], "General": [[22, "general"]], "Version Control System": [[22, "version-control-system"]], "The #define Guard": [[22, "the-define-guard"]], "Naming Macros": [[22, "naming-macros"]], "Naming Types": [[22, "naming-types"]], "Naming Functions": [[22, "naming-functions"]], "Naming Variables": [[22, "naming-variables"]], "Coding conventions": [[22, "coding-conventions"]], "Argument Passing": [[22, "argument-passing"]], "How OTP Source Would Benefit from C++": [[23, "how-otp-source-would-benefit-from-c"]], "Portability Benefits": [[23, "portability-benefits"]], "Code Benefits": [[23, "code-benefits"]], "Compatible with C": [[23, "compatible-with-c"]], "Compile-Time Everywhere": [[23, "compile-time-everywhere"]], "Type Safety": [[23, "type-safety"]], "Divide and Rule": [[23, "divide-and-rule"]], "Generic Code": [[23, "generic-code"]], "Performance and Safety": [[23, "performance-and-safety"]], "How Hard Is To Migrate": [[23, "how-hard-is-to-migrate"]], "Interfacing Erlang with the Outer World": [[20, "interfacing-erlang-with-the-outer-world"]], "Native Libraries": [[20, "native-libraries"]], "C": [[20, "c"]], "C++": [[20, "id1"]], "Lua": [[20, "lua"]], "Python": [[20, "python"]], "Ruby": [[20, "ruby"]], "PHP": [[20, "php"]], "Rust": [[20, "rust"]], "Nim": [[20, "nim"]], "Javascript": [[20, "javascript"]], "Perl": [[20, "perl"]], "Ports and Network": [[20, "ports-and-network"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index 5643391..679e05c 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -11,6 +11,7 @@ Github repository for pages https://github.com/kvakvs/beam-wisdoms Latest `````` +* 2024-03-26 Migrate to Hetzner Webhosting (certificate problem). * 2023-06-18 Leave readthedocs and migrate to Github pages. * 2019-03-03 Binary match opcodes added to the instruction list. * 2018-12-30 Try/catch opcodes added to the instruction list.