]> gitweb.factorcode.org Git - factor.git/blob - basis/bootstrap/image/image.factor
Clean up startup/shutdown hook code
[factor.git] / basis / bootstrap / image / image.factor
1 ! Copyright (C) 2004, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien arrays byte-arrays generic hashtables
4 hashtables.private io io.binary io.files io.encodings.binary
5 io.pathnames kernel kernel.private math namespaces make parser
6 prettyprint sequences strings sbufs vectors words quotations
7 assocs system layouts splitting grouping growable classes
8 classes.builtin classes.tuple classes.tuple.private vocabs
9 vocabs.loader source-files definitions debugger
10 quotations.private combinators combinators.short-circuit
11 math.order math.private accessors slots.private
12 generic.single.private compiler.units compiler.constants fry
13 bootstrap.image.syntax ;
14 IN: bootstrap.image
15
16 : arch ( os cpu -- arch )
17     {
18         { "ppc" [ "-ppc" append ] }
19         { "x86.64" [ "winnt" = "winnt" "unix" ? "-x86.64" append ] }
20         [ nip ]
21     } case ;
22
23 : my-arch ( -- arch )
24     os name>> cpu name>> arch ;
25
26 : boot-image-name ( arch -- string )
27     "boot." ".image" surround ;
28
29 : my-boot-image-name ( -- string )
30     my-arch boot-image-name ;
31
32 : images ( -- seq )
33     {
34         "x86.32"
35         "winnt-x86.64" "unix-x86.64"
36         "linux-ppc" "macosx-ppc"
37     } ;
38
39 <PRIVATE
40
41 ! Object cache; we only consider numbers equal if they have the
42 ! same type
43 TUPLE: eql-wrapper { obj read-only } ;
44
45 C: <eql-wrapper> eql-wrapper
46
47 M: eql-wrapper hashcode* obj>> hashcode* ;
48
49 GENERIC: (eql?) ( obj1 obj2 -- ? )
50
51 : eql? ( obj1 obj2 -- ? )
52     { [ [ class ] bi@ = ] [ (eql?) ] } 2&& ;
53
54 M: fixnum (eql?) eq? ;
55
56 M: bignum (eql?) = ;
57
58 M: float (eql?) fp-bitwise= ;
59
60 M: sequence (eql?) 2dup [ length ] bi@ = [ [ eql? ] 2all? ] [ 2drop f ] if ;
61
62 M: object (eql?) = ;
63
64 M: eql-wrapper equal?
65     over eql-wrapper? [ [ obj>> ] bi@ eql? ] [ 2drop f ] if ;
66
67 TUPLE: eq-wrapper { obj read-only } ;
68
69 C: <eq-wrapper> eq-wrapper
70
71 M: eq-wrapper equal?
72     over eq-wrapper? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
73
74 M: eq-wrapper hashcode*
75     nip obj>> identity-hashcode ;
76
77 SYMBOL: objects
78
79 : cache-eql-object ( obj quot -- value )
80     [ <eql-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
81
82 : cache-eq-object ( obj quot -- value )
83     [ <eq-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
84
85 : lookup-object ( obj -- n/f ) <eq-wrapper> objects get at ;
86
87 : put-object ( n obj -- ) <eq-wrapper> objects get set-at ;
88
89 ! Constants
90
91 CONSTANT: image-magic HEX: 0f0e0d0c
92 CONSTANT: image-version 4
93
94 CONSTANT: data-base 1024
95
96 CONSTANT: userenv-size 70
97
98 CONSTANT: header-size 10
99
100 CONSTANT: data-heap-size-offset 3
101 CONSTANT: t-offset              6
102 CONSTANT: 0-offset              7
103 CONSTANT: 1-offset              8
104 CONSTANT: -1-offset             9
105
106 SYMBOL: sub-primitives
107
108 SYMBOL: jit-relocations
109
110 : compute-offset ( rc -- offset )
111     [ building get length ] dip rc-absolute-cell = bootstrap-cell 4 ? - ;
112
113 : jit-rel ( rc rt -- )
114     over compute-offset 3array jit-relocations get push-all ;
115
116 SYMBOL: jit-literals
117
118 : jit-literal ( literal -- )
119     jit-literals get push ;
120
121 : make-jit ( quot -- jit-literals jit-data )
122     [
123         V{ } clone jit-literals set
124         V{ } clone jit-relocations set
125         call( -- )
126         jit-literals get >array
127         jit-relocations get >array
128     ] B{ } make prefix ;
129
130 : jit-define ( quot name -- )
131     [ make-jit nip ] dip set ;
132
133 : define-sub-primitive ( quot word -- )
134     [ make-jit 2array ] dip sub-primitives get set-at ;
135
136 ! The image being constructed; a vector of word-size integers
137 SYMBOL: image
138
139 ! Image output format
140 SYMBOL: big-endian
141
142 ! Bootstrap architecture name
143 SYMBOL: architecture
144
145 RESET
146
147 ! Boot quotation, set in stage1.factor
148 USERENV: bootstrap-startup-quot 20
149
150 ! Bootstrap global namesapce
151 USERENV: bootstrap-global 21
152
153 ! JIT parameters
154 USERENV: jit-prolog 23
155 USERENV: jit-primitive-word 24
156 USERENV: jit-primitive 25
157 USERENV: jit-word-jump 26
158 USERENV: jit-word-call 27
159 USERENV: jit-word-special 28
160 USERENV: jit-if-word 29
161 USERENV: jit-if 30
162 USERENV: jit-epilog 31
163 USERENV: jit-return 32
164 USERENV: jit-profiling 33
165 USERENV: jit-push-immediate 34
166 USERENV: jit-dip-word 35
167 USERENV: jit-dip 36
168 USERENV: jit-2dip-word 37
169 USERENV: jit-2dip 38
170 USERENV: jit-3dip-word 39
171 USERENV: jit-3dip 40
172 USERENV: jit-execute-word 41
173 USERENV: jit-execute-jump 42
174 USERENV: jit-execute-call 43
175 USERENV: jit-declare-word 44
176
177 USERENV: callback-stub 45
178
179 ! PIC stubs
180 USERENV: pic-load 47
181 USERENV: pic-tag 48
182 USERENV: pic-tuple 49
183 USERENV: pic-check-tag 50
184 USERENV: pic-check-tuple 51
185 USERENV: pic-hit 52
186 USERENV: pic-miss-word 53
187 USERENV: pic-miss-tail-word 54
188
189 ! Megamorphic dispatch
190 USERENV: mega-lookup 57
191 USERENV: mega-lookup-word 58
192 USERENV: mega-miss-word 59
193
194 ! Default definition for undefined words
195 USERENV: undefined-quot 60
196
197 : userenv-offset ( symbol -- n )
198     userenvs get at header-size + ;
199
200 : emit ( cell -- ) image get push ;
201
202 : emit-64 ( cell -- )
203     bootstrap-cell 8 = [
204         emit
205     ] [
206         d>w/w big-endian get [ swap ] unless emit emit
207     ] if ;
208
209 : emit-seq ( seq -- ) image get push-all ;
210
211 : fixup ( value offset -- ) image get set-nth ;
212
213 : heap-size ( -- size )
214     image get length header-size - userenv-size -
215     bootstrap-cells ;
216
217 : here ( -- size ) heap-size data-base + ;
218
219 : here-as ( tag -- pointer ) here bitor ;
220
221 : (align-here) ( alignment -- )
222     [ here neg ] dip rem
223     [ bootstrap-cell /i [ 0 emit ] times ] unless-zero ;
224
225 : align-here ( -- )
226     data-alignment get (align-here) ;
227
228 : emit-fixnum ( n -- ) tag-fixnum emit ;
229
230 : emit-header ( n -- ) tag-header emit ;
231
232 : emit-object ( class quot -- addr )
233     [ type-number ] dip over here-as
234     [ swap emit-header call align-here ] dip ;
235     inline
236
237 ! Write an object to the image.
238 GENERIC: ' ( obj -- ptr )
239
240 ! Image header
241
242 : emit-image-header ( -- )
243     image-magic emit
244     image-version emit
245     data-base emit ! relocation base at end of header
246     0 emit ! size of data heap set later
247     0 emit ! reloc base of code heap is 0
248     0 emit ! size of code heap is 0
249     0 emit ! pointer to t object
250     0 emit ! pointer to bignum 0
251     0 emit ! pointer to bignum 1
252     0 emit ! pointer to bignum -1
253     userenv-size [ f ' emit ] times ;
254
255 : emit-userenv ( symbol -- )
256     [ get ' ] [ userenv-offset ] bi fixup ;
257
258 ! Bignums
259
260 : bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
261
262 : bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
263
264 : bignum>seq ( n -- seq )
265     #! n is positive or zero.
266     [ dup 0 > ]
267     [ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
268     produce nip ;
269
270 : emit-bignum ( n -- )
271     dup dup 0 < [ neg ] when bignum>seq
272     [ nip length 1 + emit-fixnum ]
273     [ drop 0 < 1 0 ? emit ]
274     [ nip emit-seq ]
275     2tri ;
276
277 M: bignum '
278     [
279         bignum [ emit-bignum ] emit-object
280     ] cache-eql-object ;
281
282 ! Fixnums
283
284 M: fixnum '
285     #! When generating a 32-bit image on a 64-bit system,
286     #! some fixnums should be bignums.
287     dup
288     bootstrap-most-negative-fixnum
289     bootstrap-most-positive-fixnum between?
290     [ tag-fixnum ] [ >bignum ' ] if ;
291
292 TUPLE: fake-bignum n ;
293
294 C: <fake-bignum> fake-bignum
295
296 M: fake-bignum ' n>> tag-fixnum ;
297
298 ! Floats
299
300 M: float '
301     [
302         float [
303             8 (align-here) double>bits emit-64
304         ] emit-object
305     ] cache-eql-object ;
306
307 ! Special objects
308
309 ! Padded with fixnums for 8-byte alignment
310
311 : t, ( -- ) t t-offset fixup ;
312
313 M: f '
314     #! f is #define F RETAG(0,F_TYPE)
315     drop \ f type-number ;
316
317 :  0, ( -- )  0 >bignum '  0-offset fixup ;
318 :  1, ( -- )  1 >bignum '  1-offset fixup ;
319 : -1, ( -- ) -1 >bignum ' -1-offset fixup ;
320
321 ! Words
322
323 : word-sub-primitive ( word -- obj )
324     global [ target-word ] bind sub-primitives get at ;
325
326 : emit-word ( word -- )
327     [
328         [ subwords [ emit-word ] each ]
329         [
330             [
331                 {
332                     [ hashcode <fake-bignum> , ]
333                     [ name>> , ]
334                     [ vocabulary>> , ]
335                     [ def>> , ]
336                     [ props>> , ]
337                     [ pic-def>> , ]
338                     [ pic-tail-def>> , ]
339                     [ drop 0 , ] ! count
340                     [ word-sub-primitive , ]
341                     [ drop 0 , ] ! xt
342                     [ drop 0 , ] ! code
343                     [ drop 0 , ] ! profiling
344                 } cleave
345             ] { } make [ ' ] map
346         ] bi
347         \ word [ emit-seq ] emit-object
348     ] keep put-object ;
349
350 : word-error ( word msg -- * )
351     [ % dup vocabulary>> % " " % name>> % ] "" make throw ;
352
353 : transfer-word ( word -- word )
354     [ target-word ] keep or ;
355
356 : fixup-word ( word -- offset )
357     transfer-word dup lookup-object
358     [ ] [ "Not in image: " word-error ] ?if ;
359
360 : fixup-words ( -- )
361     image get [ dup word? [ fixup-word ] when ] map! drop ;
362
363 M: word ' ;
364
365 ! Wrappers
366
367 M: wrapper '
368     [ wrapped>> ' wrapper [ emit ] emit-object ] cache-eql-object ;
369
370 ! Strings
371 : native> ( object -- object )
372     big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
373
374 : emit-bytes ( seq -- )
375     bootstrap-cell <groups> native> emit-seq ;
376
377 : pad-bytes ( seq -- newseq )
378     dup length bootstrap-cell align 0 pad-tail ;
379
380 : extended-part ( str -- str' )
381     dup [ 128 < ] all? [ drop f ] [
382         [ -7 shift 1 bitxor ] { } map-as
383         big-endian get
384         [ [ 2 >be ] { } map-as ]
385         [ [ 2 >le ] { } map-as ] if
386         B{ } join
387     ] if ;
388
389 : ascii-part ( str -- str' )
390     [
391         [ 128 mod ] [ 128 >= ] bi
392         [ 128 bitor ] when
393     ] B{ } map-as ;
394
395 : emit-string ( string -- ptr )
396     [ length ] [ extended-part ' ] [ ] tri
397     string [
398         [ emit-fixnum ]
399         [ emit ]
400         [ f ' emit ascii-part pad-bytes emit-bytes ]
401         tri*
402     ] emit-object ;
403
404 M: string '
405     #! We pool strings so that each string is only written once
406     #! to the image
407     [ emit-string ] cache-eql-object ;
408
409 : assert-empty ( seq -- )
410     length 0 assert= ;
411
412 : emit-dummy-array ( obj type -- ptr )
413     [ assert-empty ] [
414         [ 0 emit-fixnum ] emit-object
415     ] bi* ;
416
417 M: byte-array '
418     [
419         byte-array [
420             dup length emit-fixnum
421             bootstrap-cell 4 = [ 0 emit 0 emit ] when
422             pad-bytes emit-bytes
423         ] emit-object
424     ] cache-eq-object ;
425
426 ! Tuples
427 ERROR: tuple-removed class ;
428
429 : require-tuple-layout ( word -- layout )
430     dup tuple-layout [ ] [ tuple-removed ] ?if ;
431
432 : (emit-tuple) ( tuple -- pointer )
433     [ tuple-slots ]
434     [ class transfer-word require-tuple-layout ] bi prefix [ ' ] map
435     tuple [ emit-seq ] emit-object ;
436
437 : emit-tuple ( tuple -- pointer )
438     dup class name>> "tombstone" =
439     [ [ (emit-tuple) ] cache-eql-object ]
440     [ [ (emit-tuple) ] cache-eq-object ]
441     if ;
442
443 M: tuple ' emit-tuple ;
444
445 M: tombstone '
446     state>> "((tombstone))" "((empty))" ?
447     "hashtables.private" lookup def>> first
448     [ emit-tuple ] cache-eql-object ;
449
450 ! Arrays
451 : emit-array ( array -- offset )
452     [ ' ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
453
454 M: array ' [ emit-array ] cache-eq-object ;
455
456 ! This is a hack. We need to detect arrays which are tuple
457 ! layout arrays so that they can be internalized, but making
458 ! them a built-in type is not worth it.
459 PREDICATE: tuple-layout-array < array
460     dup length 5 >= [
461         [ first tuple-class? ]
462         [ second fixnum? ]
463         [ third fixnum? ]
464         tri and and
465     ] [ drop f ] if ;
466
467 M: tuple-layout-array '
468     [
469         [ dup integer? [ <fake-bignum> ] when ] map
470         emit-array
471     ] cache-eql-object ;
472
473 ! Quotations
474
475 M: quotation '
476     [
477         array>> '
478         quotation [
479             emit ! array
480             f ' emit ! cached-effect
481             f ' emit ! cache-counter
482             0 emit ! xt
483             0 emit ! code
484         ] emit-object
485     ] cache-eql-object ;
486
487 ! End of the image
488
489 : emit-words ( -- )
490     all-words [ emit-word ] each ;
491
492 : emit-global ( -- )
493     {
494         dictionary source-files builtins
495         update-map implementors-map
496     } [ [ bootstrap-word ] [ get ] bi ] H{ } map>assoc
497     {
498         class<=-cache class-not-cache classes-intersect-cache
499         class-and-cache class-or-cache next-method-quot-cache
500     } [ H{ } clone ] H{ } map>assoc assoc-union
501     bootstrap-global set ;
502
503 : emit-jit-data ( -- )
504     \ if jit-if-word set
505     \ do-primitive jit-primitive-word set
506     \ dip jit-dip-word set
507     \ 2dip jit-2dip-word set
508     \ 3dip jit-3dip-word set
509     \ (execute) jit-execute-word set
510     \ inline-cache-miss \ pic-miss-word set
511     \ inline-cache-miss-tail \ pic-miss-tail-word set
512     \ mega-cache-lookup \ mega-lookup-word set
513     \ mega-cache-miss \ mega-miss-word set
514     \ declare jit-declare-word set
515     [ undefined ] undefined-quot set ;
516
517 : emit-userenvs ( -- )
518     userenvs get keys [ emit-userenv ] each ;
519
520 : fixup-header ( -- )
521     heap-size data-heap-size-offset fixup ;
522
523 : build-image ( -- image )
524     800000 <vector> image set
525     20000 <hashtable> objects set
526     emit-image-header t, 0, 1, -1,
527     "Building generic words..." print flush
528     remake-generics
529     "Serializing words..." print flush
530     emit-words
531     "Serializing JIT data..." print flush
532     emit-jit-data
533     "Serializing global namespace..." print flush
534     emit-global
535     "Serializing user environment..." print flush
536     emit-userenvs
537     "Performing word fixups..." print flush
538     fixup-words
539     "Performing header fixups..." print flush
540     fixup-header
541     "Image length: " write image get length .
542     "Object cache size: " write objects get assoc-size .
543     \ word global delete-at
544     image get ;
545
546 ! Image output
547
548 : (write-image) ( image -- )
549     bootstrap-cell big-endian get
550     [ '[ _ >be write ] each ]
551     [ '[ _ >le write ] each ] if ;
552
553 : write-image ( image -- )
554     "Writing image to " write
555     architecture get boot-image-name resource-path
556     [ write "..." print flush ]
557     [ binary [ (write-image) ] with-file-writer ] bi ;
558
559 PRIVATE>
560
561 : make-image ( arch -- )
562     [
563         architecture set
564         "resource:/core/bootstrap/stage1.factor" run-file
565         build-image
566         write-image
567     ] with-scope ;
568
569 : make-images ( -- )
570     images [ make-image ] each ;