225 lines
12 KiB
HTML
225 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<!-- Created by GNU Texinfo 7.1, https://www.gnu.org/software/texinfo/ -->
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<!-- This manual documents Guile version 3.0.10.
|
|
|
|
Copyright (C) 1996-1997, 2000-2005, 2009-2023 Free Software Foundation,
|
|
Inc.
|
|
|
|
Copyright (C) 2021 Maxime Devos
|
|
|
|
Copyright (C) 2024 Tomas Volf
|
|
|
|
|
|
Permission is granted to copy, distribute and/or modify this document
|
|
under the terms of the GNU Free Documentation License, Version 1.3 or
|
|
any later version published by the Free Software Foundation; with no
|
|
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
|
|
copy of the license is included in the section entitled "GNU Free
|
|
Documentation License." -->
|
|
<title>VM Programs (Guile Reference Manual)</title>
|
|
|
|
<meta name="description" content="VM Programs (Guile Reference Manual)">
|
|
<meta name="keywords" content="VM Programs (Guile Reference Manual)">
|
|
<meta name="resource-type" content="document">
|
|
<meta name="distribution" content="global">
|
|
<meta name="Generator" content=".texi2any-real">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
|
|
<link href="index.html" rel="start" title="Top">
|
|
<link href="Concept-Index.html" rel="index" title="Concept Index">
|
|
<link href="index.html#SEC_Contents" rel="contents" title="Table of Contents">
|
|
<link href="A-Virtual-Machine-for-Guile.html" rel="up" title="A Virtual Machine for Guile">
|
|
<link href="Object-File-Format.html" rel="next" title="Object File Format">
|
|
<link href="Variables-and-the-VM.html" rel="prev" title="Variables and the VM">
|
|
<style type="text/css">
|
|
<!--
|
|
a.copiable-link {visibility: hidden; text-decoration: none; line-height: 0em}
|
|
div.example {margin-left: 3.2em}
|
|
span:hover a.copiable-link {visibility: visible}
|
|
-->
|
|
</style>
|
|
<link rel="stylesheet" type="text/css" href="https://www.gnu.org/software/gnulib/manual.css">
|
|
|
|
|
|
</head>
|
|
|
|
<body lang="en">
|
|
<div class="subsection-level-extent" id="VM-Programs">
|
|
<div class="nav-panel">
|
|
<p>
|
|
Next: <a href="Object-File-Format.html" accesskey="n" rel="next">Object File Format</a>, Previous: <a href="Variables-and-the-VM.html" accesskey="p" rel="prev">Variables and the VM</a>, Up: <a href="A-Virtual-Machine-for-Guile.html" accesskey="u" rel="up">A Virtual Machine for Guile</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
|
|
</div>
|
|
<hr>
|
|
<h4 class="subsection" id="Compiled-Procedures-are-VM-Programs"><span>9.3.5 Compiled Procedures are VM Programs<a class="copiable-link" href="#Compiled-Procedures-are-VM-Programs"> ¶</a></span></h4>
|
|
|
|
<p>By default, when you enter in expressions at Guile’s REPL, they are
|
|
first compiled to bytecode. Then that bytecode is executed to produce a
|
|
value. If the expression evaluates to a procedure, the result of this
|
|
process is a compiled procedure.
|
|
</p>
|
|
<p>A compiled procedure is a compound object consisting of its bytecode and
|
|
a reference to any captured lexical variables. In addition, when a
|
|
procedure is compiled, it has associated metadata written to side
|
|
tables, for instance a line number mapping, or its docstring. You can
|
|
pick apart these pieces with the accessors in <code class="code">(system vm
|
|
program)</code>. See <a class="xref" href="Compiled-Procedures.html">Compiled Procedures</a>, for a full API reference.
|
|
</p>
|
|
<p>A procedure may reference data that was statically allocated when the
|
|
procedure was compiled. For example, a pair of immediate objects
|
|
(see <a class="pxref" href="Immediate-Objects.html">Immediate Objects</a>) can be allocated directly in the memory
|
|
segment that contains the compiled bytecode, and accessed directly by
|
|
the bytecode.
|
|
</p>
|
|
<p>Another use for statically allocated data is to serve as a cache for a
|
|
bytecode. Top-level variable lookups are handled in this way; the first
|
|
time a top-level binding is referenced, the resolved variable will be
|
|
stored in a cache. Thereafter all access to the variable goes through
|
|
the cache cell. The variable’s value may change in the future, but the
|
|
variable itself will not.
|
|
</p>
|
|
<p>We can see how these concepts tie together by disassembling the
|
|
<code class="code">foo</code> function we defined earlier to see what is going on:
|
|
</p>
|
|
<div class="example smallexample">
|
|
<pre class="example-preformatted">scheme@(guile-user)> (define (foo a) (lambda (b) (vector foo a b)))
|
|
scheme@(guile-user)> ,x foo
|
|
Disassembly of #<procedure foo (a)> at #xf1da30:
|
|
|
|
0 (instrument-entry 164) at (unknown file):5:0
|
|
2 (assert-nargs-ee/locals 2 1) ;; 3 slots (1 arg)
|
|
3 (allocate-words/immediate 2 3) at (unknown file):5:16
|
|
4 (load-u64 0 0 65605)
|
|
7 (word-set!/immediate 2 0 0)
|
|
8 (load-label 0 7) ;; anonymous procedure at #xf1da6c
|
|
10 (word-set!/immediate 2 1 0)
|
|
11 (scm-set!/immediate 2 2 1)
|
|
12 (reset-frame 1) ;; 1 slot
|
|
13 (handle-interrupts)
|
|
14 (return-values)
|
|
|
|
----------------------------------------
|
|
Disassembly of anonymous procedure at #xf1da6c:
|
|
|
|
0 (instrument-entry 183) at (unknown file):5:16
|
|
2 (assert-nargs-ee/locals 2 3) ;; 5 slots (1 arg)
|
|
3 (static-ref 2 152) ;; #<variable 112e530 value: #<procedure foo (a)>>
|
|
5 (immediate-tag=? 2 7 0) ;; heap-object?
|
|
7 (je 19) ;; -> L2
|
|
8 (static-ref 2 119) ;; #<directory (guile-user) ca9750>
|
|
10 (static-ref 1 127) ;; foo
|
|
12 (call-scm<-scm-scm 2 2 1 40)
|
|
14 (immediate-tag=? 2 7 0) ;; heap-object?
|
|
16 (jne 8) ;; -> L1
|
|
17 (scm-ref/immediate 0 2 1)
|
|
18 (immediate-tag=? 0 4095 2308) ;; undefined?
|
|
20 (je 4) ;; -> L1
|
|
21 (static-set! 2 134) ;; #<variable 112e530 value: #<procedure foo (a)>>
|
|
23 (j 3) ;; -> L2
|
|
L1:
|
|
24 (throw/value 1 151) ;; #(unbound-variable #f "Unbound variable: ~S")
|
|
L2:
|
|
26 (scm-ref/immediate 2 2 1)
|
|
27 (allocate-words/immediate 1 4) at (unknown file):5:28
|
|
28 (load-u64 0 0 781)
|
|
31 (word-set!/immediate 1 0 0)
|
|
32 (scm-set!/immediate 1 1 2)
|
|
33 (scm-ref/immediate 4 4 2)
|
|
34 (scm-set!/immediate 1 2 4)
|
|
35 (scm-set!/immediate 1 3 3)
|
|
36 (mov 4 1)
|
|
37 (reset-frame 1) ;; 1 slot
|
|
38 (handle-interrupts)
|
|
39 (return-values)
|
|
</pre></div>
|
|
|
|
<p>The first thing to notice is that the bytecode is at a fairly low level.
|
|
When a program is compiled from Scheme to bytecode, it is expressed in
|
|
terms of more primitive operations. As such, there can be more
|
|
instructions than you might expect.
|
|
</p>
|
|
<p>The first chunk of instructions is the outer <code class="code">foo</code> procedure. It
|
|
is followed by the code for the contained closure. The code can look
|
|
daunting at first glance, but with practice it quickly becomes
|
|
comprehensible, and indeed being able to read bytecode is an important
|
|
step to understanding the low-level performance of Guile programs.
|
|
</p>
|
|
<p>The <code class="code">foo</code> function begins with a prelude. The
|
|
<code class="code">instrument-entry</code> bytecode increments a counter associated with
|
|
the function. If the counter reaches a certain threshold, Guile will
|
|
emit machine code (“JIT-compile”) for <code class="code">foo</code>. Emitting machine
|
|
code is fairly cheap but it does take time, so it’s not something you
|
|
want to do for every function. Using a per-function counter and a
|
|
global threshold allows Guile to spend time JIT-compiling only the
|
|
“hot” functions.
|
|
</p>
|
|
<p>Next in the prelude is an argument-checking instruction, which checks
|
|
that it was called with only 1 argument (plus the callee function itself
|
|
makes 2) and then reserves stack space for an additional 1 local.
|
|
</p>
|
|
<p>Then from <code class="code">ip</code> 3 to 11, we allocate a new closure by allocating a
|
|
three-word object, initializing its first word to store a type tag,
|
|
setting its second word to its code pointer, and finally at <code class="code">ip</code>
|
|
11, storing local value 1 (the <code class="code">a</code> argument) into the third word
|
|
(the first free variable).
|
|
</p>
|
|
<p>Before returning, <code class="code">foo</code> “resets the frame” to hold only one local
|
|
(the return value), runs any pending interrupts (see <a class="pxref" href="Asyncs.html">Asynchronous Interrupts</a>) and
|
|
then returns.
|
|
</p>
|
|
<p>Note that local variables in Guile’s virtual machine are usually
|
|
addressed relative to the stack pointer, which leads to a pleasantly
|
|
efficient <code class="code">sp[<var class="var">n</var>]</code> access. However it can make the
|
|
disassembly hard to read, because the <code class="code">sp</code> can change during the
|
|
function, and because incoming arguments are relative to the <code class="code">fp</code>,
|
|
not the <code class="code">sp</code>.
|
|
</p>
|
|
<p>To know what <code class="code">fp</code>-relative slot corresponds to an
|
|
<code class="code">sp</code>-relative reference, scan up in the disassembly until you get
|
|
to a “<var class="var">n</var> slots” annotation; in our case, 3, indicating that the
|
|
frame has space for 3 slots. Thus a zero-indexed <code class="code">sp</code>-relative
|
|
slot of 2 corresponds to the <code class="code">fp</code>-relative slot of 0, which
|
|
initially held the value of the closure being called. This means that
|
|
Guile doesn’t need the value of the closure to compute its result, and
|
|
so slot 0 was free for re-use, in this case for the result of making a
|
|
new closure.
|
|
</p>
|
|
<p>A closure is code with data. As you can see, making the closure
|
|
involved making an object (<code class="code">ip</code> 3), putting a code pointer in it
|
|
(<code class="code">ip</code> 8 and 10), and putting in the closure’s free variable
|
|
(<code class="code">ip</code> 11).
|
|
</p>
|
|
<p>The second stanza disassembles the code for the closure. After the
|
|
prelude, all of the code between <code class="code">ip</code> 5 and 24 is related to
|
|
loading the toplevel variable <code class="code">foo</code> into slot 1. This lookup
|
|
happens only once, and is associated with a cache; after the first run,
|
|
the value in the cache will be a bound variable, and the code will jump
|
|
from <code class="code">ip</code> 7 to 26. On the first run, Guile gets the module
|
|
associated with the function, calls out to a run-time routine to look up
|
|
the variable, and checks that the variable is bound before initializing
|
|
the cache. Either way, <code class="code">ip</code> 26 dereferences the variable into
|
|
local 2.
|
|
</p>
|
|
<p>What follows is the allocation and initialization of the vector return
|
|
value. <code class="code">Ip</code> 27 does the allocation, and the following two
|
|
instructions initialize the type-and-length tag for the object’s first
|
|
word. <code class="code">Ip</code> 32 sets word 1 of the object (the first vector slot) to
|
|
the value of <code class="code">foo</code>; <code class="code">ip</code> 33 fetches the closure variable for
|
|
<code class="code">a</code>, then in <code class="code">ip</code> 34 stores it in the second vector slot; and
|
|
finally, in <code class="code">ip</code> 35, local <code class="code">b</code> is stored to the third vector
|
|
slot. This is followed by the return sequence.
|
|
</p>
|
|
|
|
</div>
|
|
<hr>
|
|
<div class="nav-panel">
|
|
<p>
|
|
Next: <a href="Object-File-Format.html">Object File Format</a>, Previous: <a href="Variables-and-the-VM.html">Variables and the VM</a>, Up: <a href="A-Virtual-Machine-for-Guile.html">A Virtual Machine for Guile</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
|
|
</div>
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|