1 ! Copyright (C) 2004, 2011 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs byte-arrays classes classes.builtin
4 classes.private classes.tuple classes.tuple.private combinators
5 combinators.short-circuit combinators.smart
6 compiler.codegen.relocation compiler.units fry generic
7 generic.single.private grouping hashtables hashtables.private io
8 io.binary io.encodings.binary io.files io.pathnames kernel
9 kernel.private layouts locals make math math.order namespaces
10 namespaces.private parser parser.notes prettyprint quotations
11 sequences sequences.private source-files strings system vectors
15 : arch-name ( os cpu -- arch )
16 2dup [ windows? ] [ ppc? ] bi* or [
19 [ name>> ] bi@ "-" glue ;
21 : my-arch-name ( -- arch )
24 : boot-image-name ( arch -- string )
25 "boot." ".image" surround ;
27 : my-boot-image-name ( -- string )
28 my-arch-name boot-image-name ;
32 "windows-x86.32" "unix-x86.32"
33 "windows-x86.64" "unix-x86.64"
38 ! Object cache; we only consider numbers equal if they have the
40 TUPLE: eql-wrapper { obj read-only } ;
42 C: <eql-wrapper> eql-wrapper
44 M: eql-wrapper hashcode* obj>> hashcode* ;
46 GENERIC: (eql?) ( obj1 obj2 -- ? )
48 : eql? ( obj1 obj2 -- ? )
49 { [ [ class-of ] same? ] [ (eql?) ] } 2&& ;
51 M: fixnum (eql?) eq? ;
53 M: bignum (eql?) { bignum bignum } declare = ;
55 M: float (eql?) fp-bitwise= ;
58 2dup [ length ] same? [ [ eql? ] 2all? ] [ 2drop f ] if ;
63 over eql-wrapper? [ [ obj>> ] bi@ eql? ] [ 2drop f ] if ;
65 TUPLE: eq-wrapper { obj read-only } ;
67 C: <eq-wrapper> eq-wrapper
70 over eq-wrapper? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
72 M: eq-wrapper hashcode*
73 nip obj>> identity-hashcode ;
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 )
84 <eq-wrapper> objects get at ;
86 : put-object ( n obj -- )
87 <eq-wrapper> objects get set-at ;
89 ! Constants need to be synced with
91 CONSTANT: image-magic 0x0f0e0d0c
92 CONSTANT: image-version 4
94 CONSTANT: data-base 1024
96 CONSTANT: header-size 10
98 CONSTANT: data-heap-size-offset 3
100 SYMBOL: sub-primitives
102 SYMBOL: special-objects
104 :: jit-conditional ( test-quot false-quot -- )
105 [ 0 test-quot call ] B{ } make length :> len
106 building get length extra-offset get + len +
107 [ extra-offset set false-quot call ] B{ } make
108 [ length test-quot call ] [ % ] bi ; inline
110 : make-jit ( quot -- parameters literals code )
115 parameter-table get >array
116 literal-table get >array
117 relocation-table get >byte-array
120 : make-jit-no-params ( quot -- code )
123 : jit-define ( quot n -- )
124 [ make-jit-no-params ] dip special-objects get set-at ;
126 : define-sub-primitive ( quot word -- )
127 [ make-jit 3array ] dip sub-primitives get set-at ;
129 : define-sub-primitives ( assoc -- )
130 [ swap define-sub-primitive ] assoc-each ;
132 : define-combinator-primitive ( quot non-tail-quot tail-quot word -- )
136 [ make-jit-no-params ]
137 [ make-jit-no-params ]
141 sub-primitives get set-at ;
143 SYMBOL: bootstrapping-image
145 ! Image output format
150 : emit ( cell -- ) bootstrapping-image get push ;
152 : emit-64 ( cell -- )
156 d>w/w big-endian get [ swap ] unless emit emit
159 : emit-seq ( seq -- ) bootstrapping-image get push-all ;
161 : fixup ( value offset -- ) bootstrapping-image get set-nth ;
163 : heap-size ( -- size )
164 bootstrapping-image get length header-size - special-object-count -
167 : here ( -- size ) heap-size data-base + ;
169 : here-as ( tag -- pointer ) here bitor ;
171 : (align-here) ( alignment -- )
173 [ bootstrap-cell /i [ 0 emit ] times ] unless-zero ;
176 data-alignment get (align-here) ;
178 : emit-fixnum ( n -- ) tag-fixnum emit ;
180 : emit-header ( n -- ) tag-header emit ;
182 : emit-object ( class quot -- addr )
183 [ type-number ] dip over here-as
184 [ swap emit-header call align-here ] dip ; inline
186 ! Read any object for emitting.
187 GENERIC: prepare-object ( obj -- ptr )
191 : emit-image-header ( -- )
194 data-base emit ! relocation base at end of header
195 0 emit ! size of data heap set later
196 0 emit ! reloc base of code heap is 0
197 0 emit ! size of code heap is 0
202 special-object-count [ f prepare-object emit ] times ;
206 : bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
208 : bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
210 : bignum>sequence ( n -- seq )
211 ! n is positive or zero.
213 [ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
216 : emit-bignum ( n -- )
217 dup dup 0 < [ neg ] when bignum>sequence
218 [ nip length 1 + emit-fixnum ]
219 [ drop 0 < 1 0 ? emit ]
223 M: bignum prepare-object
225 bignum [ emit-bignum ] emit-object
230 M: fixnum prepare-object
231 ! When generating a 32-bit image on a 64-bit system,
232 ! some fixnums should be bignums.
234 bootstrap-most-negative-fixnum
235 bootstrap-most-positive-fixnum between?
236 [ tag-fixnum ] [ >bignum prepare-object ] if ;
238 TUPLE: fake-bignum n ;
240 C: <fake-bignum> fake-bignum
242 M: fake-bignum prepare-object n>> tag-fixnum ;
246 M: float prepare-object
249 8 (align-here) double>bits emit-64
255 ! Padded with fixnums for 8-byte alignment
256 M: f prepare-object drop \ f type-number ;
260 : word-sub-primitive ( word -- obj )
261 [ target-word ] with-global sub-primitives get at ;
263 : emit-word ( word -- )
265 [ subwords [ emit-word ] each ]
269 [ hashcode <fake-bignum> ]
276 [ word-sub-primitive ]
277 [ drop 0 ] ! entry point
279 ] output>array [ prepare-object ] map!
281 \ word [ emit-seq ] emit-object
284 ERROR: not-in-image vocabulary word ;
286 : transfer-word ( word -- word )
287 [ target-word ] keep or ;
289 : fixup-word ( word -- offset )
290 transfer-word dup lookup-object
291 [ ] [ [ vocabulary>> ] [ name>> ] bi not-in-image ] ?if ;
294 bootstrapping-image get [ dup word? [ fixup-word ] when ] map! drop ;
296 M: word prepare-object ;
300 M: wrapper prepare-object
301 [ wrapped>> prepare-object wrapper [ emit ] emit-object ] cache-eql-object ;
304 : native> ( object -- object )
305 big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
307 : emit-bytes ( seq -- )
308 bootstrap-cell <groups> native> emit-seq ;
310 : pad-bytes ( seq -- newseq )
311 dup length bootstrap-cell align 0 pad-tail ;
313 : extended-part ( str -- str' )
314 dup [ 128 < ] all? [ drop f ] [
315 [ -7 shift 1 bitxor ] { } map-as
317 [ [ 2 >be ] { } map-as ]
318 [ [ 2 >le ] { } map-as ] if
322 : ascii-part ( str -- str' )
324 [ 128 mod ] [ 128 >= ] bi
328 : emit-string ( string -- ptr )
329 [ length ] [ extended-part prepare-object ] [ ] tri
333 [ f prepare-object emit ascii-part pad-bytes emit-bytes ]
337 M: string prepare-object
338 ! We pool strings so that each string is only written once
340 [ emit-string ] cache-eql-object ;
342 : assert-empty ( seq -- )
345 : emit-dummy-array ( obj type -- ptr )
347 [ 0 emit-fixnum ] emit-object
350 M: byte-array prepare-object
353 dup length emit-fixnum
354 bootstrap-cell 4 = [ 0 emit 0 emit ] when
360 ERROR: tuple-removed class ;
362 : require-tuple-layout ( word -- layout )
363 dup tuple-layout [ ] [ tuple-removed ] ?if ;
365 : (emit-tuple) ( tuple -- pointer )
367 [ class-of transfer-word require-tuple-layout ] bi prefix [ prepare-object ] map
368 tuple [ emit-seq ] emit-object ;
370 : emit-tuple ( tuple -- pointer )
371 dup class-of name>> "tombstone" =
372 [ [ (emit-tuple) ] cache-eql-object ]
373 [ [ (emit-tuple) ] cache-eq-object ]
376 M: tuple prepare-object emit-tuple ;
378 M: tombstone prepare-object
379 state>> "+tombstone+" "+empty+" ?
380 "hashtables.private" lookup-word def>> first
381 [ emit-tuple ] cache-eql-object ;
384 : emit-array ( array -- offset )
385 [ prepare-object ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
387 M: array prepare-object [ emit-array ] cache-eq-object ;
389 ! This is a hack. We need to detect arrays which are tuple
390 ! layout arrays so that they can be internalized, but making
391 ! them a built-in type is not worth it.
392 PREDICATE: tuple-layout-array < array
395 [ first-unsafe tuple-class? ]
396 [ second-unsafe fixnum? ]
397 [ third-unsafe fixnum? ]
401 M: tuple-layout-array prepare-object
403 [ dup integer? [ <fake-bignum> ] when ] map
409 M: quotation prepare-object
411 array>> prepare-object
414 f prepare-object emit ! cached-effect
415 f prepare-object emit ! cache-counter
423 all-words [ emit-word ] each ;
425 : emit-singletons ( -- )
426 t OBJ-CANONICAL-TRUE special-objects get set-at
427 0 >bignum OBJ-BIGNUM-ZERO special-objects get set-at
428 1 >bignum OBJ-BIGNUM-POS-ONE special-objects get set-at
429 -1 >bignum OBJ-BIGNUM-NEG-ONE special-objects get set-at ;
431 : create-global-hashtable ( -- global-hashtable )
433 dictionary source-files builtins
434 update-map implementors-map
435 } [ [ bootstrap-word ] [ get global-box boa ] bi ] H{ } map>assoc
437 class<=-cache class-not-cache classes-intersect-cache
438 class-and-cache class-or-cache next-method-quot-cache
439 } [ H{ } clone global-box boa ] H{ } map>assoc assoc-union
440 global-hashtable boa ;
443 create-global-hashtable
444 OBJ-GLOBAL special-objects get set-at ;
446 : emit-jit-data ( -- )
449 { JIT-PRIMITIVE-WORD do-primitive }
451 { JIT-2DIP-WORD 2dip }
452 { JIT-3DIP-WORD 3dip }
453 { PIC-MISS-WORD inline-cache-miss }
454 { PIC-MISS-TAIL-WORD inline-cache-miss-tail }
455 { MEGA-LOOKUP-WORD mega-cache-lookup }
456 { MEGA-MISS-WORD mega-cache-miss }
457 { JIT-DECLARE-WORD declare }
458 { C-TO-FACTOR-WORD c-to-factor }
459 { LAZY-JIT-COMPILE-WORD lazy-jit-compile }
460 { UNWIND-NATIVE-FRAMES-WORD unwind-native-frames }
461 { GET-FPU-STATE-WORD fpu-state }
462 { SET-FPU-STATE-WORD set-fpu-state }
463 { SIGNAL-HANDLER-WORD signal-handler }
464 { LEAF-SIGNAL-HANDLER-WORD leaf-signal-handler }
466 \ OBJ-UNDEFINED undefined-def 2array suffix [
467 swap execute( -- x ) special-objects get set-at
470 : emit-special-object ( obj idx -- )
471 [ prepare-object ] [ header-size + ] bi* fixup ;
473 : emit-special-objects ( -- )
474 special-objects get [ swap emit-special-object ] assoc-each ;
476 : fixup-header ( -- )
477 heap-size data-heap-size-offset fixup ;
479 : build-generics ( -- )
483 [ make-generic ] each
484 ] with-compilation-unit ;
486 : build-image ( -- image )
487 600,000 <vector> bootstrapping-image set
488 60,000 <hashtable> objects set
490 "Building generic words..." print flush
492 "Serializing words..." print flush
494 "Serializing JIT data..." print flush
496 "Serializing global namespace..." print flush
498 "Serializing singletons..." print flush
500 "Serializing special object table..." print flush
502 "Performing word fixups..." print flush
504 "Performing header fixups..." print flush
506 "Image length: " write bootstrapping-image get length .
507 "Object cache size: " write objects get assoc-size .
508 \ last-word global delete-at
509 bootstrapping-image get ;
513 : (write-image) ( image -- )
514 bootstrap-cell output-stream get
516 [ '[ _ >be _ stream-write ] each ]
517 [ '[ _ >le _ stream-write ] each ] if ;
519 : write-image ( image -- )
520 "Writing image to " write
521 architecture get boot-image-name resource-path
522 [ write "..." print flush ]
523 [ binary [ (write-image) ] with-file-writer ] bi ;
527 : make-image ( arch -- )
528 architecture associate H{
532 H{ } clone special-objects set
533 "resource:/core/bootstrap/stage1.factor" run-file
539 image-names [ make-image ] each ;
541 : make-my-image ( -- )
542 my-arch-name make-image ;