1 ! Copyright (C) 2004, 2008 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 ;
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>> ] prepose cache ; inline
80 : image-magic HEX: 0f0e0d0c ; inline
81 : image-version 4 ; inline
83 : data-base 1024 ; inline
85 : userenv-size 70 ; inline
87 : header-size 10 ; inline
89 : data-heap-size-offset 3 ; inline
93 : -1-offset 9 ; inline
95 SYMBOL: sub-primitives
97 : make-jit ( quot rc rt offset -- quad )
98 { [ { } make ] [ ] [ ] [ ] } spread 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 : emit-bytes ( seq -- )
348 bootstrap-cell <groups>
349 big-endian get [ [ be> ] map ] [ [ le> ] map ] if
352 : pad-bytes ( seq -- newseq )
353 dup length bootstrap-cell align 0 pad-right ;
355 : check-string ( string -- )
357 [ "Bootstrap cannot emit non-ASCII strings" throw ] when ;
359 : emit-string ( string -- ptr )
361 string type-number object tag-number [
362 dup length emit-fixnum
369 #! We pool strings so that each string is only written once
371 [ emit-string ] cache-object ;
373 : assert-empty ( seq -- )
376 : emit-dummy-array ( obj type -- ptr )
378 type-number object tag-number
379 [ 0 emit-fixnum ] emit-object
383 byte-array type-number object tag-number [
384 dup length emit-fixnum
389 : (emit-tuple) ( tuple -- pointer )
391 [ class transfer-word tuple-layout ] bi prefix [ ' ] map
392 tuple type-number dup [ emit-seq ] emit-object ;
394 : emit-tuple ( tuple -- pointer )
395 dup class name>> "tombstone" =
396 [ [ (emit-tuple) ] cache-object ] [ (emit-tuple) ] if ;
398 M: tuple ' emit-tuple ;
401 state>> "((tombstone))" "((empty))" ?
402 "hashtables.private" lookup def>> first
403 [ emit-tuple ] cache-object ;
406 : emit-array ( array -- offset )
407 [ ' ] map array type-number object tag-number
408 [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
410 M: array ' emit-array ;
412 ! This is a hack. We need to detect arrays which are tuple
413 ! layout arrays so that they can be internalized, but making
414 ! them a built-in type is not worth it.
415 PREDICATE: tuple-layout-array < array
417 [ first tuple-class? ]
423 M: tuple-layout-array '
425 [ dup integer? [ <fake-bignum> ] when ] map
434 quotation type-number object tag-number [
436 f ' emit ! compiled>>
445 all-words [ emit-word ] each ;
449 dictionary source-files builtins
450 update-map implementors-map
451 } [ [ bootstrap-word ] [ get ] bi ] H{ } map>assoc
453 class<=-cache class-not-cache classes-intersect-cache
454 class-and-cache class-or-cache next-method-quot-cache
455 } [ H{ } clone ] H{ } map>assoc assoc-union
457 bootstrap-global emit-userenv ;
459 : emit-boot-quot ( -- )
460 bootstrap-boot-quot emit-userenv ;
462 : emit-jit-data ( -- )
464 \ dispatch jit-dispatch-word set
465 \ do-primitive jit-primitive-word set
466 \ declare jit-declare-word set
467 \ dip jit-dip-word set
468 \ 2dip jit-2dip-word set
469 \ 3dip jit-3dip-word set
470 [ undefined ] undefined-quot set
496 } [ emit-userenv ] each ;
498 : fixup-header ( -- )
499 heap-size data-heap-size-offset fixup ;
501 : build-image ( -- image )
502 800000 <vector> image set
503 20000 <hashtable> objects set
504 emit-header t, 0, 1, -1,
505 "Building generic words..." print flush
506 call-remake-generics-hook
507 "Serializing words..." print flush
509 "Serializing JIT data..." print flush
511 "Serializing global namespace..." print flush
513 "Serializing boot quotation..." print flush
515 "Performing word fixups..." print flush
517 "Performing header fixups..." print flush
519 "Image length: " write image get length .
520 "Object cache size: " write objects get assoc-size .
521 \ word global delete-at
526 : (write-image) ( image -- )
527 bootstrap-cell big-endian get [
528 [ >be write ] curry each
530 [ >le write ] curry each
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 -- )
544 "resource:/core/bootstrap/stage1.factor" run-file
550 images [ make-image ] each ;