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 ;
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
102 CONSTANT: -1-offset 9
104 SYMBOL: sub-primitives
106 SYMBOL: special-objects
108 :: jit-conditional ( test-quot false-quot -- )
109 [ 0 test-quot call ] B{ } make length :> len
110 building get length extra-offset get + len +
111 [ extra-offset set false-quot call ] B{ } make
112 [ length test-quot call ] [ % ] bi ; inline
114 : make-jit ( quot -- parameters literals code )
115 ! code is a { relocation insns } pair
120 parameter-table get >array
121 literal-table get >array
122 relocation-table get >byte-array
125 : make-jit-no-params ( quot -- code )
128 : jit-define ( quot n -- )
129 [ make-jit-no-params ] dip special-objects get set-at ;
131 : define-sub-primitive ( quot word -- )
132 [ make-jit 3array ] dip sub-primitives get set-at ;
134 : define-combinator-primitive ( quot non-tail-quot tail-quot word -- )
138 [ make-jit-no-params ]
139 [ make-jit-no-params ]
143 sub-primitives get set-at ;
145 SYMBOL: bootstrapping-image
147 ! Image output format
152 H{ } clone special-objects set-global
154 : emit ( cell -- ) bootstrapping-image get push ;
156 : emit-64 ( cell -- )
160 d>w/w big-endian get [ swap ] unless emit emit
163 : emit-seq ( seq -- ) bootstrapping-image get push-all ;
165 : fixup ( value offset -- ) bootstrapping-image get set-nth ;
167 : heap-size ( -- size )
168 bootstrapping-image get length header-size - special-object-count -
171 : here ( -- size ) heap-size data-base + ;
173 : here-as ( tag -- pointer ) here bitor ;
175 : (align-here) ( alignment -- )
177 [ bootstrap-cell /i [ 0 emit ] times ] unless-zero ;
180 data-alignment get (align-here) ;
182 : emit-fixnum ( n -- ) tag-fixnum emit ;
184 : emit-header ( n -- ) tag-header emit ;
186 : emit-object ( class quot -- addr )
187 [ type-number ] dip over here-as
188 [ swap emit-header call align-here ] dip ; inline
190 ! Read any object for emitting.
191 GENERIC: prepare-object ( obj -- ptr )
195 : emit-image-header ( -- )
198 data-base emit ! relocation base at end of header
199 0 emit ! size of data heap set later
200 0 emit ! reloc base of code heap is 0
201 0 emit ! size of code heap is 0
202 0 emit ! pointer to t object
203 0 emit ! pointer to bignum 0
204 0 emit ! pointer to bignum 1
205 0 emit ! pointer to bignum -1
206 special-object-count [ f prepare-object emit ] times ;
210 : bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
212 : bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
214 : bignum>sequence ( n -- seq )
215 ! n is positive or zero.
217 [ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
220 : emit-bignum ( n -- )
221 dup dup 0 < [ neg ] when bignum>sequence
222 [ nip length 1 + emit-fixnum ]
223 [ drop 0 < 1 0 ? emit ]
227 M: bignum prepare-object
229 bignum [ emit-bignum ] emit-object
234 M: fixnum prepare-object
235 ! When generating a 32-bit image on a 64-bit system,
236 ! some fixnums should be bignums.
238 bootstrap-most-negative-fixnum
239 bootstrap-most-positive-fixnum between?
240 [ tag-fixnum ] [ >bignum prepare-object ] if ;
242 TUPLE: fake-bignum n ;
244 C: <fake-bignum> fake-bignum
246 M: fake-bignum prepare-object n>> tag-fixnum ;
250 M: float prepare-object
253 8 (align-here) double>bits emit-64
259 ! Padded with fixnums for 8-byte alignment
261 : t, ( -- ) t t-offset fixup ;
263 M: f prepare-object drop \ f type-number ;
265 : 0, ( -- ) 0 >bignum prepare-object 0-offset fixup ;
266 : 1, ( -- ) 1 >bignum prepare-object 1-offset fixup ;
267 : -1, ( -- ) -1 >bignum prepare-object -1-offset fixup ;
271 : word-sub-primitive ( word -- obj )
272 [ target-word ] with-global sub-primitives get at ;
274 : emit-word ( word -- )
276 [ subwords [ emit-word ] each ]
280 [ hashcode <fake-bignum> ]
287 [ word-sub-primitive ]
288 [ drop 0 ] ! entry point
290 ] output>array [ prepare-object ] map!
292 \ word [ emit-seq ] emit-object
295 ERROR: not-in-image vocabulary word ;
297 : transfer-word ( word -- word )
298 [ target-word ] keep or ;
300 : fixup-word ( word -- offset )
301 transfer-word dup lookup-object
302 [ ] [ [ vocabulary>> ] [ name>> ] bi not-in-image ] ?if ;
305 bootstrapping-image get [ dup word? [ fixup-word ] when ] map! drop ;
307 M: word prepare-object ;
311 M: wrapper prepare-object
312 [ wrapped>> prepare-object wrapper [ emit ] emit-object ] cache-eql-object ;
315 : native> ( object -- object )
316 big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
318 : emit-bytes ( seq -- )
319 bootstrap-cell <groups> native> emit-seq ;
321 : pad-bytes ( seq -- newseq )
322 dup length bootstrap-cell align 0 pad-tail ;
324 : extended-part ( str -- str' )
325 dup [ 128 < ] all? [ drop f ] [
326 [ -7 shift 1 bitxor ] { } map-as
328 [ [ 2 >be ] { } map-as ]
329 [ [ 2 >le ] { } map-as ] if
333 : ascii-part ( str -- str' )
335 [ 128 mod ] [ 128 >= ] bi
339 : emit-string ( string -- ptr )
340 [ length ] [ extended-part prepare-object ] [ ] tri
344 [ f prepare-object emit ascii-part pad-bytes emit-bytes ]
348 M: string prepare-object
349 ! We pool strings so that each string is only written once
351 [ emit-string ] cache-eql-object ;
353 : assert-empty ( seq -- )
356 : emit-dummy-array ( obj type -- ptr )
358 [ 0 emit-fixnum ] emit-object
361 M: byte-array prepare-object
364 dup length emit-fixnum
365 bootstrap-cell 4 = [ 0 emit 0 emit ] when
371 ERROR: tuple-removed class ;
373 : require-tuple-layout ( word -- layout )
374 dup tuple-layout [ ] [ tuple-removed ] ?if ;
376 : (emit-tuple) ( tuple -- pointer )
378 [ class-of transfer-word require-tuple-layout ] bi prefix [ prepare-object ] map
379 tuple [ emit-seq ] emit-object ;
381 : emit-tuple ( tuple -- pointer )
382 dup class-of name>> "tombstone" =
383 [ [ (emit-tuple) ] cache-eql-object ]
384 [ [ (emit-tuple) ] cache-eq-object ]
387 M: tuple prepare-object emit-tuple ;
389 M: tombstone prepare-object
390 state>> "((tombstone))" "((empty))" ?
391 "hashtables.private" lookup-word def>> first
392 [ emit-tuple ] cache-eql-object ;
395 : emit-array ( array -- offset )
396 [ prepare-object ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
398 M: array prepare-object [ emit-array ] cache-eq-object ;
400 ! This is a hack. We need to detect arrays which are tuple
401 ! layout arrays so that they can be internalized, but making
402 ! them a built-in type is not worth it.
403 PREDICATE: tuple-layout-array < array
406 [ first-unsafe tuple-class? ]
407 [ second-unsafe fixnum? ]
408 [ third-unsafe fixnum? ]
412 M: tuple-layout-array prepare-object
414 [ dup integer? [ <fake-bignum> ] when ] map
420 M: quotation prepare-object
422 array>> prepare-object
425 f prepare-object emit ! cached-effect
426 f prepare-object emit ! cache-counter
434 all-words [ emit-word ] each ;
438 dictionary source-files builtins
439 update-map implementors-map
440 } [ [ bootstrap-word ] [ get global-box boa ] bi ] H{ } map>assoc
442 class<=-cache class-not-cache classes-intersect-cache
443 class-and-cache class-or-cache next-method-quot-cache
444 } [ H{ } clone global-box boa ] H{ } map>assoc assoc-union
446 OBJ-GLOBAL special-objects get set-at ;
448 : emit-jit-data ( -- )
451 { JIT-PRIMITIVE-WORD do-primitive }
453 { JIT-2DIP-WORD 2dip }
454 { JIT-3DIP-WORD 3dip }
455 { PIC-MISS-WORD inline-cache-miss }
456 { PIC-MISS-TAIL-WORD inline-cache-miss-tail }
457 { MEGA-LOOKUP-WORD mega-cache-lookup }
458 { MEGA-MISS-WORD mega-cache-miss }
459 { JIT-DECLARE-WORD declare }
460 { C-TO-FACTOR-WORD c-to-factor }
461 { LAZY-JIT-COMPILE-WORD lazy-jit-compile }
462 { UNWIND-NATIVE-FRAMES-WORD unwind-native-frames }
463 { GET-FPU-STATE-WORD fpu-state }
464 { SET-FPU-STATE-WORD set-fpu-state }
465 { SIGNAL-HANDLER-WORD signal-handler }
466 { LEAF-SIGNAL-HANDLER-WORD leaf-signal-handler }
468 \ OBJ-UNDEFINED undefined-def 2array suffix [
469 swap execute( -- x ) special-objects get set-at
472 : emit-special-object ( obj idx -- )
473 [ prepare-object ] [ header-size + ] bi* fixup ;
475 : emit-special-objects ( -- )
476 special-objects get [ swap emit-special-object ] assoc-each ;
478 : fixup-header ( -- )
479 heap-size data-heap-size-offset fixup ;
481 : build-generics ( -- )
485 [ make-generic ] each
486 ] with-compilation-unit ;
488 : build-image ( -- image )
489 600,000 <vector> bootstrapping-image set
490 60,000 <hashtable> objects set
491 emit-image-header t, 0, 1, -1,
492 "Building generic words..." print flush
494 "Serializing words..." print flush
496 "Serializing JIT data..." print flush
498 "Serializing global namespace..." 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 "resource:/core/bootstrap/stage1.factor" run-file
538 image-names [ make-image ] each ;
540 : make-my-image ( -- )
541 my-arch-name make-image ;