diff --git a/chapters/beam.asciidoc b/chapters/beam.asciidoc index 939a485..65d8804 100644 --- a/chapters/beam.asciidoc +++ b/chapters/beam.asciidoc @@ -1,5 +1,5 @@ [[CH-BEAM]] -== The Erlang Virtual Machine: BEAM +== The Erlang Virtual Machine: BEAM BEAM (Bogumil's/Björn's Abstract Machine) is the machine that executes the code in the Erlang Runtime System. It is a garbage collecting, @@ -92,7 +92,6 @@ Great, you have built your first virtual machine! Handling subtraction, division and the rest of the Erlang language is left as an exercise for the reader. - Anyway, the BEAM is *not* a stack machine, it is a _register machine_. In a register machine instruction operands are stored in registers instead of the stack, and the result of an operation usually end up @@ -101,7 +100,7 @@ in a specific register. Most register machines do still have a stack used for passing arguments to functions and saving return addresses. BEAM has both a stack and registers, but just as in WAM the stack slots are accessible through -registers called Y-registers. BEAM also have a number of X-registers, +registers called Y-registers. BEAM also have a number of X-registers, and a special register X0 (sometimes also called R0) which works as an accumulator where results are stored. @@ -111,7 +110,7 @@ and register X0 is used for the return value. The X registers are stored in a C-array in the BEAM emulator and they are globally accessible from all functions. The X0 register is cached in a local variable mapped to a physical machine register in the native -machine on most architectures. +machine on most architectures. The Y registers are stored in the stack frame of the caller and only accessible by the calling functions. To save a value across a function @@ -119,10 +118,12 @@ call BEAM allocates a stack slot for it in the current stack frame and then moves the value to a Y register. [[x_and_y_regs_in_memory]] + +[shaape] ---- hend -> +----+ - - |....| - (fp) -> | AN | + |....| + (fp) -> | AN | (y0) -> | | (y1) -> | | stop -> | | diff --git a/chapters/compiler.asciidoc b/chapters/compiler.asciidoc index 323d517..b5b6d20 100644 --- a/chapters/compiler.asciidoc +++ b/chapters/compiler.asciidoc @@ -61,6 +61,7 @@ xref:fig_compiler_passes[Compiler Passes]. [[fig_compiler_passes]] .Compiler Passes. +[shaape] ---- [] = Compiler options, () = files, {} = erlang terms, boxes = passes (.erl) diff --git a/chapters/introduction.asciidoc b/chapters/introduction.asciidoc index 1ce809a..ad2c0ef 100644 --- a/chapters/introduction.asciidoc +++ b/chapters/introduction.asciidoc @@ -158,6 +158,7 @@ help you profile and optimize your application. In xref:CH-Crash[] and xref:CH-Debugger[] I'll give you some hints on how to find the cause of crashing applications and how to find bugs in your application. +[shaape] ---- Node1 Node2 @@ -336,6 +337,7 @@ is that there is no operating system in the Erlang on Xen stack. Since Ling implements the generic instruction set of BEAM, it can reuse the BEAM compiler from the OTP layer to compile Erlang to Ling. +[shaape] ---- Node1 Node2 Node2 Node3 @@ -368,6 +370,7 @@ to note here is that JVM has replaced BEAM as the virtual machine and that Erjang provides the services of ERTS by implementing them in Java on top of the VM. +[shaape] ---- Node1 Node2 Node3 Node4 diff --git a/chapters/memory.asciidoc b/chapters/memory.asciidoc index 5b9f262..929228b 100644 --- a/chapters/memory.asciidoc +++ b/chapters/memory.asciidoc @@ -11,6 +11,7 @@ compile on. A program's memory layout looks something like this: +[shaape] ---- high addresses @@ -306,6 +307,7 @@ of system flags below. Most allocators also have one "main multiblock carrier" which is never deallocated. +[shaape] ---- high addresses diff --git a/chapters/processes.asciidoc b/chapters/processes.asciidoc index b7c89c2..04b2b9a 100644 --- a/chapters/processes.asciidoc +++ b/chapters/processes.asciidoc @@ -418,6 +418,7 @@ of the process. See the following figure for an illustration of a process as memory: +[shaape] ---- +-------+ +-------+ | PCB | | Stack | @@ -695,6 +696,7 @@ with and which it will not shrink smaller than, the default value is We can now refine the picture of the process heap with the fields from the PCB that controls the shape of the heap: +[shaape] ---- hend -> +----+ - @@ -707,14 +709,13 @@ fields from the PCB that controls the shape of the heap: The Heap ---- - - But wait, how come we have a heap start and a heap end, but no start and stop for the stack? That is because the BEAM uses a trick to save space and pointers by allocating the heap and the stack together. It is time for our first revision of our process as memory picture. The heap and the stack are actually just one memory area: +[shaape] ---- +-------+ +-------+ | PCB | | Stack | @@ -725,11 +726,11 @@ heap and the stack are actually just one memory area: +-------+ +-------+ ---- - The stack grows towards lower memory addresses and the heap towards higher memory, so we can also refine the picture of the heap by adding the stack top pointer to the picture: +[shaape] ---- hend -> +----+ - |....| ^ @@ -788,9 +789,9 @@ each process: the old heap, handled by the fields `old_heap`, `old_htop` and `old_hend` in the PCB. This almost brings us back to our original picture of a process as four memory areas: +[shaape] ---- - +-------+ +-------+ | PCB | | Stack | +-------+ - old_hend +-------+ +-------+ + + - old_htop @@ -886,7 +887,7 @@ We can now revise our picture of the process as four memory areas once more. Now the process is made up of five memory areas (two mailboxes) and a varying number of heap fragments (`m-bufs`): - +[shaape] ---- +-------+ +-------+ @@ -1002,6 +1003,7 @@ consider messages sent between Erlang nodes. Imagine two processes `P1` and `P2`. Process `P1` wants to send a message (_Msg_) to process `P2`, as illustrated by this figure: +[shaape] ---- P 1 +---------------------------------+ @@ -1046,6 +1048,7 @@ send a message to `P2` and there is space on the heap and the allocation strategy is _on_heap_ the message will directly end up on the heap: +[shaape] ---- P 1 +---------------------------------+ @@ -1090,7 +1093,7 @@ If `P1` can not get the `main lock` of P2 or there is not enough space on `P2's` heap and the allocation strategy is _on_heap_ the message will end up in an `m-buf` but linked from the internal mailbox: - +[shaape] ---- P 1 +---------------------------------+ @@ -1225,7 +1228,6 @@ worse if all processes use off heap allocation. Then you might want to find bottle neck processes and test switching allocation strategies for those processes only. - === The Process Dictionary There is actually one more memory area in a process where Erlang terms can be stored, the _Process Dictionary_. @@ -1237,6 +1239,7 @@ and there is no copying as with send or an ETS table. We can now update our view of a process with yet another memory area, PD, the process dictionary: +[shaape] ---- +-------+ +-------+ +-------+ diff --git a/chapters/scheduling.asciidoc b/chapters/scheduling.asciidoc index 9e5d625..632e5a4 100644 --- a/chapters/scheduling.asciidoc +++ b/chapters/scheduling.asciidoc @@ -63,7 +63,6 @@ of processes _running_ in parallel and some processes that are _runnable_ but not currently running. We can see this with the function `erlang:process_info/2`. - ---- 1> Loop = fun (0, _) -> ok; (N, F) -> F(N-1, F) end, @@ -105,7 +104,6 @@ four schedulers are fully loaded while the busy processes execute. observer:start(). ok 3> RunThem(8). - ---- image::../images/observer_load.jpg[Observer] @@ -252,6 +250,7 @@ Machine. Events such as a timeout or a delivered message triggers transitions along the edges in the state machine. The _Process State Machine_ looks like this: +[shaape] ---- diff --git a/chapters/type_system.asciidoc b/chapters/type_system.asciidoc index f4a40b4..6186793 100644 --- a/chapters/type_system.asciidoc +++ b/chapters/type_system.asciidoc @@ -24,7 +24,9 @@ types, numbers have the sub types integer and float, and list has the subtypes nil and cons. (One could also argue that tuple has one subtype for each size.) -The Erlang Type Lattice +The Erlang Type Lattice + +[shaape] ---- any()