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
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.builtin classes.tuple classes.tuple.private vocabs
9 vocabs.loader source-files definitions debugger
10 quotations.private combinators combinators.short-circuit
11 math.order math.private accessors slots.private
12 generic.single.private compiler.units compiler.constants fry
13 bootstrap.image.syntax ;
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
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 ;
76 : cache-eql-object ( obj quot -- value )
77 [ <eql-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
79 : cache-eq-object ( obj quot -- value )
80 [ <eq-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
82 : lookup-object ( obj -- n/f ) <eq-wrapper> objects get at ;
84 : put-object ( n obj -- ) <eq-wrapper> objects get set-at ;
88 CONSTANT: image-magic HEX: 0f0e0d0c
89 CONSTANT: image-version 4
91 CONSTANT: data-base 1024
93 CONSTANT: userenv-size 70
95 CONSTANT: header-size 10
97 CONSTANT: data-heap-size-offset 3
101 CONSTANT: -1-offset 9
103 SYMBOL: sub-primitives
105 SYMBOL: jit-relocations
107 : compute-offset ( rc -- offset )
108 [ building get length ] dip rc-absolute-cell = bootstrap-cell 4 ? - ;
110 : jit-rel ( rc rt -- )
111 over compute-offset 3array jit-relocations get push-all ;
115 : jit-literal ( literal -- )
116 jit-literals get push ;
118 : make-jit ( quot -- jit-literals jit-data )
120 V{ } clone jit-literals set
121 V{ } clone jit-relocations set
123 jit-literals get >array
124 jit-relocations get >array
127 : jit-define ( quot name -- )
128 [ make-jit nip ] dip set ;
130 : define-sub-primitive ( quot word -- )
131 [ make-jit 2array ] dip sub-primitives get set-at ;
133 ! The image being constructed; a vector of word-size integers
136 ! Image output format
139 ! Bootstrap architecture name
144 ! Boot quotation, set in stage1.factor
145 USERENV: bootstrap-boot-quot 20
147 ! Bootstrap global namesapce
148 USERENV: bootstrap-global 21
151 USERENV: jit-prolog 23
152 USERENV: jit-primitive-word 24
153 USERENV: jit-primitive 25
154 USERENV: jit-word-jump 26
155 USERENV: jit-word-call 27
156 USERENV: jit-word-special 28
157 USERENV: jit-if-word 29
159 USERENV: jit-epilog 31
160 USERENV: jit-return 32
161 USERENV: jit-profiling 33
162 USERENV: jit-push-immediate 34
163 USERENV: jit-dip-word 35
165 USERENV: jit-2dip-word 37
167 USERENV: jit-3dip-word 39
169 USERENV: jit-execute-word 41
170 USERENV: jit-execute-jump 42
171 USERENV: jit-execute-call 43
172 USERENV: jit-declare-word 44
174 USERENV: callback-stub 45
179 USERENV: pic-tuple 49
180 USERENV: pic-check-tag 50
181 USERENV: pic-check-tuple 51
183 USERENV: pic-miss-word 53
184 USERENV: pic-miss-tail-word 54
186 ! Megamorphic dispatch
187 USERENV: mega-lookup 57
188 USERENV: mega-lookup-word 58
189 USERENV: mega-miss-word 59
191 ! Default definition for undefined words
192 USERENV: undefined-quot 60
194 : userenv-offset ( symbol -- n )
195 userenvs get at header-size + ;
197 : emit ( cell -- ) image get push ;
199 : emit-64 ( cell -- )
203 d>w/w big-endian get [ swap ] unless emit emit
206 : emit-seq ( seq -- ) image get push-all ;
208 : fixup ( value offset -- ) image get set-nth ;
210 : heap-size ( -- size )
211 image get length header-size - userenv-size -
214 : here ( -- size ) heap-size data-base + ;
216 : here-as ( tag -- pointer ) here bitor ;
218 : (align-here) ( alignment -- )
220 [ bootstrap-cell /i [ 0 emit ] times ] unless-zero ;
223 data-alignment get (align-here) ;
225 : emit-fixnum ( n -- ) tag-fixnum emit ;
227 : emit-object ( class quot -- addr )
228 [ type-number ] dip over here-as
229 [ swap tag-fixnum emit call align-here ] dip ;
232 ! Write an object to the image.
233 GENERIC: ' ( obj -- ptr )
240 data-base emit ! relocation base at end of header
241 0 emit ! size of data heap set later
242 0 emit ! reloc base of code heap is 0
243 0 emit ! size of code heap is 0
244 0 emit ! pointer to t object
245 0 emit ! pointer to bignum 0
246 0 emit ! pointer to bignum 1
247 0 emit ! pointer to bignum -1
248 userenv-size [ f ' emit ] times ;
250 : emit-userenv ( symbol -- )
251 [ get ' ] [ userenv-offset ] bi fixup ;
255 : bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
257 : bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
259 : bignum>seq ( n -- seq )
260 #! n is positive or zero.
262 [ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
265 : emit-bignum ( n -- )
266 dup dup 0 < [ neg ] when bignum>seq
267 [ nip length 1 + emit-fixnum ]
268 [ drop 0 < 1 0 ? emit ]
274 bignum [ emit-bignum ] emit-object
280 #! When generating a 32-bit image on a 64-bit system,
281 #! some fixnums should be bignums.
283 bootstrap-most-negative-fixnum
284 bootstrap-most-positive-fixnum between?
285 [ tag-fixnum ] [ >bignum ' ] if ;
287 TUPLE: fake-bignum n ;
289 C: <fake-bignum> fake-bignum
291 M: fake-bignum ' n>> tag-fixnum ;
298 8 (align-here) double>bits emit-64
304 ! Padded with fixnums for 8-byte alignment
306 : t, ( -- ) t t-offset fixup ;
309 #! f is #define F RETAG(0,F_TYPE)
310 drop \ f type-number ;
312 : 0, ( -- ) 0 >bignum ' 0-offset fixup ;
313 : 1, ( -- ) 1 >bignum ' 1-offset fixup ;
314 : -1, ( -- ) -1 >bignum ' -1-offset fixup ;
318 : word-sub-primitive ( word -- obj )
319 global [ target-word ] bind sub-primitives get at ;
321 : emit-word ( word -- )
323 [ subwords [ emit-word ] each ]
327 [ hashcode <fake-bignum> , ]
335 [ word-sub-primitive , ]
338 [ drop 0 , ] ! profiling
342 \ word [ emit-seq ] emit-object
345 : word-error ( word msg -- * )
346 [ % dup vocabulary>> % " " % name>> % ] "" make throw ;
348 : transfer-word ( word -- word )
349 [ target-word ] keep or ;
351 : fixup-word ( word -- offset )
352 transfer-word dup lookup-object
353 [ ] [ "Not in image: " word-error ] ?if ;
356 image get [ dup word? [ fixup-word ] when ] map! drop ;
363 [ wrapped>> ' wrapper [ emit ] emit-object ] cache-eql-object ;
366 : native> ( object -- object )
367 big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
369 : emit-bytes ( seq -- )
370 bootstrap-cell <groups> native> emit-seq ;
372 : pad-bytes ( seq -- newseq )
373 dup length bootstrap-cell align 0 pad-tail ;
375 : extended-part ( str -- str' )
376 dup [ 128 < ] all? [ drop f ] [
377 [ -7 shift 1 bitxor ] { } map-as
379 [ [ 2 >be ] { } map-as ]
380 [ [ 2 >le ] { } map-as ] if
384 : ascii-part ( str -- str' )
386 [ 128 mod ] [ 128 >= ] bi
390 : emit-string ( string -- ptr )
391 [ length ] [ extended-part ' ] [ ] tri
395 [ f ' emit ascii-part pad-bytes emit-bytes ]
400 #! We pool strings so that each string is only written once
402 [ emit-string ] cache-eql-object ;
404 : assert-empty ( seq -- )
407 : emit-dummy-array ( obj type -- ptr )
409 [ 0 emit-fixnum ] emit-object
415 dup length emit-fixnum
416 bootstrap-cell 4 = [ 0 emit 0 emit ] when
422 ERROR: tuple-removed class ;
424 : require-tuple-layout ( word -- layout )
425 dup tuple-layout [ ] [ tuple-removed ] ?if ;
427 : (emit-tuple) ( tuple -- pointer )
429 [ class transfer-word require-tuple-layout ] bi prefix [ ' ] map
430 tuple [ emit-seq ] emit-object ;
432 : emit-tuple ( tuple -- pointer )
433 dup class name>> "tombstone" =
434 [ [ (emit-tuple) ] cache-eql-object ]
435 [ [ (emit-tuple) ] cache-eq-object ]
438 M: tuple ' emit-tuple ;
441 state>> "((tombstone))" "((empty))" ?
442 "hashtables.private" lookup def>> first
443 [ emit-tuple ] cache-eql-object ;
446 : emit-array ( array -- offset )
447 [ ' ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
449 M: array ' [ emit-array ] cache-eq-object ;
451 ! This is a hack. We need to detect arrays which are tuple
452 ! layout arrays so that they can be internalized, but making
453 ! them a built-in type is not worth it.
454 PREDICATE: tuple-layout-array < array
456 [ first tuple-class? ]
462 M: tuple-layout-array '
464 [ dup integer? [ <fake-bignum> ] when ] map
475 f ' emit ! cached-effect
476 f ' emit ! cache-counter
485 all-words [ emit-word ] each ;
489 dictionary source-files builtins
490 update-map implementors-map
491 } [ [ bootstrap-word ] [ get ] bi ] H{ } map>assoc
493 class<=-cache class-not-cache classes-intersect-cache
494 class-and-cache class-or-cache next-method-quot-cache
495 } [ H{ } clone ] H{ } map>assoc assoc-union
496 bootstrap-global set ;
498 : emit-jit-data ( -- )
500 \ do-primitive jit-primitive-word set
501 \ dip jit-dip-word set
502 \ 2dip jit-2dip-word set
503 \ 3dip jit-3dip-word set
504 \ (execute) jit-execute-word set
505 \ inline-cache-miss \ pic-miss-word set
506 \ inline-cache-miss-tail \ pic-miss-tail-word set
507 \ mega-cache-lookup \ mega-lookup-word set
508 \ mega-cache-miss \ mega-miss-word set
509 \ declare jit-declare-word set
510 [ undefined ] undefined-quot set ;
512 : emit-userenvs ( -- )
513 userenvs get keys [ emit-userenv ] each ;
515 : fixup-header ( -- )
516 heap-size data-heap-size-offset fixup ;
518 : build-image ( -- image )
519 800000 <vector> image set
520 20000 <hashtable> objects set
521 emit-header t, 0, 1, -1,
522 "Building generic words..." print flush
524 "Serializing words..." print flush
526 "Serializing JIT data..." print flush
528 "Serializing global namespace..." print flush
530 "Serializing user environment..." print flush
532 "Performing word fixups..." print flush
534 "Performing header fixups..." print flush
536 "Image length: " write image get length .
537 "Object cache size: " write objects get assoc-size .
538 \ word global delete-at
543 : (write-image) ( image -- )
544 bootstrap-cell big-endian get
545 [ '[ _ >be write ] each ]
546 [ '[ _ >le write ] each ] if ;
548 : write-image ( image -- )
549 "Writing image to " write
550 architecture get boot-image-name resource-path
551 [ write "..." print flush ]
552 [ binary [ (write-image) ] with-file-writer ] bi ;
556 : make-image ( arch -- )
559 "resource:/core/bootstrap/stage1.factor" run-file
565 images [ make-image ] each ;