source: project/chicken/trunk/manual/Unit lolevel @ 13148

Last change on this file since 13148 was 13148, checked in by Kon Lovett, 11 years ago

distribution/manifest : added lolevel test
tests/lolevel-tests.scm : new lolevel test (incomplete)
runtime.c : MacOS X is-a BSD
lolevel.scm : better arg checks, grouping, added record-instance procs.
chicken.h : grouped like, comments, swig-pointer is now special
manual/Unit lolevel : discussion of pointer-like & vector-like
chicken-primitive-inlines.scm : wrond identifier for unbound value predicate

File size: 20.2 KB
Line 
1[[tags: manual internals]]
2[[toc:]]
3
4
5== Unit lolevel
6
7This unit provides a number of handy low-level operations. '''Use
8at your own risk.'''
9
10This unit uses the {{srfi-4}} and {{extras}} units.
11
12
13
14=== Foreign pointers
15
16The abstract class of ''pointer'' is divided into 2 categories:
17
18; ''pointer object'' : is a foreign pointer object, a tagged foreign pointer object (see {{Tagged pointers}}), or a SWIG-pointer.
19
20; ''pointer-like object'' " is a closure, port, locative (see {{Locatives}}, or a pointer object.
21
22SWIG-pointers are currently an issue due to "bitrot" in the SWIG Chicken
23translator. While they are considered a pointer object unexpected results are
24possible.
25
26Note that Locatives, while technically pointers, are not considered a ''pointer
27object'', but a ''pointer-like object''. The distinction is artificial.
28
29
30==== address->pointer
31
32 [procedure] (address->pointer ADDRESS)
33
34Creates a new foreign pointer object initialized to point to the address
35given in the integer {{ADDRESS}}.
36
37
38==== allocate
39
40 [procedure] (allocate BYTES)
41
42Returns a foreign pointer object to a freshly allocated region of static
43memory.
44
45This procedure could be defined as follows:
46
47<enscript highlight=scheme>
48(define allocate (foreign-lambda c-pointer "malloc" integer))
49</enscript>
50
51
52==== free
53
54 [procedure] (free POINTER)
55
56Frees the memory pointed to by {{POINTER}}.
57
58This procedure could be defined as follows:
59
60<enscript highlight=scheme>
61(define free (foreign-lambda void "free" c-pointer))
62</enscript>
63
64
65==== null-pointer
66
67 [procedure] (null-pointer)
68
69Another way to say {{(address->pointer 0)}}.
70
71
72==== null-pointer?
73
74 [procedure] (null-pointer? POINTER*)
75
76Returns {{#t}} if the pointer-like object {{POINTER*}} contains a {{NULL}} pointer,
77or {{#f}} otherwise.
78
79
80==== object->pointer
81
82 [procedure] (object->pointer X)
83
84Returns a foreign pointer object pointing to the Scheme object X, which should
85be a non-immediate object. ("foreign" here is a bit of a misnomer.)
86
87Note that data in the garbage collected heap moves during garbage collection.
88
89
90==== pointer->object
91
92 [procedure] (pointer->object POINTER)
93
94Returns the Scheme object pointed to by the pointer object {{POINTER}}.
95
96Whether the {{POINTER}} actually points to a Scheme object is not guaranteed. Use
97at your own risk.
98
99==== pointer?
100
101 [procedure] (pointer? X)
102
103Returns {{#t}} if {{X}} is a pointer object, or {{#f}} otherwise.
104
105
106==== pointer-like?
107
108 [procedure] (pointer-like? X)
109
110Returns {{#t}} if {{X}} is a pointer-like object, or {{#f}} otherwise.
111
112
113==== pointer=?
114
115 [procedure] (pointer=? POINTER*1 POINTER*2)
116
117Returns {{#t}} if the pointer-like objects {{POINTER*1}} and {{POINTER*2}} point
118to the same address, or {{#f}} otherwise.
119
120
121==== pointer->address
122
123 [procedure] (pointer->address POINTER*)
124
125Returns the address, to which the pointer-like object {{POINTER*}} points.
126
127
128==== pointer-offset
129
130 [procedure] (pointer-offset POINTER* N)
131
132Returns a new foreign pointer object representing the pointer-like object
133{{POINTER*}} address value increased by the byte-offset {{N}}.
134
135Use of anything other than a pointer object as an argument is questionable.
136
137
138==== align-to-word
139
140 [procedure] (align-to-word POINTER*-OR-INT)
141
142Accepts either a pointer-like object or an integer as the argument and returns
143a new foreign pointer or integer aligned to the native word size of the host
144platform.
145
146Use of anything other than an integer or pointer object as an argument is
147questionable.
148
149
150
151=== SRFI-4 Foreign pointers
152
153These procedures actually accept a pointer-like object as the {{POINTER}} argument.
154However, as usual, use of anything other than a pointer object is questionable.
155
156==== pointer-u8-ref
157
158 [procedure] (pointer-u8-ref POINTER)
159
160Returns the unsigned byte at the address designated by {{POINTER}}.
161
162
163==== pointer-s8-ref
164
165 [procedure] (pointer-s8-ref POINTER)
166
167Returns the signed byte at the address designated by {{POINTER}}.
168
169
170==== pointer-u16-ref
171
172 [procedure] (pointer-u16-ref POINTER)
173
174Returns the unsigned 16-bit integer at the address designated by {{POINTER}}.
175
176
177==== pointer-s16-ref
178
179 [procedure] (pointer-s16-ref POINTER)
180
181Returns the signed 16-bit integer at the address designated by {{POINTER}}.
182
183
184==== pointer-u32-ref
185
186 [procedure] (pointer-u32-ref POINTER)
187
188Returns the unsigned 32-bit integer at the address designated by {{POINTER}}.
189
190
191==== pointer-s32-ref
192
193 [procedure] (pointer-s32-ref POINTER)
194
195Returns the signed 32-bit integer at the address designated by {{POINTER}}.
196
197
198==== pointer-f32-ref
199
200 [procedure] (pointer-f32-ref POINTER)
201
202Returns the 32-bit float at the address designated by {{POINTER}}.
203
204
205==== pointer-f64-ref
206
207 [procedure] (pointer-f64-ref POINTER)
208
209Returns the 64-bit double at the address designated by {{POINTER}}.
210
211
212==== pointer-u8-set!
213
214 [procedure] (pointer-u8-set! POINTER N)
215 [procedure] (set! (pointer-u8-ref POINTER) N)
216
217Stores the unsigned byte {{N}} at the address designated by {{POINTER}}.
218
219
220==== pointer-s8-set!
221
222 [procedure] (pointer-s8-set! POINTER N)
223 [procedure] (set! (pointer-s8-ref POINTER) N)
224
225Stores the signed byte {{N}} at the address designated by {{POINTER}}.
226
227
228==== pointer-u16-set!
229
230 [procedure] (pointer-u16-set! POINTER N)
231 [procedure] (set! (pointer-u16-ref POINTER) N)
232
233Stores the unsigned 16-bit integer {{N}} at the address designated by {{POINTER}}.
234
235
236==== pointer-s16-set!
237
238 [procedure] (pointer-s16-set! POINTER N)
239 [procedure] (set! (pointer-s16-ref POINTER) N)
240
241Stores the signed 16-bit integer {{N}} at the address designated by {{POINTER}}.
242
243
244==== pointer-u32-set!
245
246 [procedure] (pointer-u32-set! POINTER N)
247 [procedure] (set! (pointer-u32-ref POINTER) N)
248
249Stores the unsigned 32-bit integer {{N}} at the address designated by {{POINTER}}.
250
251
252==== pointer-s32-set!
253
254 [procedure] (pointer-s32-set! POINTER N)
255 [procedure] (set! (pointer-s32-ref POINTER) N)
256
257Stores the 32-bit integer {{N}} at the address designated by {{POINTER}}.
258
259
260==== pointer-f32-set!
261
262 [procedure] (pointer-f32-set! POINTER N)
263 [procedure] (set! (pointer-f32-ref POINTER) N)
264
265Stores the 32-bit floating-point number {{N}} at the address designated by {{POINTER}}.
266
267
268==== pointer-f64-set!
269
270 [procedure] (pointer-f64-set! POINTER N)
271 [procedure] (set! (pointer-f64-ref POINTER) N)
272
273Stores the 64-bit floating-point number {{N}} at the address designated by {{POINTER}}.
274
275
276
277=== Tagged pointers
278
279''Tagged'' pointers are foreign pointer objects with an extra tag object.
280
281
282==== tag-pointer
283
284 [procedure] (tag-pointer POINTER* TAG)
285
286Creates a new tagged foreign pointer object from the pointer-like object
287{{POINTER*}} with the tag {{TAG}}, which may an arbitrary Scheme object.
288
289Use of anything other than a pointer object is questionable.
290
291==== tagged-pointer?
292
293 [procedure] (tagged-pointer? X [TAG])
294
295Returns {{#t}} if {{X}} is a tagged foreign pointer object, or {{#f}} otherwise.
296
297Further, returns {{#t}} when {{X}} has the optional tag {{TAG}} (using an
298{{equal?}} comparison), or {{#f}} otherwise.
299
300
301==== pointer-tag
302
303 [procedure] (pointer-tag POINTER*)
304
305If {{POINTER}} is a tagged foreign pointer object, its tag is returned. If {{POINTER*}}
306is any other kind of pointer-like object {{#f}} is returned. Otherwise an
307error is signalled.
308
309
310
311=== Locatives
312
313
314A ''locative'' is an object that points to an element of a containing object,
315much like a ''pointer'' in low-level, imperative programming languages like ''C''. The element can
316be accessed and changed indirectly, by performing access or change operations
317on the locative. The container object can be computed by calling the
318{{location->object}} procedure.
319
320Locatives may be passed to foreign procedures that expect pointer arguments.
321The effect of creating locatives for evicted data (see {{object-evict}}) is undefined.
322
323
324==== make-locative
325
326 [procedure] (make-locative OBJ [INDEX])
327
328Creates a locative that refers to the element of the non-immediate object
329{{OBJ}} at position {{INDEX}}. {{OBJ}} may be a vector, pair, string, blob,
330SRFI-4 number-vector, or record structure. {{INDEX}} should be a fixnum.
331{{INDEX}} defaults to 0.
332
333
334==== make-weak-locative
335
336 [procedure] (make-weak-locative OBJ [INDEX])
337
338Creates a ''weak'' locative. Even though the locative refers to an element of a container object,
339the container object will still be reclaimed by garbage collection if no other references
340to it exist.
341
342
343==== locative?
344
345 [procedure] (locative? X)
346
347Returns {{#t}} if {{X}} is a locative, or {{#f}} otherwise.
348
349
350==== locative-ref
351
352 [procedure] (locative-ref LOC)
353
354Returns the element to which the locative {{LOC}} refers. If the containing
355object has been reclaimed by garbage collection, an error is signalled.
356
357 (locative-ref (make-locative "abc" 1)) ==> #\b
358
359==== locative-set!
360
361 [procedure] (locative-set! LOC X)
362 [procedure] (set! (locative-ref LOC) X)
363
364Changes the element to which the locative {{LOC}} refers to {{X}}.
365If the containing
366object has been reclaimed by garbage collection, an error is signalled.
367
368
369==== locative->object
370
371 [procedure] (locative->object LOC)
372
373Returns the object that contains the element referred to by {{LOC}} or
374{{#f}} if the container has been reclaimed by garbage collection.
375
376 (locative->object (make-locative "abc" 1)) ==> "abc"
377
378
379
380=== Extending procedures with data
381
382
383==== extend-procedure
384
385 [procedure] (extend-procedure PROCEDURE X)
386
387Returns a copy of the procedure {{PROCEDURE}} which contains an additional data
388slot initialized to {{X}}. If {{PROCEDURE}} is already an extended procedure,
389then its data slot is changed to contain {{X}} and the same procedure is
390returned. Signals an error when {{PROCEDURE}} is not a procedure.
391
392
393==== extended-procedure?
394
395 [procedure] (extended-procedure? PROCEDURE)
396
397Returns {{#t}} if {{PROCEDURE}} is an extended procedure,
398or {{#f}} otherwise.
399
400
401==== procedure-data
402
403 [procedure] (procedure-data PROCEDURE)
404
405Returns the data object contained in the extended procedure {{PROCEDURE}}, or
406{{#f}} if it is not an extended procedure.
407
408
409==== set-procedure-data!
410
411 [procedure] (set-procedure-data! PROCEDURE X)
412
413Changes the data object contained in the extended procedure {{PROCEDURE}} to
414{{X}}. Signals an error when {{PROCEDURE}} is not an extended procedure.
415
416<enscript highlight=scheme>
417(define foo
418  (letrec ((f (lambda () (procedure-data x)))
419           (x #f) )
420    (set! x (extend-procedure f 123))
421    x) )
422(foo)                                         ==> 123
423(set-procedure-data! foo 'hello)
424(foo)                                         ==> hello
425</enscript>
426
427
428
429=== Low-level data access
430
431These procedures operate with what are known as {{vector-like objects}}. A
432{{vector-like object}} is a vector, record structure, pair, symbol or keyword.
433
434Note that strings and blobs are not considered vector-like.
435
436
437==== vector-like?
438
439 [procedure] (vector-like? X)
440
441Returns {{#t}} when {{X}} is a vector-like object, returns {{#f}}
442otherwise.
443
444
445==== block-ref
446
447 [procedure] (block-ref VECTOR* INDEX)
448
449Returns the contents of the {{INDEX}}th slot of the vector-like object
450{{VECTOR*}}.
451
452
453==== block-set!
454
455 [procedure] (block-set! VECTOR* INDEX X)
456 [procedure] (set! (block-ref VECTOR* INDEX) X)
457
458Sets the contents of the {{INDEX}}th slot of the vector-like object {{VECTOR*}}
459to the value of {{X}}.
460
461==== number-of-slots
462
463 [procedure] (number-of-slots VECTOR*)
464
465Returns the number of slots that the vector-like object {{VECTOR*}} contains.
466
467
468==== number-of-bytes
469
470 [procedure] (number-of-bytes BLOCK)
471
472Returns the number of bytes that the object {{BLOCK}} contains. {{BLOCK}} may
473be any non-immediate value.
474
475
476==== object-copy
477
478 [procedure] (object-copy X)
479
480Copies {{X}} recursively and returns the fresh copy. Objects allocated in
481static memory are copied back into garbage collected storage.
482
483
484==== move-memory!
485
486 [procedure] (move-memory! FROM TO [BYTES [FROM-OFFSET [TO-OFFSET]])
487
488Copies {{BYTES}} bytes of memory from {{FROM}} to {{TO}}. {{FROM}} and {{TO}}
489may be strings, blobs, SRFI-4 number-vectors (see: @ref{Unit srfi-4}), memory
490mapped files, foreign pointers (as obtained from a call to {{foreign-lambda}},
491for example), tagged-pointers or locatives. if {{BYTES}} is not given and the
492size of the source or destination operand is known then the maximal number of
493bytes will be copied. Moving memory to the storage returned by locatives will
494cause havoc, if the locative refers to containers of non-immediate data, like
495vectors or pairs.
496
497The additional fourth and fifth argument specify starting offsets (in bytes)
498for the source and destination arguments.
499
500Signals an error if any of the above constraints is violated.
501
502
503
504=== Data in unmanaged memory
505
506
507==== object-evict
508
509 [procedure] (object-evict X [ALLOCATOR])
510
511Copies the object {{X}} recursively into the memory pointed to by the foreign
512pointer object returned by {{ALLOCATOR}}, which should be a procedure of a
513single argument (the number of bytes to allocate). The freshly copied object is
514returned.
515
516This facility allows moving arbitrary objects into static memory, but care
517should be taken when mutating evicted data: setting slots in evicted
518vector-like objects to non-evicted data is not allowed. It '''is''' possible to
519set characters/bytes in evicted strings or byte-vectors, though.  It is
520advisable '''not''' to evict ports, because they might be mutated by certain
521file-operations.  {{object-evict}} is able to handle circular and shared
522structures, but evicted symbols are no longer unique: a fresh copy of the
523symbol is created, so
524
525<enscript highlight=scheme>
526(define x 'foo)
527(define y (object-evict 'foo))
528y                              ==> foo
529(eq? x y)                      ==> #f
530(define z (object-evict '(bar bar)))
531(eq? (car z) (cadr z))         ==> #t
532</enscript>
533
534The {{ALLOCATOR}} defaults to {{allocate}}.
535
536
537==== object-evict-to-location
538
539 [procedure] (object-evict-to-location X POINTER* [LIMIT])
540
541As {{object-evict}} but moves the object at the address pointed to by
542the pointer-like object {{POINTER*}}. If the number of copied bytes exceeds
543the optional {{LIMIT}} then an error is signalled (specifically a composite
544condition of types {{exn}} and {{evict}}. The latter provides
545a {{limit}} property which holds the exceeded limit. Two values are
546returned: the evicted object and a new pointer pointing to the first
547free address after the evicted object.
548
549Use of anything other than a pointer object as the {{POINTER*}} argument is
550questionable.
551
552==== object-evicted?
553
554 [procedure] (object-evicted? X)
555
556Returns {{#t}} if {{X}} is a non-immediate evicted data object, or {{#f}}
557otherwise.
558
559
560==== object-release
561
562 [procedure] (object-release X [RELEASER])
563
564Frees memory occupied by the evicted object {{X}} recursively.
565{{RELEASER}} should be a procedure of a single argument (a foreign
566pointer object to the static memory to be freed) and defaults to
567{{free}}.
568
569
570==== object-unevict
571
572 [procedure] (object-unevict X [FULL])
573
574Copies the object {{X}} and nested objects back into the normal Scheme heap.
575Symbols are re-interned into the symbol table. Strings and byte-vectors are
576'''not''' copied, unless {{FULL}} is given and not {{#f}}.
577
578
579==== object-size
580
581 [procedure] (object-size X)
582
583Returns the number of bytes that would be needed to evict the data object
584{{X}}.
585
586
587
588=== Accessing toplevel variables
589
590
591==== global-bound?
592
593 [procedure] (global-bound? SYMBOL)
594
595Returns {{#t}}, if the global (''toplevel'') variable with the name {{SYMBOL}}
596is bound to a value, or {{#f}} otherwise.
597
598
599==== global-ref
600
601 [procedure] (global-ref SYMBOL)
602
603Returns the value of the global variable {{SYMBOL}}.
604If no variable under that name is bound, an error is signalled.
605
606Note that it is not possible to access a toplevel binding with {{global-ref}} or
607{{global-set!}} if it has been hidden in compiled code via {{(declare (hide ...))}},
608or if the code has been compiled in {{block}} mode.
609
610
611==== global-set!
612
613 [procedure] (global-set! SYMBOL X)
614 [procedure] (set! (global-ref SYMBOL) X)
615
616Sets the global variable named {{SYMBOL}} to the value {{X}}.
617
618
619
620=== Record instance
621
622
623==== make-record-instance
624
625 [procedure] (make-record-instance SYMBOL ARG1 ...)
626
627Returns a new instance of the record type {{SYMBOL}}, with its
628slots initialized to {{ARG1 ...}}.  To illustrate:
629
630<enscript highlight=scheme>
631(define-record-type point (make-point x y) point?
632  (x point-x point-x-set!)
633  (y point-y point-y-set!))
634</enscript>
635
636expands into something quite similar to:
637
638<enscript highlight=scheme>
639(begin
640  (define (make-point x y)
641    (make-record-instance 'point x y) )
642  (define (point? x)
643    (and (record-instance? x)
644         (eq? 'point (block-ref x 0)) ) )
645  (define (point-x p) (block-ref p 1))
646  (define (point-x-set! p x) (block-set! p 1 x))
647  (define (point-y p) (block-ref p 2))
648  (define (point-y-set! p y) (block-set! p 1 y)) )
649</enscript>
650
651
652==== record-instance?
653
654 [procedure] (record-instance? X [SYMBOL])
655
656Returns {{#t}} if {{X}} is a record structure, or {{#f}} otherwise.
657
658Further, returns {{#t}} if {{X}} is of type {{SYMBOL}}, or {{#f}} otherwise.
659
660
661==== record-instance-type
662
663 [procedure] (record-instance-type RECORD)
664
665Returns type symbol of the record structure {{RECORD}}. Signals an error if
666{{RECORD}} is not a record structure.
667
668
669==== record-instance-length
670
671 [procedure] (record-instance-length RECORD)
672
673Returns number of slots for the record structure {{RECORD}}. The
674record-instance type is not counted. Signals an error if
675{{RECORD}} is not a record structure.
676
677
678==== record-instance-slot
679
680 [procedure] (record-instance-slot RECORD INDEX)
681
682Returns the contents of the {{INDEX}}th slot of the record structure
683{{RECORD}}. The slot index range is the open interval (([0
684record-instance-length)}}. Signals an error if {{RECORD}} is not a record
685structure.
686
687
688==== record-instance-slot-set!
689
690 [procedure] (record-instance-slot-set! RECORD INDEX X)
691 [procedure] (set! (record-instance-slot RECORD INDEX) X)
692
693Sets the {{INDEX}}th slot of the record structure {{RECORD}} to {{X}}. The slot
694index range is the open interval (([0 record-instance-length)}}. Signals an
695error if {{RECORD}} is not a record structure.
696
697
698==== record->vector
699
700 [procedure] (record->vector RECORD)
701
702Returns a new vector with the type and the elements of the record structure
703{{RECORD}}. Signals an error if {{RECORD}} is not a record structure.
704
705
706
707=== Procedure-call- and variable reference hooks
708
709
710==== set-invalid-procedure-call-handler!
711
712 [procedure] (set-invalid-procedure-call-handler! PROC)
713
714Sets an internal hook that is invoked when a call to an object other than a
715procedure is executed at runtime. The procedure {{PROC}} will in that case be
716called with two arguments: the object being called and a list of the passed
717arguments.
718
719<enscript highlight=scheme>
720;;; Access sequence-elements as in ARC:
721
722(set-invalid-procedure-call-handler!
723  (lambda (proc args)
724    (cond [(string? proc) (apply string-ref proc args)]
725          [(vector? proc) (apply vector-ref proc args)]
726          [else (error "call of non-procedure" proc)] ) ) )
727
728("hello" 4)    ==>  #\o
729</enscript>
730
731This facility does not work in code compiled with the ''unsafe'' setting.
732
733
734==== unbound-variable-value
735
736 [procedure] (unbound-variable-value [X])
737
738Defines the value that is returned for unbound variables. Normally an error is
739signalled, use this procedure to override the check and return {{X}} instead.
740To set the default behavior (of signalling an error), call
741{{unbound-variable-value}} with no arguments.
742
743This facility does not work in code compiled with the ''unsafe'' setting.
744
745
746
747=== Magic
748
749
750==== object-become!
751
752 [procedure] (object-become! ALIST)
753
754Changes the identity of the value of the car of each pair in {{ALIST}} to the
755value of the cdr. Both values may not be immediate (i.e. exact integers,
756characters, booleans or the empty list).
757
758<enscript highlight=scheme>
759(define x "i used to be a string")
760(define y '#(and now i am a vector))
761(object-become! (list (cons x y)))
762x                                    ==> #(and now i am a vector)
763y                                    ==> #(and now i am a vector)
764(eq? x y)                            ==> #t
765</enscript>
766
767Note: this operation invokes a major garbage collection.
768
769The effect of using {{object-become!}} on evicted data (see {{object-evict}})
770is undefined.
771
772
773==== mutate-procedure
774
775 [procedure] (mutate-procedure OLD PROC)
776
777Replaces the procedure {{OLD}} with the result of calling the one-argument
778procedure {{PROC}}. {{PROC}} will receive a copy of {{OLD}} that will be
779identical in behaviour to the result of {{PROC}}:
780
781<enscript highlight=scheme>
782;;; Replace arbitrary procedure with tracing one:
783
784(mutate-procedure my-proc
785  (lambda (new)
786    (lambda args
787      (printf "~s called with arguments: ~s~%" new args)
788      (apply new args) ) ) )
789</enscript>
790
791
792Previous: [[Unit tcp]]
793
794Next: [[Interface to external functions and variables]]
Note: See TracBrowser for help on using the repository browser.