1 ! Copyright (C) 2004, 2011 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 combinators.smart strings sbufs vectors
7 words quotations assocs system layouts splitting grouping
8 growable classes 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 compiler.codegen.relocation fry locals
14 bootstrap.image.syntax 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 "windows-x86.64" "unix-x86.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 ] bi@ = ] [ (eql?) ] } 2&& ;
53 M: fixnum (eql?) eq? ;
57 M: float (eql?) fp-bitwise= ;
59 M: sequence (eql?) 2dup [ length ] bi@ = [ [ eql? ] 2all? ] [ 2drop f ] if ;
64 over eql-wrapper? [ [ obj>> ] bi@ eql? ] [ 2drop f ] if ;
66 TUPLE: eq-wrapper { obj read-only } ;
68 C: <eq-wrapper> eq-wrapper
71 over eq-wrapper? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
73 M: eq-wrapper hashcode*
74 nip obj>> identity-hashcode ;
78 : cache-eql-object ( obj quot -- value )
79 [ <eql-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
81 : cache-eq-object ( obj quot -- value )
82 [ <eq-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
84 : lookup-object ( obj -- n/f ) <eq-wrapper> objects get at ;
86 : put-object ( n obj -- ) <eq-wrapper> objects get set-at ;
90 CONSTANT: image-magic HEX: 0f0e0d0c
91 CONSTANT: image-version 4
93 CONSTANT: data-base 1024
95 CONSTANT: special-objects-size 80
97 CONSTANT: header-size 10
99 CONSTANT: data-heap-size-offset 3
103 CONSTANT: -1-offset 9
105 SYMBOL: sub-primitives
107 :: jit-conditional ( test-quot false-quot -- )
108 [ 0 test-quot call ] B{ } make length :> len
109 building get length extra-offset get + len +
110 [ extra-offset set false-quot call ] B{ } make
111 [ length test-quot call ] [ % ] bi ; inline
113 : make-jit ( quot -- parameters literals code )
114 #! code is a { relocation insns } pair
119 parameter-table get >array
120 literal-table get >array
121 relocation-table get >byte-array
124 : make-jit-no-params ( quot -- code )
127 : jit-define ( quot name -- )
128 [ make-jit-no-params ] dip set ;
130 : define-sub-primitive ( quot word -- )
131 [ make-jit 3array ] dip sub-primitives get set-at ;
133 : define-combinator-primitive ( quot non-tail-quot tail-quot word -- )
137 [ make-jit-no-params ]
138 [ make-jit-no-params ]
142 sub-primitives get set-at ;
144 ! The image being constructed; a vector of word-size integers
147 ! Image output format
150 ! Bootstrap architecture name
155 ! Boot quotation, set in stage1.factor
156 SPECIAL-OBJECT: bootstrap-startup-quot 20
158 ! Bootstrap global namesapce
159 SPECIAL-OBJECT: bootstrap-global 21
162 SPECIAL-OBJECT: jit-prolog 23
163 SPECIAL-OBJECT: jit-primitive-word 24
164 SPECIAL-OBJECT: jit-primitive 25
165 SPECIAL-OBJECT: jit-word-jump 26
166 SPECIAL-OBJECT: jit-word-call 27
167 SPECIAL-OBJECT: jit-if-word 28
168 SPECIAL-OBJECT: jit-if 29
169 SPECIAL-OBJECT: jit-epilog 30
170 SPECIAL-OBJECT: jit-return 31
171 SPECIAL-OBJECT: jit-profiling 32
172 SPECIAL-OBJECT: jit-push 33
173 SPECIAL-OBJECT: jit-dip-word 34
174 SPECIAL-OBJECT: jit-dip 35
175 SPECIAL-OBJECT: jit-2dip-word 36
176 SPECIAL-OBJECT: jit-2dip 37
177 SPECIAL-OBJECT: jit-3dip-word 38
178 SPECIAL-OBJECT: jit-3dip 39
179 SPECIAL-OBJECT: jit-execute 40
180 SPECIAL-OBJECT: jit-declare-word 41
182 SPECIAL-OBJECT: c-to-factor-word 42
183 SPECIAL-OBJECT: lazy-jit-compile-word 43
184 SPECIAL-OBJECT: unwind-native-frames-word 44
185 SPECIAL-OBJECT: fpu-state-word 45
186 SPECIAL-OBJECT: set-fpu-state-word 46
187 SPECIAL-OBJECT: signal-handler-word 47
188 SPECIAL-OBJECT: leaf-signal-handler-word 48
190 SPECIAL-OBJECT: callback-stub 50
193 SPECIAL-OBJECT: pic-load 51
194 SPECIAL-OBJECT: pic-tag 52
195 SPECIAL-OBJECT: pic-tuple 53
196 SPECIAL-OBJECT: pic-check-tag 54
197 SPECIAL-OBJECT: pic-check-tuple 55
198 SPECIAL-OBJECT: pic-hit 56
199 SPECIAL-OBJECT: pic-miss-word 57
200 SPECIAL-OBJECT: pic-miss-tail-word 58
202 ! Megamorphic dispatch
203 SPECIAL-OBJECT: mega-lookup 59
204 SPECIAL-OBJECT: mega-lookup-word 60
205 SPECIAL-OBJECT: mega-miss-word 61
207 ! Default definition for undefined words
208 SPECIAL-OBJECT: undefined-quot 62
210 : special-object-offset ( symbol -- n )
211 special-objects get at header-size + ;
213 : emit ( cell -- ) image get push ;
215 : emit-64 ( cell -- )
219 d>w/w big-endian get [ swap ] unless emit emit
222 : emit-seq ( seq -- ) image get push-all ;
224 : fixup ( value offset -- ) image get set-nth ;
226 : heap-size ( -- size )
227 image get length header-size - special-objects-size -
230 : here ( -- size ) heap-size data-base + ;
232 : here-as ( tag -- pointer ) here bitor ;
234 : (align-here) ( alignment -- )
236 [ bootstrap-cell /i [ 0 emit ] times ] unless-zero ;
239 data-alignment get (align-here) ;
241 : emit-fixnum ( n -- ) tag-fixnum emit ;
243 : emit-header ( n -- ) tag-header emit ;
245 : emit-object ( class quot -- addr )
246 [ type-number ] dip over here-as
247 [ swap emit-header call align-here ] dip ;
250 ! Write an object to the image.
251 GENERIC: ' ( obj -- ptr )
255 : emit-image-header ( -- )
258 data-base emit ! relocation base at end of header
259 0 emit ! size of data heap set later
260 0 emit ! reloc base of code heap is 0
261 0 emit ! size of code heap is 0
262 0 emit ! pointer to t object
263 0 emit ! pointer to bignum 0
264 0 emit ! pointer to bignum 1
265 0 emit ! pointer to bignum -1
266 special-objects-size [ f ' emit ] times ;
268 : emit-special-object ( symbol -- )
269 [ get ' ] [ special-object-offset ] bi fixup ;
273 : bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
275 : bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
277 : bignum>seq ( n -- seq )
278 #! n is positive or zero.
280 [ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
283 : emit-bignum ( n -- )
284 dup dup 0 < [ neg ] when bignum>seq
285 [ nip length 1 + emit-fixnum ]
286 [ drop 0 < 1 0 ? emit ]
292 bignum [ emit-bignum ] emit-object
298 #! When generating a 32-bit image on a 64-bit system,
299 #! some fixnums should be bignums.
301 bootstrap-most-negative-fixnum
302 bootstrap-most-positive-fixnum between?
303 [ tag-fixnum ] [ >bignum ' ] if ;
305 TUPLE: fake-bignum n ;
307 C: <fake-bignum> fake-bignum
309 M: fake-bignum ' n>> tag-fixnum ;
316 8 (align-here) double>bits emit-64
322 ! Padded with fixnums for 8-byte alignment
324 : t, ( -- ) t t-offset fixup ;
326 M: f ' drop \ f type-number ;
328 : 0, ( -- ) 0 >bignum ' 0-offset fixup ;
329 : 1, ( -- ) 1 >bignum ' 1-offset fixup ;
330 : -1, ( -- ) -1 >bignum ' -1-offset fixup ;
334 : word-sub-primitive ( word -- obj )
335 [ target-word ] with-global sub-primitives get at ;
337 : emit-word ( word -- )
339 [ subwords [ emit-word ] each ]
343 [ hashcode <fake-bignum> , ]
351 [ word-sub-primitive , ]
354 [ drop 0 , ] ! profiling
358 \ word [ emit-seq ] emit-object
361 : word-error ( word msg -- * )
362 [ % dup vocabulary>> % " " % name>> % ] "" make throw ;
364 : transfer-word ( word -- word )
365 [ target-word ] keep or ;
367 : fixup-word ( word -- offset )
368 transfer-word dup lookup-object
369 [ ] [ "Not in image: " word-error ] ?if ;
372 image get [ dup word? [ fixup-word ] when ] map! drop ;
379 [ wrapped>> ' wrapper [ emit ] emit-object ] cache-eql-object ;
382 : native> ( object -- object )
383 big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
385 : emit-bytes ( seq -- )
386 bootstrap-cell <groups> native> emit-seq ;
388 : pad-bytes ( seq -- newseq )
389 dup length bootstrap-cell align 0 pad-tail ;
391 : extended-part ( str -- str' )
392 dup [ 128 < ] all? [ drop f ] [
393 [ -7 shift 1 bitxor ] { } map-as
395 [ [ 2 >be ] { } map-as ]
396 [ [ 2 >le ] { } map-as ] if
400 : ascii-part ( str -- str' )
402 [ 128 mod ] [ 128 >= ] bi
406 : emit-string ( string -- ptr )
407 [ length ] [ extended-part ' ] [ ] tri
411 [ f ' emit ascii-part pad-bytes emit-bytes ]
416 #! We pool strings so that each string is only written once
418 [ emit-string ] cache-eql-object ;
420 : assert-empty ( seq -- )
423 : emit-dummy-array ( obj type -- ptr )
425 [ 0 emit-fixnum ] emit-object
431 dup length emit-fixnum
432 bootstrap-cell 4 = [ 0 emit 0 emit ] when
438 ERROR: tuple-removed class ;
440 : require-tuple-layout ( word -- layout )
441 dup tuple-layout [ ] [ tuple-removed ] ?if ;
443 : (emit-tuple) ( tuple -- pointer )
445 [ class-of transfer-word require-tuple-layout ] bi prefix [ ' ] map
446 tuple [ emit-seq ] emit-object ;
448 : emit-tuple ( tuple -- pointer )
449 dup class-of name>> "tombstone" =
450 [ [ (emit-tuple) ] cache-eql-object ]
451 [ [ (emit-tuple) ] cache-eq-object ]
454 M: tuple ' emit-tuple ;
457 state>> "((tombstone))" "((empty))" ?
458 "hashtables.private" lookup def>> first
459 [ emit-tuple ] cache-eql-object ;
462 : emit-array ( array -- offset )
463 [ ' ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
465 M: array ' [ emit-array ] cache-eq-object ;
467 ! This is a hack. We need to detect arrays which are tuple
468 ! layout arrays so that they can be internalized, but making
469 ! them a built-in type is not worth it.
470 PREDICATE: tuple-layout-array < array
472 [ first tuple-class? ]
478 M: tuple-layout-array '
480 [ dup integer? [ <fake-bignum> ] when ] map
491 f ' emit ! cached-effect
492 f ' emit ! cache-counter
501 all-words [ emit-word ] each ;
505 dictionary source-files builtins
506 update-map implementors-map
507 } [ [ bootstrap-word ] [ get ] bi ] H{ } map>assoc
509 class<=-cache class-not-cache classes-intersect-cache
510 class-and-cache class-or-cache next-method-quot-cache
511 } [ H{ } clone ] H{ } map>assoc assoc-union
512 bootstrap-global set ;
514 : emit-jit-data ( -- )
516 \ do-primitive jit-primitive-word set
517 \ dip jit-dip-word set
518 \ 2dip jit-2dip-word set
519 \ 3dip jit-3dip-word set
520 \ inline-cache-miss pic-miss-word set
521 \ inline-cache-miss-tail pic-miss-tail-word set
522 \ mega-cache-lookup mega-lookup-word set
523 \ mega-cache-miss mega-miss-word set
524 \ declare jit-declare-word set
525 \ c-to-factor c-to-factor-word set
526 \ lazy-jit-compile lazy-jit-compile-word set
527 \ unwind-native-frames unwind-native-frames-word set
528 \ fpu-state fpu-state-word set
529 \ set-fpu-state set-fpu-state-word set
530 \ signal-handler signal-handler-word set
531 \ leaf-signal-handler leaf-signal-handler-word set
532 undefined-def undefined-quot set ;
534 : emit-special-objects ( -- )
535 special-objects get keys [ emit-special-object ] each ;
537 : fixup-header ( -- )
538 heap-size data-heap-size-offset fixup ;
540 : build-generics ( -- )
544 [ make-generic ] each
545 ] with-compilation-unit ;
547 : build-image ( -- image )
548 800000 <vector> image set
549 20000 <hashtable> objects set
550 emit-image-header t, 0, 1, -1,
551 "Building generic words..." print flush
553 "Serializing words..." print flush
555 "Serializing JIT data..." print flush
557 "Serializing global namespace..." print flush
559 "Serializing special object table..." print flush
561 "Performing word fixups..." print flush
563 "Performing header fixups..." print flush
565 "Image length: " write image get length .
566 "Object cache size: " write objects get assoc-size .
567 \ word global delete-at
572 : (write-image) ( image -- )
573 bootstrap-cell big-endian get
574 [ '[ _ >be write ] each ]
575 [ '[ _ >le write ] each ] if ;
577 : write-image ( image -- )
578 "Writing image to " write
579 architecture get boot-image-name resource-path
580 [ write "..." print flush ]
581 [ binary [ (write-image) ] with-file-writer ] bi ;
585 : make-image ( arch -- )
590 "resource:/core/bootstrap/stage1.factor" run-file
596 images [ make-image ] each ;