-
Notifications
You must be signed in to change notification settings - Fork 0
/
JOURNAL
236 lines (168 loc) · 8.55 KB
/
JOURNAL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#author Matthias Benkard
#date 2008-06-14 - <lisp>(format-time-string "%Y-%m-%d")</lisp>
#title Toilet Lisp Development Diary
#desc Random news and stuff about just another random pet project
; Time-stamp: <2008-08-11 02:35:35 mulk>
;
; C-c i t insert-time-stamp
; C-c C-t muse-project-publish-this-file
; C-c C-e muse-edit-link-at-point
; C-c C-i muse-insert-thing
----
Context: [[http://matthias.benkard.de/toilet][The Toilet Lisp Project]].
----
* 2008-10-02, 16:38:15 CEST
** Multiple-Value Returns
Multiple-value returns are now implemented in the most C-friendly way that I
can imagine. The way they work is:
- Every compiled function gets an additional argument that points to a cell
which the caller has allocated. The cell may be set to point to a list
(i.e., either =nil= or an instance of =MLKCons=) by the callee, in which
case the caller will use the list as the list of return values.
- The argument that points to the return value list cell may be =NULL=, in
which case the callee must assume a single-return convention.
- Return-value setting may be delegated to a subform by simply passing the
pointer on.
- The compiler always passes =NULL= as the list pointer when it neither uses
nor delegates the return values.
- The compiler occasionally sets the =llvm:Value= that represents the list
pointer to =NULL=. It thereby communicates to itself that no
multiple-return value handling is needed in the current lexical context.
This should speed some things up.
- A function implemented in C may choose to simply ignore the list pointer.
Similarly, it may choose to always pass a list pointer of =NULL= to callees
if it does not care about return values other than the primary one.
- A function that does not return multiple values simply ignores the list
pointer, which is guaranteed to contain a value that the caller can
identify as signifying that no multiple-value return has occurred.
In the current implementation, this role is filled by the
=MLKEndOfArgumentsMarker=.
- Regardless of multiple-value returns happening or not, the primary value of
a function call is always its normal return value. When there is no
primary value, =nil= is to be used.
* 2008-08-11, 02:09:21 CEST
** Function Calling, 2nd Take
More thoughts:
- Fat pointers are =MLKClosure= instances. =(funcall x a b c)= is compiled
into:
<example>
%tmp1 = x->code
%tmp2 = x->closure_data_pointer
tail call %tmp1 (%tmp2, a, b, c)
</example>
Of course, the =code= and =closure_data_pointer= ivar offsets have to be
known in advance, but that should be doable.
- Contrary to what I said earlier, I now think it should be possible to
not always require the use of varargs. Simply accept one more
argument than we really expect, then look for the end-of-arguments
marker in the supplied arguments. If it's there, determine whether
it's in an expected place (i.e. not at a position that a required
argument was expected at), if not, signal an error.
- It should also be possible to skip argument list checking entirely,
either by providing another thread-local flag or by putting the same
=BasicBlock= into two different functions so that there are two entry
points (a safe one and an unsafe one).
- **lambda** is just as dumb as **flet**: Neither operator causes an =MLKClosure=
object to be created at runtime. Both yield two values upon
compilation: a =Value*= that contains the closure data value at runtime
(i.e. the first argument of the function to call) and a code pointer.
Now, where do =MLKClosure= objects come from, then? Easy: **function** is
the one that creates them from all that information.
* 2008-08-06, 11:08:30 CEST
** Function Calling
I'm pondering function call conventions. My current design looks like this:
*** Entry Points
- For each function, provide two distinct entry points: a trampoline
for use by C code and the “direct” entry point.
- The direct entry point requires supplying the closure variable vector
to be passed explicitly as the first argument, while the trampoline
doesn't.
- The trampoline uses the normal C calling convention. The direct
entry point may use a different one (it's not clear to me that LLVM
allows such, though).
*** Arguments
- All functions are varargs, because there is no other way to ensure
the safety of passing more arguments than are expected. Should we
provide yet a third entry point for unsafe code?
- There is a thread-local global variable that controls the use of
multiple value returns. The caller sets it to 1 if they want to have
multiple values returned to them. In this case, the callee
immediately sets the variable to 0 again and before returning either
arranges for the thread-local variable to contain a pointer to a
vector of values (along with their number or an end-of-vector marker,
of course) or it leaves it as 0 if there is exactly one return value.
The caller is responsible for freeing the memory used by the return
vector.
*** Return Values
- (multiple-value-call ... (values ...)) is handled specially by the
compiler, because (values ...) isn't a function call.
*** Foreign Functions
- C functions may simply be placed in the global environment as-is as
long as they only take =id= arguments and return a single id value.
- Other C functions are wrapped in a Lisp-to-C trampoline that does the
needed conversions of arguments and return values.
* 2008-08-02, 13:46:14 CEST
** Exception Handling Crashes on Debian Systems
On Debian systems using the ffcall-compiled GNUstep Base libraries from
the **libgnustep-base1.16** package, an exception raised from within a
method called by way of an **NSInvocation** object causes the Objective-C
runtime to crash with a **SIGABRT** by calling **abort()** from
**objc_exception_throw()**.
Installing **libgnustep-base1.16-libffi** (which diverts the shared
libraries installed by **libgnustep-base1.16**) or compiling your own custom
version of GNUstep Base fixes the problem.
I have reported this bug as [[http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=493250][#493250]].
So if Toilet Lisp crashes when you type =(send 'a "isEqualToString:" 'b)=
at the REPL, please consider switching GNUstep Base installations. =sudo
apt-get install libgnustep-base1.16-libffi= should do the trick.
* 2008-07-27, 16:51:13 CEST
** DESTRUCTURING-BIND and DEFUN and DEFMACRO, Oh My!
We've now got **defun** and **defmacro** in all their lambda-list destructuring
glory. Finally!
So yeah, they're missing a bit of error handling here and there when
parsing lambda lists. Too permissive to be conforming. But hey, at
least your missing arguments will merely be =nil= instead of crashing the
interpreter (the hard way, I mean, not by catchable exceptions). Isn't
that an improvement?
* 2008-06-14, 16:41:55 CEST
** Another Random Piece of Vaporware is Born
Here I go again, starting yet another little pet software project whose
chance of surviving for more than a few months is limited, but hey, it'd
not be me if I didn't start bragging about it before having written even
a single line of code, right? So here we go!
I intend Mulklisp (which is obviously a preliminary, WebShaka-style
proto-name) to become a Lisp compiler for the Étoilé runtime (and maybe
Mac OS X as well, but that's of a lower priority) with the following
features:
- A proper subset of ANSI Common Lisp, with an eye towards full ANSI
compliance in the far future.
- CFFI support.
- Lexical **and** dynamic scoping.
- Integration with the Étoilé object system.
- DEFMACRO.
- Hygienic macros by way of Explicit Renaming and Syntactic Closures.
- Read macros. (?)
- TAGBODY and GO. (?)
- CATCH and THROW. (?)
- Places (that is, SETF).
- A package system.
- Arrays and hash tables compatible with their Common Lisp counterparts,
but based on the Étoilé/GNUstep ones.
- Direct compilation to Étoilé runtime code (as with Étoilé Smalltalk).
- A REPL.
- Conditions and restarts.
- Multiple namespaces.
- Bignums and rationals.
- JIT and explicit compilation (COMPILE) via LLVM. (?)
- Optional static typing with Cells-based/Hindley-Milner/whatever type
inference. (?)
Well, that's what I'm dreaming of. At least now you have something new
to joke about in place of Duke Nukem Forever (which is coming out
Practically Tomorrow! Preorder today!).
Maybe I ought to change my nickname from Kompottkin to Master Vaporware.
----
*Matthias Benkard, <lisp>(format-time-string "%Y-%m-%d, %k:%M %Z")</lisp>*
http://matthias.benkard.de/
; Local Variables:
; mode: muse
; End: