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