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 parser.notes ;
17 : arch ( os cpu -- arch )
18 2dup [ windows? ] [ ppc? ] bi* or [
21 [ name>> ] [ name>> ] bi* "-" glue ;
26 : boot-image-name ( arch -- string )
27 "boot." ".image" surround ;
29 : my-boot-image-name ( -- string )
30 my-arch boot-image-name ;
34 "windows-x86.32" "unix-x86.32"
35 "linux-ppc.32" "linux-ppc.64"
36 "windows-x86.64" "unix-x86.64"
41 ! Object cache; we only consider numbers equal if they have the
43 TUPLE: eql-wrapper { obj read-only } ;
45 C: <eql-wrapper> eql-wrapper
47 M: eql-wrapper hashcode* obj>> hashcode* ;
49 GENERIC: (eql?) ( obj1 obj2 -- ? )
51 : eql? ( obj1 obj2 -- ? )
52 { [ [ class ] bi@ = ] [ (eql?) ] } 2&& ;
54 M: fixnum (eql?) eq? ;
58 M: float (eql?) fp-bitwise= ;
60 M: sequence (eql?) 2dup [ length ] bi@ = [ [ 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 ) <eq-wrapper> objects get at ;
87 : put-object ( n obj -- ) <eq-wrapper> objects get set-at ;
91 CONSTANT: image-magic HEX: 0f0e0d0c
92 CONSTANT: image-version 4
94 CONSTANT: data-base 1024
96 CONSTANT: special-objects-size 70
98 CONSTANT: header-size 10
100 CONSTANT: data-heap-size-offset 3
104 CONSTANT: -1-offset 9
106 SYMBOL: sub-primitives
108 SYMBOL: jit-relocations
112 : compute-offset ( -- offset )
113 building get length jit-offset get + ;
115 : jit-rel ( rc rt -- )
116 compute-offset 3array jit-relocations get push-all ;
118 SYMBOL: jit-parameters
120 : jit-parameter ( parameter -- )
121 jit-parameters get push ;
125 : jit-literal ( literal -- )
126 jit-literals get push ;
128 : jit-vm ( offset rc -- )
129 [ jit-parameter ] dip rt-vm jit-rel ;
131 : jit-dlsym ( name rc -- )
132 rt-dlsym jit-rel string>symbol jit-parameter f jit-parameter ;
134 : jit-dlsym-toc ( name rc -- )
135 rt-dlsym-toc jit-rel string>symbol jit-parameter f jit-parameter ;
137 :: jit-conditional ( test-quot false-quot -- )
138 [ 0 test-quot call ] B{ } make length :> len
139 building get length jit-offset get + len +
140 [ jit-offset set false-quot call ] B{ } make
141 [ length test-quot call ] [ % ] bi ; inline
143 : make-jit ( quot -- jit-parameters jit-literals jit-code )
146 V{ } clone jit-parameters set
147 V{ } clone jit-literals set
148 V{ } clone jit-relocations set
150 jit-parameters get >array
151 jit-literals get >array
152 jit-relocations get >array
155 : jit-define ( quot name -- )
156 [ make-jit 2nip ] dip set ;
158 : define-sub-primitive ( quot word -- )
159 [ make-jit 3array ] dip sub-primitives get set-at ;
161 : define-combinator-primitive ( quot non-tail-quot tail-quot word -- )
168 sub-primitives get set-at ;
170 ! The image being constructed; a vector of word-size integers
173 ! Image output format
176 ! Bootstrap architecture name
181 ! Boot quotation, set in stage1.factor
182 SPECIAL-OBJECT: bootstrap-startup-quot 20
184 ! Bootstrap global namesapce
185 SPECIAL-OBJECT: bootstrap-global 21
188 SPECIAL-OBJECT: jit-prolog 23
189 SPECIAL-OBJECT: jit-primitive-word 24
190 SPECIAL-OBJECT: jit-primitive 25
191 SPECIAL-OBJECT: jit-word-jump 26
192 SPECIAL-OBJECT: jit-word-call 27
193 SPECIAL-OBJECT: jit-if-word 28
194 SPECIAL-OBJECT: jit-if 29
195 SPECIAL-OBJECT: jit-epilog 30
196 SPECIAL-OBJECT: jit-return 31
197 SPECIAL-OBJECT: jit-profiling 32
198 SPECIAL-OBJECT: jit-push 33
199 SPECIAL-OBJECT: jit-dip-word 34
200 SPECIAL-OBJECT: jit-dip 35
201 SPECIAL-OBJECT: jit-2dip-word 36
202 SPECIAL-OBJECT: jit-2dip 37
203 SPECIAL-OBJECT: jit-3dip-word 38
204 SPECIAL-OBJECT: jit-3dip 39
205 SPECIAL-OBJECT: jit-execute 40
206 SPECIAL-OBJECT: jit-declare-word 41
208 SPECIAL-OBJECT: c-to-factor-word 42
209 SPECIAL-OBJECT: lazy-jit-compile-word 43
210 SPECIAL-OBJECT: unwind-native-frames-word 44
211 SPECIAL-OBJECT: fpu-state-word 45
212 SPECIAL-OBJECT: set-fpu-state-word 46
214 SPECIAL-OBJECT: callback-stub 48
217 SPECIAL-OBJECT: pic-load 49
218 SPECIAL-OBJECT: pic-tag 50
219 SPECIAL-OBJECT: pic-tuple 51
220 SPECIAL-OBJECT: pic-check-tag 52
221 SPECIAL-OBJECT: pic-check-tuple 53
222 SPECIAL-OBJECT: pic-hit 54
223 SPECIAL-OBJECT: pic-miss-word 55
224 SPECIAL-OBJECT: pic-miss-tail-word 56
226 ! Megamorphic dispatch
227 SPECIAL-OBJECT: mega-lookup 57
228 SPECIAL-OBJECT: mega-lookup-word 58
229 SPECIAL-OBJECT: mega-miss-word 59
231 ! Default definition for undefined words
232 SPECIAL-OBJECT: undefined-quot 60
234 : special-object-offset ( symbol -- n )
235 special-objects get at header-size + ;
237 : emit ( cell -- ) image get push ;
239 : emit-64 ( cell -- )
243 d>w/w big-endian get [ swap ] unless emit emit
246 : emit-seq ( seq -- ) image get push-all ;
248 : fixup ( value offset -- ) image get set-nth ;
250 : heap-size ( -- size )
251 image get length header-size - special-objects-size -
254 : here ( -- size ) heap-size data-base + ;
256 : here-as ( tag -- pointer ) here bitor ;
258 : (align-here) ( alignment -- )
260 [ bootstrap-cell /i [ 0 emit ] times ] unless-zero ;
263 data-alignment get (align-here) ;
265 : emit-fixnum ( n -- ) tag-fixnum emit ;
267 : emit-header ( n -- ) tag-header emit ;
269 : emit-object ( class quot -- addr )
270 [ type-number ] dip over here-as
271 [ swap emit-header call align-here ] dip ;
274 ! Write an object to the image.
275 GENERIC: ' ( obj -- ptr )
279 : emit-image-header ( -- )
282 data-base emit ! relocation base at end of header
283 0 emit ! size of data heap set later
284 0 emit ! reloc base of code heap is 0
285 0 emit ! size of code heap is 0
286 0 emit ! pointer to t object
287 0 emit ! pointer to bignum 0
288 0 emit ! pointer to bignum 1
289 0 emit ! pointer to bignum -1
290 special-objects-size [ f ' emit ] times ;
292 : emit-special-object ( symbol -- )
293 [ get ' ] [ special-object-offset ] bi fixup ;
297 : bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
299 : bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
301 : bignum>seq ( n -- seq )
302 #! n is positive or zero.
304 [ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
307 : emit-bignum ( n -- )
308 dup dup 0 < [ neg ] when bignum>seq
309 [ nip length 1 + emit-fixnum ]
310 [ drop 0 < 1 0 ? emit ]
316 bignum [ emit-bignum ] emit-object
322 #! When generating a 32-bit image on a 64-bit system,
323 #! some fixnums should be bignums.
325 bootstrap-most-negative-fixnum
326 bootstrap-most-positive-fixnum between?
327 [ tag-fixnum ] [ >bignum ' ] if ;
329 TUPLE: fake-bignum n ;
331 C: <fake-bignum> fake-bignum
333 M: fake-bignum ' n>> tag-fixnum ;
340 8 (align-here) double>bits emit-64
346 ! Padded with fixnums for 8-byte alignment
348 : t, ( -- ) t t-offset fixup ;
350 M: f ' drop \ f type-number ;
352 : 0, ( -- ) 0 >bignum ' 0-offset fixup ;
353 : 1, ( -- ) 1 >bignum ' 1-offset fixup ;
354 : -1, ( -- ) -1 >bignum ' -1-offset fixup ;
358 : word-sub-primitive ( word -- obj )
359 global [ target-word ] bind sub-primitives get at ;
361 : emit-word ( word -- )
363 [ subwords [ emit-word ] each ]
367 [ hashcode <fake-bignum> , ]
375 [ word-sub-primitive , ]
378 [ drop 0 , ] ! profiling
382 \ word [ emit-seq ] emit-object
385 : word-error ( word msg -- * )
386 [ % dup vocabulary>> % " " % name>> % ] "" make throw ;
388 : transfer-word ( word -- word )
389 [ target-word ] keep or ;
391 : fixup-word ( word -- offset )
392 transfer-word dup lookup-object
393 [ ] [ "Not in image: " word-error ] ?if ;
396 image get [ dup word? [ fixup-word ] when ] map! drop ;
403 [ wrapped>> ' wrapper [ emit ] emit-object ] cache-eql-object ;
406 : native> ( object -- object )
407 big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
409 : emit-bytes ( seq -- )
410 bootstrap-cell <groups> native> emit-seq ;
412 : pad-bytes ( seq -- newseq )
413 dup length bootstrap-cell align 0 pad-tail ;
415 : extended-part ( str -- str' )
416 dup [ 128 < ] all? [ drop f ] [
417 [ -7 shift 1 bitxor ] { } map-as
419 [ [ 2 >be ] { } map-as ]
420 [ [ 2 >le ] { } map-as ] if
424 : ascii-part ( str -- str' )
426 [ 128 mod ] [ 128 >= ] bi
430 : emit-string ( string -- ptr )
431 [ length ] [ extended-part ' ] [ ] tri
435 [ f ' emit ascii-part pad-bytes emit-bytes ]
440 #! We pool strings so that each string is only written once
442 [ emit-string ] cache-eql-object ;
444 : assert-empty ( seq -- )
447 : emit-dummy-array ( obj type -- ptr )
449 [ 0 emit-fixnum ] emit-object
455 dup length emit-fixnum
456 bootstrap-cell 4 = [ 0 emit 0 emit ] when
462 ERROR: tuple-removed class ;
464 : require-tuple-layout ( word -- layout )
465 dup tuple-layout [ ] [ tuple-removed ] ?if ;
467 : (emit-tuple) ( tuple -- pointer )
469 [ class transfer-word require-tuple-layout ] bi prefix [ ' ] map
470 tuple [ emit-seq ] emit-object ;
472 : emit-tuple ( tuple -- pointer )
473 dup class name>> "tombstone" =
474 [ [ (emit-tuple) ] cache-eql-object ]
475 [ [ (emit-tuple) ] cache-eq-object ]
478 M: tuple ' emit-tuple ;
481 state>> "((tombstone))" "((empty))" ?
482 "hashtables.private" lookup def>> first
483 [ emit-tuple ] cache-eql-object ;
486 : emit-array ( array -- offset )
487 [ ' ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
489 M: array ' [ emit-array ] cache-eq-object ;
491 ! This is a hack. We need to detect arrays which are tuple
492 ! layout arrays so that they can be internalized, but making
493 ! them a built-in type is not worth it.
494 PREDICATE: tuple-layout-array < array
496 [ first tuple-class? ]
502 M: tuple-layout-array '
504 [ dup integer? [ <fake-bignum> ] when ] map
515 f ' emit ! cached-effect
516 f ' emit ! cache-counter
525 all-words [ emit-word ] each ;
529 dictionary source-files builtins
530 update-map implementors-map
531 } [ [ bootstrap-word ] [ get ] bi ] H{ } map>assoc
533 class<=-cache class-not-cache classes-intersect-cache
534 class-and-cache class-or-cache next-method-quot-cache
535 } [ H{ } clone ] H{ } map>assoc assoc-union
536 bootstrap-global set ;
538 : emit-jit-data ( -- )
540 \ do-primitive jit-primitive-word set
541 \ dip jit-dip-word set
542 \ 2dip jit-2dip-word set
543 \ 3dip jit-3dip-word set
544 \ inline-cache-miss pic-miss-word set
545 \ inline-cache-miss-tail pic-miss-tail-word set
546 \ mega-cache-lookup mega-lookup-word set
547 \ mega-cache-miss mega-miss-word set
548 \ declare jit-declare-word set
549 \ c-to-factor c-to-factor-word set
550 \ lazy-jit-compile lazy-jit-compile-word set
551 \ unwind-native-frames unwind-native-frames-word set
552 \ fpu-state fpu-state-word set
553 \ set-fpu-state set-fpu-state-word set
554 undefined-def undefined-quot set ;
556 : emit-special-objects ( -- )
557 special-objects get keys [ emit-special-object ] each ;
559 : fixup-header ( -- )
560 heap-size data-heap-size-offset fixup ;
562 : build-generics ( -- )
566 [ make-generic ] each
567 ] with-compilation-unit ;
569 : build-image ( -- image )
570 800000 <vector> image set
571 20000 <hashtable> objects set
572 emit-image-header t, 0, 1, -1,
573 "Building generic words..." print flush
575 "Serializing words..." print flush
577 "Serializing JIT data..." print flush
579 "Serializing global namespace..." print flush
581 "Serializing special object table..." print flush
583 "Performing word fixups..." print flush
585 "Performing header fixups..." print flush
587 "Image length: " write image get length .
588 "Object cache size: " write objects get assoc-size .
589 \ word global delete-at
594 : (write-image) ( image -- )
595 bootstrap-cell big-endian get
596 [ '[ _ >be write ] each ]
597 [ '[ _ >le write ] each ] if ;
599 : write-image ( image -- )
600 "Writing image to " write
601 architecture get boot-image-name resource-path
602 [ write "..." print flush ]
603 [ binary [ (write-image) ] with-file-writer ] bi ;
607 : make-image ( arch -- )
611 "resource:/core/bootstrap/stage1.factor" run-file
617 images [ make-image ] each ;