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