1 ! Copyright (C) 2004, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien arrays byte-arrays generic hashtables hashtables.private
4 io io.binary io.files io.encodings.binary io.pathnames kernel
5 kernel.private math namespaces make parser prettyprint sequences
6 strings sbufs vectors words quotations assocs system layouts splitting
7 grouping growable classes classes.builtin classes.tuple
8 classes.tuple.private vocabs vocabs.loader source-files definitions
9 debugger quotations.private combinators math.order math.private
10 accessors slots.private generic.single.private compiler.units
11 compiler.constants fry bootstrap.image.syntax ;
14 : arch ( os cpu -- arch )
16 { "ppc" [ "-ppc" append ] }
17 { "x86.64" [ "winnt" = "winnt" "unix" ? "-x86.64" append ] }
22 os name>> cpu name>> arch ;
24 : boot-image-name ( arch -- string )
25 "boot." ".image" surround ;
27 : my-boot-image-name ( -- string )
28 my-arch boot-image-name ;
33 "winnt-x86.64" "unix-x86.64"
34 "linux-ppc" "macosx-ppc"
39 ! Object cache; we only consider numbers equal if they have the
41 TUPLE: eql-wrapper obj ;
43 C: <eql-wrapper> eql-wrapper
45 M: eql-wrapper hashcode* obj>> hashcode* ;
47 GENERIC: (eql?) ( obj1 obj2 -- ? )
49 : eql? ( obj1 obj2 -- ? )
50 [ (eql?) ] [ [ class ] bi@ = ] 2bi and ;
55 over float? [ fp-bitwise= ] [ 2drop f ] if ;
60 [ [ eql? ] 2all? ] [ 2drop f ] if
66 over eql-wrapper? [ [ obj>> ] bi@ eql? ] [ 2drop f ] if ;
68 TUPLE: eq-wrapper obj ;
70 C: <eq-wrapper> eq-wrapper
73 over eq-wrapper? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
77 : cache-eql-object ( obj quot -- value )
78 [ <eql-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
80 : cache-eq-object ( obj quot -- value )
81 [ <eq-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
83 : lookup-object ( obj -- n/f ) <eq-wrapper> objects get at ;
85 : put-object ( n obj -- ) <eq-wrapper> objects get set-at ;
89 CONSTANT: image-magic HEX: 0f0e0d0c
90 CONSTANT: image-version 4
92 CONSTANT: data-base 1024
94 CONSTANT: userenv-size 70
96 CONSTANT: header-size 10
98 CONSTANT: data-heap-size-offset 3
102 CONSTANT: -1-offset 9
104 SYMBOL: sub-primitives
106 SYMBOL: jit-relocations
108 : compute-offset ( rc -- offset )
109 [ building get length ] dip rc-absolute-cell = bootstrap-cell 4 ? - ;
111 : jit-rel ( rc rt -- )
112 over compute-offset 3array jit-relocations get push-all ;
116 : jit-literal ( literal -- )
117 jit-literals get push ;
119 : make-jit ( quot -- jit-literals jit-data )
121 V{ } clone jit-literals set
122 V{ } clone jit-relocations set
124 jit-literals get >array
125 jit-relocations get >array
128 : jit-define ( quot name -- )
129 [ make-jit nip ] dip set ;
131 : define-sub-primitive ( quot word -- )
132 [ make-jit 2array ] dip sub-primitives get set-at ;
134 ! The image being constructed; a vector of word-size integers
137 ! Image output format
140 ! Bootstrap architecture name
145 ! Boot quotation, set in stage1.factor
146 USERENV: bootstrap-boot-quot 20
148 ! Bootstrap global namesapce
149 USERENV: bootstrap-global 21
152 USERENV: jit-prolog 23
153 USERENV: jit-primitive-word 24
154 USERENV: jit-primitive 25
155 USERENV: jit-word-jump 26
156 USERENV: jit-word-call 27
157 USERENV: jit-word-special 28
158 USERENV: jit-if-word 29
160 USERENV: jit-epilog 31
161 USERENV: jit-return 32
162 USERENV: jit-profiling 33
163 USERENV: jit-push-immediate 34
164 USERENV: jit-dip-word 35
166 USERENV: jit-2dip-word 37
168 USERENV: jit-3dip-word 39
170 USERENV: jit-execute-word 41
171 USERENV: jit-execute-jump 42
172 USERENV: jit-execute-call 43
173 USERENV: jit-declare-word 44
175 USERENV: callback-stub 45
180 USERENV: pic-hi-tag 49
181 USERENV: pic-tuple 50
182 USERENV: pic-hi-tag-tuple 51
183 USERENV: pic-check-tag 52
184 USERENV: pic-check 53
186 USERENV: pic-miss-word 55
187 USERENV: pic-miss-tail-word 56
189 ! Megamorphic dispatch
190 USERENV: mega-lookup 57
191 USERENV: mega-lookup-word 58
192 USERENV: mega-miss-word 59
194 ! Default definition for undefined words
195 USERENV: undefined-quot 60
197 : userenv-offset ( symbol -- n )
198 userenvs get at header-size + ;
200 : emit ( cell -- ) image get push ;
202 : emit-64 ( cell -- )
206 d>w/w big-endian get [ swap ] unless emit emit
209 : emit-seq ( seq -- ) image get push-all ;
211 : fixup ( value offset -- ) image get set-nth ;
213 : heap-size ( -- size )
214 image get length header-size - userenv-size -
217 : here ( -- size ) heap-size data-base + ;
219 : here-as ( tag -- pointer ) here bitor ;
221 : (align-here) ( alignment -- )
223 [ bootstrap-cell /i [ 0 emit ] times ] unless-zero ;
226 data-alignment get (align-here) ;
228 : emit-fixnum ( n -- ) tag-fixnum emit ;
230 : emit-object ( class quot -- addr )
231 over tag-number here-as [ swap type-number tag-fixnum emit call align-here ] dip ;
234 ! Write an object to the image.
235 GENERIC: ' ( obj -- ptr )
242 data-base emit ! relocation base at end of header
243 0 emit ! size of data heap set later
244 0 emit ! reloc base of code heap is 0
245 0 emit ! size of code heap is 0
246 0 emit ! pointer to t object
247 0 emit ! pointer to bignum 0
248 0 emit ! pointer to bignum 1
249 0 emit ! pointer to bignum -1
250 userenv-size [ f ' emit ] times ;
252 : emit-userenv ( symbol -- )
253 [ get ' ] [ userenv-offset ] bi fixup ;
257 : bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
259 : bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
261 : bignum>seq ( n -- seq )
262 #! n is positive or zero.
264 [ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
267 : emit-bignum ( n -- )
268 dup dup 0 < [ neg ] when bignum>seq
269 [ nip length 1 + emit-fixnum ]
270 [ drop 0 < 1 0 ? emit ]
276 bignum [ emit-bignum ] emit-object
282 #! When generating a 32-bit image on a 64-bit system,
283 #! some fixnums should be bignums.
285 bootstrap-most-negative-fixnum
286 bootstrap-most-positive-fixnum between?
287 [ tag-fixnum ] [ >bignum ' ] if ;
289 TUPLE: fake-bignum n ;
291 C: <fake-bignum> fake-bignum
293 M: fake-bignum ' n>> tag-fixnum ;
300 8 (align-here) double>bits emit-64
306 ! Padded with fixnums for 8-byte alignment
308 : t, ( -- ) t t-offset fixup ;
311 #! f is #define F RETAG(0,F_TYPE)
312 drop \ f tag-number ;
314 : 0, ( -- ) 0 >bignum ' 0-offset fixup ;
315 : 1, ( -- ) 1 >bignum ' 1-offset fixup ;
316 : -1, ( -- ) -1 >bignum ' -1-offset fixup ;
320 : word-sub-primitive ( word -- obj )
321 global [ target-word ] bind sub-primitives get at ;
323 : emit-word ( word -- )
325 [ subwords [ emit-word ] each ]
329 [ hashcode <fake-bignum> , ]
337 [ word-sub-primitive , ]
340 [ drop 0 , ] ! profiling
344 \ word [ emit-seq ] emit-object
347 : word-error ( word msg -- * )
348 [ % dup vocabulary>> % " " % name>> % ] "" make throw ;
350 : transfer-word ( word -- word )
351 [ target-word ] keep or ;
353 : fixup-word ( word -- offset )
354 transfer-word dup lookup-object
355 [ ] [ "Not in image: " word-error ] ?if ;
358 image get [ dup word? [ fixup-word ] when ] map! drop ;
365 [ wrapped>> ' wrapper [ emit ] emit-object ] cache-eql-object ;
368 : native> ( object -- object )
369 big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
371 : emit-bytes ( seq -- )
372 bootstrap-cell <groups> native> emit-seq ;
374 : pad-bytes ( seq -- newseq )
375 dup length bootstrap-cell align 0 pad-tail ;
377 : extended-part ( str -- str' )
378 dup [ 128 < ] all? [ drop f ] [
379 [ -7 shift 1 bitxor ] { } map-as
381 [ [ 2 >be ] { } map-as ]
382 [ [ 2 >le ] { } map-as ] if
386 : ascii-part ( str -- str' )
388 [ 128 mod ] [ 128 >= ] bi
392 : emit-string ( string -- ptr )
393 [ length ] [ extended-part ' ] [ ] tri
397 [ f ' emit ascii-part pad-bytes emit-bytes ]
402 #! We pool strings so that each string is only written once
404 [ emit-string ] cache-eql-object ;
406 : assert-empty ( seq -- )
409 : emit-dummy-array ( obj type -- ptr )
411 [ 0 emit-fixnum ] emit-object
417 dup length emit-fixnum
418 bootstrap-cell 4 = [ 0 emit 0 emit ] when
424 ERROR: tuple-removed class ;
426 : require-tuple-layout ( word -- layout )
427 dup tuple-layout [ ] [ tuple-removed ] ?if ;
429 : (emit-tuple) ( tuple -- pointer )
431 [ class transfer-word require-tuple-layout ] bi prefix [ ' ] map
432 tuple [ emit-seq ] emit-object ;
434 : emit-tuple ( tuple -- pointer )
435 dup class name>> "tombstone" =
436 [ [ (emit-tuple) ] cache-eql-object ]
437 [ [ (emit-tuple) ] cache-eq-object ]
440 M: tuple ' emit-tuple ;
443 state>> "((tombstone))" "((empty))" ?
444 "hashtables.private" lookup def>> first
445 [ emit-tuple ] cache-eql-object ;
448 : emit-array ( array -- offset )
449 [ ' ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
451 M: array ' [ emit-array ] cache-eq-object ;
453 ! This is a hack. We need to detect arrays which are tuple
454 ! layout arrays so that they can be internalized, but making
455 ! them a built-in type is not worth it.
456 PREDICATE: tuple-layout-array < array
458 [ first tuple-class? ]
464 M: tuple-layout-array '
466 [ dup integer? [ <fake-bignum> ] when ] map
477 f ' emit ! cached-effect
478 f ' emit ! cache-counter
487 all-words [ emit-word ] each ;
491 dictionary source-files builtins
492 update-map implementors-map
493 } [ [ bootstrap-word ] [ get ] bi ] H{ } map>assoc
495 class<=-cache class-not-cache classes-intersect-cache
496 class-and-cache class-or-cache next-method-quot-cache
497 } [ H{ } clone ] H{ } map>assoc assoc-union
498 bootstrap-global set ;
500 : emit-jit-data ( -- )
502 \ do-primitive jit-primitive-word set
503 \ dip jit-dip-word set
504 \ 2dip jit-2dip-word set
505 \ 3dip jit-3dip-word set
506 \ (execute) jit-execute-word set
507 \ inline-cache-miss \ pic-miss-word set
508 \ inline-cache-miss-tail \ pic-miss-tail-word set
509 \ mega-cache-lookup \ mega-lookup-word set
510 \ mega-cache-miss \ mega-miss-word set
511 \ declare jit-declare-word set
512 [ undefined ] undefined-quot set ;
514 : emit-userenvs ( -- )
515 userenvs get keys [ emit-userenv ] each ;
517 : fixup-header ( -- )
518 heap-size data-heap-size-offset fixup ;
520 : build-image ( -- image )
521 800000 <vector> image set
522 20000 <hashtable> objects set
523 emit-header t, 0, 1, -1,
524 "Building generic words..." print flush
526 "Serializing words..." print flush
528 "Serializing JIT data..." print flush
530 "Serializing global namespace..." print flush
532 "Serializing user environment..." print flush
534 "Performing word fixups..." print flush
536 "Performing header fixups..." print flush
538 "Image length: " write image get length .
539 "Object cache size: " write objects get assoc-size .
540 \ word global delete-at
545 : (write-image) ( image -- )
546 bootstrap-cell big-endian get
547 [ '[ _ >be write ] each ]
548 [ '[ _ >le write ] each ] if ;
550 : write-image ( image -- )
551 "Writing image to " write
552 architecture get boot-image-name resource-path
553 [ write "..." print flush ]
554 [ binary [ (write-image) ] with-file-writer ] bi ;
558 : make-image ( arch -- )
561 "resource:/core/bootstrap/stage1.factor" run-file
567 images [ make-image ] each ;