1 ! Copyright (C) 2004, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien arrays byte-arrays generic assocs hashtables assocs
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.private strings sbufs
7 vectors words quotations assocs system layouts splitting
8 grouping growable classes classes.builtin classes.tuple
9 classes.tuple.private words.private vocabs
10 vocabs.loader source-files definitions debugger
11 quotations.private sequences.private combinators
12 math.order math.private accessors
13 slots.private compiler.units fry ;
16 : arch ( os cpu -- arch )
18 { "ppc" [ "-ppc" append ] }
19 { "x86.64" [ "winnt" = "winnt" "unix" ? "-x86.64" append ] }
24 os name>> cpu name>> arch ;
26 : boot-image-name ( arch -- string )
27 "boot." ".image" surround ;
29 : my-boot-image-name ( -- string )
30 my-arch boot-image-name ;
35 "winnt-x86.64" "unix-x86.64"
36 "linux-ppc" "macosx-ppc"
41 ! Object cache; we only consider numbers equal if they have the
47 M: id hashcode* obj>> hashcode* ;
49 GENERIC: (eql?) ( obj1 obj2 -- ? )
51 : eql? ( obj1 obj2 -- ? )
52 [ (eql?) ] [ [ class ] bi@ = ] 2bi and ;
59 [ [ eql? ] 2all? ] [ 2drop f ] if
65 over id? [ [ obj>> ] bi@ eql? ] [ 2drop f ] if ;
69 : (objects) ( obj -- id assoc ) <id> objects get ; inline
71 : lookup-object ( obj -- n/f ) (objects) at ;
73 : put-object ( n obj -- ) (objects) set-at ;
75 : cache-object ( obj quot -- value )
76 [ (objects) ] dip '[ obj>> @ ] cache ; inline
80 CONSTANT: image-magic HEX: 0f0e0d0c
81 CONSTANT: image-version 4
83 CONSTANT: data-base 1024
85 CONSTANT: userenv-size 70
87 CONSTANT: header-size 10
89 CONSTANT: data-heap-size-offset 3
95 SYMBOL: sub-primitives
97 : make-jit ( quot rc rt offset -- quad )
98 [ { } make ] 3dip 4array ; inline
100 : jit-define ( quot rc rt offset name -- )
101 [ make-jit ] dip set ; inline
103 : define-sub-primitive ( quot rc rt offset word -- )
104 [ make-jit ] dip sub-primitives get set-at ;
106 ! The image being constructed; a vector of word-size integers
109 ! Image output format
112 ! Bootstrap architecture name
115 ! Bootstrap global namesapce
116 SYMBOL: bootstrap-global
118 ! Boot quotation, set in stage1.factor
119 SYMBOL: bootstrap-boot-quot
122 SYMBOL: jit-code-format
124 SYMBOL: jit-primitive-word
125 SYMBOL: jit-primitive
126 SYMBOL: jit-word-jump
127 SYMBOL: jit-word-call
128 SYMBOL: jit-push-immediate
132 SYMBOL: jit-dispatch-word
136 SYMBOL: jit-2dip-word
138 SYMBOL: jit-3dip-word
142 SYMBOL: jit-profiling
143 SYMBOL: jit-declare-word
144 SYMBOL: jit-save-stack
146 ! Default definition for undefined words
147 SYMBOL: undefined-quot
149 : userenvs ( -- assoc )
151 { bootstrap-boot-quot 20 }
152 { bootstrap-global 21 }
153 { jit-code-format 22 }
155 { jit-primitive-word 24 }
162 { jit-dispatch-word 31 }
167 { jit-push-immediate 36 }
168 { jit-declare-word 42 }
169 { jit-save-stack 43 }
176 { undefined-quot 60 }
179 : userenv-offset ( symbol -- n )
180 userenvs at header-size + ;
182 : emit ( cell -- ) image get push ;
184 : emit-64 ( cell -- )
188 d>w/w big-endian get [ swap ] unless emit emit
191 : emit-seq ( seq -- ) image get push-all ;
193 : fixup ( value offset -- ) image get set-nth ;
195 : heap-size ( -- size )
196 image get length header-size - userenv-size -
199 : here ( -- size ) heap-size data-base + ;
201 : here-as ( tag -- pointer ) here bitor ;
204 here 8 mod 4 = [ 0 emit ] when ;
206 : emit-fixnum ( n -- ) tag-fixnum emit ;
208 : emit-object ( header tag quot -- addr )
209 swap here-as [ swap tag-fixnum emit call align-here ] dip ;
212 ! Write an object to the image.
213 GENERIC: ' ( obj -- ptr )
220 data-base emit ! relocation base at end of header
221 0 emit ! size of data heap set later
222 0 emit ! reloc base of code heap is 0
223 0 emit ! size of code heap is 0
224 0 emit ! pointer to t object
225 0 emit ! pointer to bignum 0
226 0 emit ! pointer to bignum 1
227 0 emit ! pointer to bignum -1
228 userenv-size [ f ' emit ] times ;
230 : emit-userenv ( symbol -- )
231 [ get ' ] [ userenv-offset ] bi fixup ;
235 : bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
237 : bignum-radix ( -- n ) bignum-bits 2^ 1- ;
239 : bignum>seq ( n -- seq )
240 #! n is positive or zero.
242 [ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
245 : emit-bignum ( n -- )
246 dup dup 0 < [ neg ] when bignum>seq
247 [ nip length 1+ emit-fixnum ]
248 [ drop 0 < 1 0 ? emit ]
254 bignum tag-number dup [ emit-bignum ] emit-object
260 #! When generating a 32-bit image on a 64-bit system,
261 #! some fixnums should be bignums.
263 bootstrap-most-negative-fixnum
264 bootstrap-most-positive-fixnum between?
265 [ tag-fixnum ] [ >bignum ' ] if ;
267 TUPLE: fake-bignum n ;
269 C: <fake-bignum> fake-bignum
271 M: fake-bignum ' n>> tag-fixnum ;
277 float tag-number dup [
278 align-here double>bits emit-64
284 ! Padded with fixnums for 8-byte alignment
286 : t, ( -- ) t t-offset fixup ;
289 #! f is #define F RETAG(0,F_TYPE)
290 drop \ f tag-number ;
292 : 0, ( -- ) 0 >bignum ' 0-offset fixup ;
293 : 1, ( -- ) 1 >bignum ' 1-offset fixup ;
294 : -1, ( -- ) -1 >bignum ' -1-offset fixup ;
298 : word-sub-primitive ( word -- obj )
299 global [ target-word ] bind sub-primitives get at ;
301 : emit-word ( word -- )
303 [ subwords [ emit-word ] each ]
307 [ hashcode <fake-bignum> , ]
314 [ word-sub-primitive , ]
317 [ drop 0 , ] ! profiling
321 \ word type-number object tag-number
322 [ emit-seq ] emit-object
325 : word-error ( word msg -- * )
326 [ % dup vocabulary>> % " " % name>> % ] "" make throw ;
328 : transfer-word ( word -- word )
329 [ target-word ] keep or ;
331 : fixup-word ( word -- offset )
332 transfer-word dup lookup-object
333 [ ] [ "Not in image: " word-error ] ?if ;
336 image get [ dup word? [ fixup-word ] when ] change-each ;
343 wrapped>> ' wrapper type-number object tag-number
344 [ emit ] emit-object ;
347 : native> ( object -- object )
348 big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
350 : emit-bytes ( seq -- )
351 bootstrap-cell <groups> native> emit-seq ;
353 : pad-bytes ( seq -- newseq )
354 dup length bootstrap-cell align 0 pad-tail ;
356 : extended-part ( str -- str' )
357 dup [ 128 < ] all? [ drop f ] [
358 [ -7 shift 1 bitxor ] { } map-as
360 [ [ 2 >be ] { } map-as ]
361 [ [ 2 >le ] { } map-as ] if
365 : ascii-part ( str -- str' )
367 [ 128 mod ] [ 128 >= ] bi
371 : emit-string ( string -- ptr )
372 [ length ] [ extended-part ' ] [ ] tri
373 string type-number object tag-number [
376 [ f ' emit ascii-part pad-bytes emit-bytes ]
381 #! We pool strings so that each string is only written once
383 [ emit-string ] cache-object ;
385 : assert-empty ( seq -- )
388 : emit-dummy-array ( obj type -- ptr )
390 type-number object tag-number
391 [ 0 emit-fixnum ] emit-object
395 byte-array type-number object tag-number [
396 dup length emit-fixnum
401 : (emit-tuple) ( tuple -- pointer )
403 [ class transfer-word tuple-layout ] bi prefix [ ' ] map
404 tuple type-number dup [ emit-seq ] emit-object ;
406 : emit-tuple ( tuple -- pointer )
407 dup class name>> "tombstone" =
408 [ [ (emit-tuple) ] cache-object ] [ (emit-tuple) ] if ;
410 M: tuple ' emit-tuple ;
413 state>> "((tombstone))" "((empty))" ?
414 "hashtables.private" lookup def>> first
415 [ emit-tuple ] cache-object ;
418 : emit-array ( array -- offset )
419 [ ' ] map array type-number object tag-number
420 [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
422 M: array ' emit-array ;
424 ! This is a hack. We need to detect arrays which are tuple
425 ! layout arrays so that they can be internalized, but making
426 ! them a built-in type is not worth it.
427 PREDICATE: tuple-layout-array < array
429 [ first tuple-class? ]
435 M: tuple-layout-array '
437 [ dup integer? [ <fake-bignum> ] when ] map
446 quotation type-number object tag-number [
449 f ' emit ! cached-effect
450 f ' emit ! cache-counter
459 all-words [ emit-word ] each ;
463 dictionary source-files builtins
464 update-map implementors-map
465 } [ [ bootstrap-word ] [ get ] bi ] H{ } map>assoc
467 class<=-cache class-not-cache classes-intersect-cache
468 class-and-cache class-or-cache next-method-quot-cache
469 } [ H{ } clone ] H{ } map>assoc assoc-union
471 bootstrap-global emit-userenv ;
473 : emit-boot-quot ( -- )
474 bootstrap-boot-quot emit-userenv ;
476 : emit-jit-data ( -- )
478 \ dispatch jit-dispatch-word set
479 \ do-primitive jit-primitive-word set
480 \ declare jit-declare-word set
481 \ dip jit-dip-word set
482 \ 2dip jit-2dip-word set
483 \ 3dip jit-3dip-word set
484 [ undefined ] undefined-quot set
510 } [ emit-userenv ] each ;
512 : fixup-header ( -- )
513 heap-size data-heap-size-offset fixup ;
515 : build-image ( -- image )
516 800000 <vector> image set
517 20000 <hashtable> objects set
518 emit-header t, 0, 1, -1,
519 "Building generic words..." print flush
521 "Serializing words..." print flush
523 "Serializing JIT data..." print flush
525 "Serializing global namespace..." print flush
527 "Serializing boot quotation..." print flush
529 "Performing word fixups..." print flush
531 "Performing header fixups..." print flush
533 "Image length: " write image get length .
534 "Object cache size: " write objects get assoc-size .
535 \ word global delete-at
540 : (write-image) ( image -- )
541 bootstrap-cell big-endian get
542 [ '[ _ >be write ] each ]
543 [ '[ _ >le write ] each ] if ;
545 : write-image ( image -- )
546 "Writing image to " write
547 architecture get boot-image-name resource-path
548 [ write "..." print flush ]
549 [ binary [ (write-image) ] with-file-writer ] bi ;
553 : make-image ( arch -- )
556 "resource:/core/bootstrap/stage1.factor" run-file
562 images [ make-image ] each ;