1 ! Copyright (C) 2004, 2011 Slava Pestov.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs byte-arrays classes
4 classes.builtin classes.private classes.tuple
5 classes.tuple.private combinators combinators.short-circuit
6 combinators.smart command-line compiler.codegen.relocation
7 compiler.units endian generic generic.single.private grouping
8 hashtables hashtables.private io io.encodings.binary io.files
9 io.pathnames kernel kernel.private layouts locals.types make
10 math math.bitwise math.order namespaces namespaces.private
11 parser parser.notes prettyprint quotations sequences
12 sequences.private source-files splitting strings system vectors
16 : arch-name ( os cpu -- arch )
17 2dup [ windows? ] [ ppc? ] bi* or [
20 [ name>> ] bi@ "-" glue ;
22 : my-arch-name ( -- arch )
25 : boot-image-name ( arch -- string )
26 "boot." ".image" surround ;
28 : my-boot-image-name ( -- string )
29 my-arch-name boot-image-name ;
33 "windows-x86.32" "unix-x86.32"
34 "windows-x86.64" "unix-x86.64"
35 "windows-arm.64" "unix-arm.64"
40 ! Object cache; we only consider numbers equal if they have the
42 TUPLE: eql-wrapper { obj read-only } ;
44 C: <eql-wrapper> eql-wrapper
46 M: eql-wrapper hashcode* obj>> hashcode* ;
48 GENERIC: (eql?) ( obj1 obj2 -- ? )
50 : eql? ( obj1 obj2 -- ? )
51 { [ [ class-of ] same? ] [ (eql?) ] } 2&& ;
53 M: fixnum (eql?) eq? ;
55 M: bignum (eql?) { bignum bignum } declare = ;
57 M: float (eql?) fp-bitwise= ;
60 2dup [ length ] same? [ [ eql? ] 2all? ] [ 2drop f ] if ;
65 over eql-wrapper? [ [ obj>> ] bi@ eql? ] [ 2drop f ] if ;
67 TUPLE: eq-wrapper { obj read-only } ;
69 C: <eq-wrapper> eq-wrapper
72 over eq-wrapper? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
74 M: eq-wrapper hashcode*
75 nip obj>> identity-hashcode ;
79 : cache-eql-object ( obj quot -- value )
80 [ <eql-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
82 : cache-eq-object ( obj quot -- value )
83 [ <eq-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
85 : lookup-object ( obj -- n/f )
86 <eq-wrapper> objects get at ;
88 : put-object ( n obj -- )
89 <eq-wrapper> objects get set-at ;
91 ! Constants need to be synced with
93 CONSTANT: image-magic 0x0f0e0d0c
94 CONSTANT: image-version 4
96 CONSTANT: data-base 1024
98 CONSTANT: header-size 10
100 CONSTANT: data-heap-size-offset 3
102 SYMBOL: sub-primitives
104 SYMBOL: special-objects
106 :: jit-conditional ( test-quot false-quot -- )
107 [ 0 test-quot call ] B{ } make length :> len
108 building get length extra-offset get + len +
109 [ extra-offset set false-quot call ] B{ } make
110 [ length test-quot call ] [ % ] bi ; inline
112 : make-jit ( quot -- parameters literals code )
117 parameter-table get >array
118 literal-table get >array
119 relocation-table get >byte-array
122 : make-jit-no-params ( quot -- code )
125 : jit-define ( quot n -- )
126 [ make-jit-no-params ] dip special-objects get set-at ;
128 : define-sub-primitive ( quot word -- )
129 [ make-jit 3array ] dip sub-primitives get set-at ;
131 : define-sub-primitives ( assoc -- )
132 [ swap define-sub-primitive ] assoc-each ;
134 : define-combinator-primitive ( quot non-tail-quot tail-quot word -- )
138 [ make-jit-no-params ]
139 [ make-jit-no-params ]
143 sub-primitives get set-at ;
145 SYMBOL: bootstrapping-image
147 ! Image output format
152 : emit ( cell -- ) bootstrapping-image get push ;
154 : emit-64 ( cell -- )
158 d>w/w big-endian get [ swap ] unless emit emit
161 : emit-seq ( seq -- ) bootstrapping-image get push-all ;
163 : fixup ( value offset -- ) bootstrapping-image get set-nth ;
165 : heap-size ( -- size )
166 bootstrapping-image get length header-size - special-object-count -
169 : here ( -- size ) heap-size data-base + ;
171 : here-as ( tag -- pointer ) here bitor ;
173 : (align-here) ( alignment -- )
175 [ bootstrap-cell /i [ 0 emit ] times ] unless-zero ;
178 data-alignment get (align-here) ;
180 : emit-fixnum ( n -- ) tag-fixnum emit ;
182 : emit-header ( n -- ) tag-header emit ;
184 : emit-object ( class quot -- addr )
185 [ type-number ] dip over here-as
186 [ swap emit-header call align-here ] dip ; inline
188 ! Read any object for emitting.
189 GENERIC: prepare-object ( obj -- ptr )
193 : emit-image-header ( -- )
196 data-base emit ! relocation base at end of header
197 0 emit ! size of data heap set later
198 0 emit ! reloc base of code heap is 0
199 0 emit ! size of code heap is 0
204 special-object-count [ f prepare-object emit ] times ;
208 : bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
210 : bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
212 : bignum>sequence ( n -- seq )
213 ! n is positive or zero.
215 [ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
218 : emit-bignum ( n -- )
219 dup dup 0 < [ neg ] when bignum>sequence
220 [ nip length 1 + emit-fixnum ]
221 [ drop 0 < 1 0 ? emit ]
225 M: bignum prepare-object
227 bignum [ emit-bignum ] emit-object
232 M: fixnum prepare-object
233 ! When generating a 32-bit image on a 64-bit system,
234 ! some fixnums should be bignums.
236 bootstrap-most-negative-fixnum
237 bootstrap-most-positive-fixnum between?
238 [ tag-fixnum ] [ >bignum prepare-object ] if ;
240 TUPLE: fake-bignum n ;
242 C: <fake-bignum> fake-bignum
244 M: fake-bignum prepare-object n>> tag-fixnum ;
248 M: float prepare-object
251 8 (align-here) double>bits emit-64
257 ! Padded with fixnums for 8-byte alignment
258 M: f prepare-object drop \ f type-number ;
262 : word-sub-primitive ( word -- obj )
263 [ target-word ] with-global sub-primitives get at ;
265 : emit-word ( word -- )
267 [ subwords [ emit-word ] each ]
271 [ hashcode <fake-bignum> ]
278 [ word-sub-primitive ]
279 [ drop 0 ] ! entry point
281 ] output>array [ prepare-object ] map!
283 \ word [ emit-seq ] emit-object
286 ERROR: not-in-image vocabulary word ;
288 : transfer-word ( word -- word )
289 [ target-word ] keep or ;
291 : fixup-word ( word -- offset )
293 [ lookup-object ] [ [ vocabulary>> ] [ name>> ] bi not-in-image ] ?unless ;
296 bootstrapping-image get [ dup word? [ fixup-word ] when ] map! drop ;
298 M: word prepare-object ;
302 M: wrapper prepare-object
303 [ wrapped>> prepare-object wrapper [ emit ] emit-object ] cache-eql-object ;
306 : native> ( object -- object )
307 big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
309 : emit-bytes ( seq -- )
310 bootstrap-cell <groups> native> emit-seq ;
312 : pad-bytes ( seq -- newseq )
313 dup length bootstrap-cell align 0 pad-tail ;
315 : extended-part ( str -- str' )
316 dup [ 128 < ] all? [ drop f ] [
317 [ -7 shift 1 bitxor ] { } map-as
319 [ [ 2 >be ] { } map-as ]
320 [ [ 2 >le ] { } map-as ] if
324 : ascii-part ( str -- str' )
326 [ 128 mod ] [ 128 >= ] bi
330 : emit-string ( string -- ptr )
331 [ length ] [ extended-part prepare-object ] [ ] tri
335 [ f prepare-object emit ascii-part pad-bytes emit-bytes ]
339 M: string prepare-object
340 ! We pool strings so that each string is only written once
342 [ emit-string ] cache-eql-object ;
344 : assert-empty ( seq -- )
347 : emit-dummy-array ( obj type -- ptr )
349 [ 0 emit-fixnum ] emit-object
352 M: byte-array prepare-object
355 dup length emit-fixnum
356 bootstrap-cell 4 = [ 0 emit 0 emit ] when
362 ERROR: tuple-removed class ;
364 : require-tuple-layout ( word -- layout )
365 [ tuple-layout ] [ tuple-removed ] ?unless ;
367 : (emit-tuple) ( tuple -- pointer )
369 [ class-of transfer-word require-tuple-layout ] bi prefix [ prepare-object ] map
370 tuple [ emit-seq ] emit-object ;
372 : emit-tuple ( tuple -- pointer )
373 dup class-of name>> "tombstone" =
374 [ [ (emit-tuple) ] cache-eql-object ]
375 [ [ (emit-tuple) ] cache-eq-object ]
378 M: tuple prepare-object emit-tuple ;
380 M: tombstone prepare-object
381 state>> "+tombstone+" "+empty+" ?
382 "hashtables.private" lookup-word def>> first
383 [ emit-tuple ] cache-eql-object ;
386 : emit-array ( array -- offset )
387 [ prepare-object ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
389 M: array prepare-object [ emit-array ] cache-eq-object ;
391 ! This is a hack. We need to detect arrays which are tuple
392 ! layout arrays so that they can be internalized, but making
393 ! them a built-in type is not worth it.
394 PREDICATE: tuple-layout-array < array
397 [ first-unsafe tuple-class? ]
398 [ second-unsafe fixnum? ]
399 [ third-unsafe fixnum? ]
403 M: tuple-layout-array prepare-object
405 [ dup integer? [ <fake-bignum> ] when ] map
411 M: quotation prepare-object
413 array>> prepare-object
416 f prepare-object emit ! cached-effect
417 f prepare-object emit ! cache-counter
425 all-words [ emit-word ] each ;
427 : emit-singletons ( -- )
428 t OBJ-CANONICAL-TRUE special-objects get set-at
429 0 >bignum OBJ-BIGNUM-ZERO special-objects get set-at
430 1 >bignum OBJ-BIGNUM-POS-ONE special-objects get set-at
431 -1 >bignum OBJ-BIGNUM-NEG-ONE special-objects get set-at ;
433 : create-global-hashtable ( -- global-hashtable )
435 dictionary source-files builtins
436 update-map implementors-map
437 } [ [ bootstrap-word ] [ get global-box boa ] bi ] H{ } map>assoc
439 class<=-cache class-not-cache classes-intersect-cache
440 class-and-cache class-or-cache next-method-quot-cache
441 } [ H{ } clone global-box boa ] H{ } map>assoc assoc-union
442 global-hashtable boa ;
445 create-global-hashtable
446 OBJ-GLOBAL special-objects get set-at ;
448 : emit-jit-data ( -- )
451 { JIT-PRIMITIVE-WORD do-primitive }
453 { JIT-2DIP-WORD 2dip }
454 { JIT-3DIP-WORD 3dip }
455 { PIC-MISS-WORD inline-cache-miss }
456 { PIC-MISS-TAIL-WORD inline-cache-miss-tail }
457 { MEGA-LOOKUP-WORD mega-cache-lookup }
458 { MEGA-MISS-WORD mega-cache-miss }
459 { JIT-DECLARE-WORD declare }
460 { C-TO-FACTOR-WORD c-to-factor }
461 { LAZY-JIT-COMPILE-WORD lazy-jit-compile }
462 { UNWIND-NATIVE-FRAMES-WORD unwind-native-frames }
463 { GET-FPU-STATE-WORD fpu-state }
464 { SET-FPU-STATE-WORD set-fpu-state }
465 { SIGNAL-HANDLER-WORD signal-handler }
466 { LEAF-SIGNAL-HANDLER-WORD leaf-signal-handler }
468 \ OBJ-UNDEFINED undefined-def 2array suffix [
469 swap execute( -- x ) special-objects get set-at
472 : emit-special-object ( obj idx -- )
473 [ prepare-object ] [ header-size + ] bi* fixup ;
475 : emit-special-objects ( -- )
476 special-objects get [ swap emit-special-object ] assoc-each ;
479 bootstrapping-image get [ dup local? [ emit-word ] [ drop ] if ] each ;
481 : fixup-header ( -- )
482 heap-size data-heap-size-offset fixup ;
484 : build-generics ( -- )
488 [ make-generic ] each
489 ] with-compilation-unit ;
491 : build-image ( -- image )
492 600,000 <vector> bootstrapping-image set
493 60,000 <hashtable> objects set
495 "Building generic words..." print flush
497 "Serializing words..." print flush
499 "Serializing locals..." print flush
501 "Serializing JIT data..." print flush
503 ! special-objects get ...
505 ! "sub-primitives" print
506 ! sub-primitives get ...
508 ! 43 special-objects get set-at
510 "Serializing global namespace..." print flush
512 "Serializing singletons..." print flush
514 "Serializing special object table..." print flush
516 "Performing word fixups..." print flush
518 "Performing header fixups..." print flush
520 "Image length: " write bootstrapping-image get length .
521 "Object cache size: " write objects get assoc-size .
522 \ last-word global delete-at
523 bootstrapping-image get ;
527 : (write-image) ( image -- )
528 bootstrap-cell output-stream get
530 [ '[ _ >be _ stream-write ] each ]
531 [ '[ _ >le _ stream-write ] each ] if ;
533 : write-image ( image -- )
534 "Writing image to " write
535 architecture get boot-image-name resource-path
536 [ write "..." print flush ]
537 [ binary [ (write-image) ] with-file-writer ] bi ;
541 : make-image ( arch -- )
542 architecture associate H{
546 H{ } clone special-objects set
547 "resource:basis/bootstrap/stage1.factor" run-file
553 image-names [ make-image ] each ;
555 : make-my-image ( -- )
556 my-arch-name make-image ;
558 : make-image-main ( -- )
562 [ "boot." ?head drop ".image" ?tail drop make-image ] each
565 MAIN: make-image-main