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 strings sbufs vectors words quotations
7 assocs system layouts splitting grouping growable classes
8 classes.private classes.builtin classes.tuple
9 classes.tuple.private vocabs vocabs.loader source-files
10 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
17 : arch ( os cpu -- arch )
19 { "ppc" [ "-ppc" append ] }
20 { "x86.64" [ "winnt" = "winnt" "unix" ? "-x86.64" append ] }
25 os name>> cpu name>> arch ;
27 : boot-image-name ( arch -- string )
28 "boot." ".image" surround ;
30 : my-boot-image-name ( -- string )
31 my-arch boot-image-name ;
36 "winnt-x86.64" "unix-x86.64"
37 "linux-ppc" "macosx-ppc"
42 ! Object cache; we only consider numbers equal if they have the
44 TUPLE: eql-wrapper { obj read-only } ;
46 C: <eql-wrapper> eql-wrapper
48 M: eql-wrapper hashcode* obj>> hashcode* ;
50 GENERIC: (eql?) ( obj1 obj2 -- ? )
52 : eql? ( obj1 obj2 -- ? )
53 { [ [ class ] bi@ = ] [ (eql?) ] } 2&& ;
55 M: fixnum (eql?) eq? ;
59 M: float (eql?) fp-bitwise= ;
61 M: sequence (eql?) 2dup [ length ] bi@ = [ [ eql? ] 2all? ] [ 2drop f ] if ;
66 over eql-wrapper? [ [ obj>> ] bi@ eql? ] [ 2drop f ] if ;
68 TUPLE: eq-wrapper { obj read-only } ;
70 C: <eq-wrapper> eq-wrapper
73 over eq-wrapper? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
75 M: eq-wrapper hashcode*
76 nip obj>> identity-hashcode ;
80 : cache-eql-object ( obj quot -- value )
81 [ <eql-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
83 : cache-eq-object ( obj quot -- value )
84 [ <eq-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
86 : lookup-object ( obj -- n/f ) <eq-wrapper> objects get at ;
88 : put-object ( n obj -- ) <eq-wrapper> objects get set-at ;
92 CONSTANT: image-magic HEX: 0f0e0d0c
93 CONSTANT: image-version 4
95 CONSTANT: data-base 1024
97 CONSTANT: special-objects-size 70
99 CONSTANT: header-size 10
101 CONSTANT: data-heap-size-offset 3
105 CONSTANT: -1-offset 9
107 SYMBOL: sub-primitives
109 SYMBOL: jit-relocations
113 : compute-offset ( -- offset )
114 building get length jit-offset get + ;
116 : jit-rel ( rc rt -- )
117 compute-offset 3array jit-relocations get push-all ;
119 SYMBOL: jit-parameters
121 : jit-parameter ( parameter -- )
122 jit-parameters get push ;
126 : jit-literal ( literal -- )
127 jit-literals get push ;
129 : jit-vm ( offset rc -- )
130 [ jit-parameter ] dip rt-vm jit-rel ;
132 : jit-dlsym ( name rc -- )
133 rt-dlsym jit-rel string>symbol jit-parameter f jit-parameter ;
135 :: jit-conditional ( test-quot false-quot -- )
136 [ 0 test-quot call ] B{ } make length :> len
137 building get length jit-offset get + len +
138 [ jit-offset set false-quot call ] B{ } make
139 [ length test-quot call ] [ % ] bi ; inline
141 : make-jit ( quot -- jit-parameters jit-literals jit-code )
144 V{ } clone jit-parameters set
145 V{ } clone jit-literals set
146 V{ } clone jit-relocations set
148 jit-parameters get >array
149 jit-literals get >array
150 jit-relocations get >array
153 : jit-define ( quot name -- )
154 [ make-jit 2nip ] dip set ;
156 : define-sub-primitive ( quot word -- )
157 [ make-jit 3array ] dip sub-primitives get set-at ;
159 : define-combinator-primitive ( quot non-tail-quot tail-quot word -- )
166 sub-primitives get set-at ;
168 ! The image being constructed; a vector of word-size integers
171 ! Image output format
174 ! Bootstrap architecture name
179 ! Boot quotation, set in stage1.factor
180 SPECIAL-OBJECT: bootstrap-startup-quot 20
182 ! Bootstrap global namesapce
183 SPECIAL-OBJECT: bootstrap-global 21
186 SPECIAL-OBJECT: jit-prolog 23
187 SPECIAL-OBJECT: jit-primitive-word 24
188 SPECIAL-OBJECT: jit-primitive 25
189 SPECIAL-OBJECT: jit-word-jump 26
190 SPECIAL-OBJECT: jit-word-call 27
191 SPECIAL-OBJECT: jit-if-word 28
192 SPECIAL-OBJECT: jit-if 29
193 SPECIAL-OBJECT: jit-epilog 30
194 SPECIAL-OBJECT: jit-return 31
195 SPECIAL-OBJECT: jit-profiling 32
196 SPECIAL-OBJECT: jit-push 33
197 SPECIAL-OBJECT: jit-dip-word 34
198 SPECIAL-OBJECT: jit-dip 35
199 SPECIAL-OBJECT: jit-2dip-word 36
200 SPECIAL-OBJECT: jit-2dip 37
201 SPECIAL-OBJECT: jit-3dip-word 38
202 SPECIAL-OBJECT: jit-3dip 39
203 SPECIAL-OBJECT: jit-execute 40
204 SPECIAL-OBJECT: jit-declare-word 41
206 SPECIAL-OBJECT: c-to-factor-word 42
207 SPECIAL-OBJECT: lazy-jit-compile-word 43
208 SPECIAL-OBJECT: unwind-native-frames-word 44
210 SPECIAL-OBJECT: callback-stub 48
213 SPECIAL-OBJECT: pic-load 49
214 SPECIAL-OBJECT: pic-tag 50
215 SPECIAL-OBJECT: pic-tuple 51
216 SPECIAL-OBJECT: pic-check-tag 52
217 SPECIAL-OBJECT: pic-check-tuple 53
218 SPECIAL-OBJECT: pic-hit 54
219 SPECIAL-OBJECT: pic-miss-word 55
220 SPECIAL-OBJECT: pic-miss-tail-word 56
222 ! Megamorphic dispatch
223 SPECIAL-OBJECT: mega-lookup 57
224 SPECIAL-OBJECT: mega-lookup-word 58
225 SPECIAL-OBJECT: mega-miss-word 59
227 ! Default definition for undefined words
228 SPECIAL-OBJECT: undefined-quot 60
230 : special-object-offset ( symbol -- n )
231 special-objects get at header-size + ;
233 : emit ( cell -- ) image get push ;
235 : emit-64 ( cell -- )
239 d>w/w big-endian get [ swap ] unless emit emit
242 : emit-seq ( seq -- ) image get push-all ;
244 : fixup ( value offset -- ) image get set-nth ;
246 : heap-size ( -- size )
247 image get length header-size - special-objects-size -
250 : here ( -- size ) heap-size data-base + ;
252 : here-as ( tag -- pointer ) here bitor ;
254 : (align-here) ( alignment -- )
256 [ bootstrap-cell /i [ 0 emit ] times ] unless-zero ;
259 data-alignment get (align-here) ;
261 : emit-fixnum ( n -- ) tag-fixnum emit ;
263 : emit-header ( n -- ) tag-header emit ;
265 : emit-object ( class quot -- addr )
266 [ type-number ] dip over here-as
267 [ swap emit-header call align-here ] dip ;
270 ! Write an object to the image.
271 GENERIC: ' ( obj -- ptr )
275 : emit-image-header ( -- )
278 data-base emit ! relocation base at end of header
279 0 emit ! size of data heap set later
280 0 emit ! reloc base of code heap is 0
281 0 emit ! size of code heap is 0
282 0 emit ! pointer to t object
283 0 emit ! pointer to bignum 0
284 0 emit ! pointer to bignum 1
285 0 emit ! pointer to bignum -1
286 special-objects-size [ f ' emit ] times ;
288 : emit-special-object ( symbol -- )
289 [ get ' ] [ special-object-offset ] bi fixup ;
293 : bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
295 : bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
297 : bignum>seq ( n -- seq )
298 #! n is positive or zero.
300 [ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
303 : emit-bignum ( n -- )
304 dup dup 0 < [ neg ] when bignum>seq
305 [ nip length 1 + emit-fixnum ]
306 [ drop 0 < 1 0 ? emit ]
312 bignum [ emit-bignum ] emit-object
318 #! When generating a 32-bit image on a 64-bit system,
319 #! some fixnums should be bignums.
321 bootstrap-most-negative-fixnum
322 bootstrap-most-positive-fixnum between?
323 [ tag-fixnum ] [ >bignum ' ] if ;
325 TUPLE: fake-bignum n ;
327 C: <fake-bignum> fake-bignum
329 M: fake-bignum ' n>> tag-fixnum ;
336 8 (align-here) double>bits emit-64
342 ! Padded with fixnums for 8-byte alignment
344 : t, ( -- ) t t-offset fixup ;
346 M: f ' drop \ f type-number ;
348 : 0, ( -- ) 0 >bignum ' 0-offset fixup ;
349 : 1, ( -- ) 1 >bignum ' 1-offset fixup ;
350 : -1, ( -- ) -1 >bignum ' -1-offset fixup ;
354 : word-sub-primitive ( word -- obj )
355 global [ target-word ] bind sub-primitives get at ;
357 : emit-word ( word -- )
359 [ subwords [ emit-word ] each ]
363 [ hashcode <fake-bignum> , ]
371 [ word-sub-primitive , ]
374 [ drop 0 , ] ! profiling
378 \ word [ emit-seq ] emit-object
381 : word-error ( word msg -- * )
382 [ % dup vocabulary>> % " " % name>> % ] "" make throw ;
384 : transfer-word ( word -- word )
385 [ target-word ] keep or ;
387 : fixup-word ( word -- offset )
388 transfer-word dup lookup-object
389 [ ] [ "Not in image: " word-error ] ?if ;
392 image get [ dup word? [ fixup-word ] when ] map! drop ;
399 [ wrapped>> ' wrapper [ emit ] emit-object ] cache-eql-object ;
402 : native> ( object -- object )
403 big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
405 : emit-bytes ( seq -- )
406 bootstrap-cell <groups> native> emit-seq ;
408 : pad-bytes ( seq -- newseq )
409 dup length bootstrap-cell align 0 pad-tail ;
411 : extended-part ( str -- str' )
412 dup [ 128 < ] all? [ drop f ] [
413 [ -7 shift 1 bitxor ] { } map-as
415 [ [ 2 >be ] { } map-as ]
416 [ [ 2 >le ] { } map-as ] if
420 : ascii-part ( str -- str' )
422 [ 128 mod ] [ 128 >= ] bi
426 : emit-string ( string -- ptr )
427 [ length ] [ extended-part ' ] [ ] tri
431 [ f ' emit ascii-part pad-bytes emit-bytes ]
436 #! We pool strings so that each string is only written once
438 [ emit-string ] cache-eql-object ;
440 : assert-empty ( seq -- )
443 : emit-dummy-array ( obj type -- ptr )
445 [ 0 emit-fixnum ] emit-object
451 dup length emit-fixnum
452 bootstrap-cell 4 = [ 0 emit 0 emit ] when
458 ERROR: tuple-removed class ;
460 : require-tuple-layout ( word -- layout )
461 dup tuple-layout [ ] [ tuple-removed ] ?if ;
463 : (emit-tuple) ( tuple -- pointer )
465 [ class transfer-word require-tuple-layout ] bi prefix [ ' ] map
466 tuple [ emit-seq ] emit-object ;
468 : emit-tuple ( tuple -- pointer )
469 dup class name>> "tombstone" =
470 [ [ (emit-tuple) ] cache-eql-object ]
471 [ [ (emit-tuple) ] cache-eq-object ]
474 M: tuple ' emit-tuple ;
477 state>> "((tombstone))" "((empty))" ?
478 "hashtables.private" lookup def>> first
479 [ emit-tuple ] cache-eql-object ;
482 : emit-array ( array -- offset )
483 [ ' ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
485 M: array ' [ emit-array ] cache-eq-object ;
487 ! This is a hack. We need to detect arrays which are tuple
488 ! layout arrays so that they can be internalized, but making
489 ! them a built-in type is not worth it.
490 PREDICATE: tuple-layout-array < array
492 [ first tuple-class? ]
498 M: tuple-layout-array '
500 [ dup integer? [ <fake-bignum> ] when ] map
511 f ' emit ! cached-effect
512 f ' emit ! cache-counter
521 all-words [ emit-word ] each ;
525 dictionary source-files builtins
526 update-map implementors-map
527 } [ [ bootstrap-word ] [ get ] bi ] H{ } map>assoc
529 class<=-cache class-not-cache classes-intersect-cache
530 class-and-cache class-or-cache next-method-quot-cache
531 } [ H{ } clone ] H{ } map>assoc assoc-union
532 bootstrap-global set ;
534 : emit-jit-data ( -- )
536 \ do-primitive jit-primitive-word set
537 \ dip jit-dip-word set
538 \ 2dip jit-2dip-word set
539 \ 3dip jit-3dip-word set
540 \ inline-cache-miss pic-miss-word set
541 \ inline-cache-miss-tail pic-miss-tail-word set
542 \ mega-cache-lookup mega-lookup-word set
543 \ mega-cache-miss mega-miss-word set
544 \ declare jit-declare-word set
545 \ c-to-factor c-to-factor-word set
546 \ lazy-jit-compile lazy-jit-compile-word set
547 \ unwind-native-frames unwind-native-frames-word set
548 undefined-def undefined-quot set ;
550 : emit-special-objects ( -- )
551 special-objects get keys [ emit-special-object ] each ;
553 : fixup-header ( -- )
554 heap-size data-heap-size-offset fixup ;
556 : build-generics ( -- )
560 [ make-generic ] each
561 ] with-compilation-unit ;
563 : build-image ( -- image )
564 800000 <vector> image set
565 20000 <hashtable> objects set
566 emit-image-header t, 0, 1, -1,
567 "Building generic words..." print flush
569 "Serializing words..." print flush
571 "Serializing JIT data..." print flush
573 "Serializing global namespace..." print flush
575 "Serializing special object table..." print flush
577 "Performing word fixups..." print flush
579 "Performing header fixups..." print flush
581 "Image length: " write image get length .
582 "Object cache size: " write objects get assoc-size .
583 \ word global delete-at
588 : (write-image) ( image -- )
589 bootstrap-cell big-endian get
590 [ '[ _ >be write ] each ]
591 [ '[ _ >le write ] each ] if ;
593 : write-image ( image -- )
594 "Writing image to " write
595 architecture get boot-image-name resource-path
596 [ write "..." print flush ]
597 [ binary [ (write-image) ] with-file-writer ] bi ;
601 : make-image ( arch -- )
604 "resource:/core/bootstrap/stage1.factor" run-file
610 images [ make-image ] each ;