factor/basis/bootstrap/image/image.factor

544 lines
14 KiB
Factor
Raw Normal View History

! Copyright (C) 2004, 2011 Slava Pestov.
2007-09-20 18:09:08 -04:00
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs byte-arrays classes classes.builtin
classes.private classes.tuple classes.tuple.private combinators
combinators.short-circuit combinators.smart
compiler.codegen.relocation compiler.units fry generic
2015-07-16 14:09:17 -04:00
generic.single.private grouping hashtables hashtables.private io
io.binary io.encodings.binary io.files io.pathnames kernel
kernel.private layouts locals make math math.order namespaces
namespaces.private parser parser.notes prettyprint quotations
sequences sequences.private source-files strings system vectors
vocabs words ;
2007-09-20 18:09:08 -04:00
IN: bootstrap.image
: arch-name ( os cpu -- arch )
2dup [ windows? ] [ ppc? ] bi* or [
2011-05-20 18:11:50 -04:00
[ drop unix ] dip
] unless
2015-07-16 14:09:17 -04:00
[ name>> ] bi@ "-" glue ;
2008-11-07 22:09:42 -05:00
: my-arch-name ( -- arch )
os cpu arch-name ;
: boot-image-name ( arch -- string )
2008-12-06 19:58:45 -05:00
"boot." ".image" surround ;
: my-boot-image-name ( -- string )
my-arch-name boot-image-name ;
CONSTANT: image-names
{
"windows-x86.32" "unix-x86.32"
"windows-x86.64" "unix-x86.64"
2015-07-16 14:09:17 -04:00
}
2007-09-20 18:09:08 -04:00
<PRIVATE
! Object cache; we only consider numbers equal if they have the
! same type
2009-10-30 21:53:18 -04:00
TUPLE: eql-wrapper { obj read-only } ;
C: <eql-wrapper> eql-wrapper
M: eql-wrapper hashcode* obj>> hashcode* ;
2008-04-29 02:49:06 -04:00
GENERIC: (eql?) ( obj1 obj2 -- ? )
: eql? ( obj1 obj2 -- ? )
2012-07-21 13:22:44 -04:00
{ [ [ class-of ] same? ] [ (eql?) ] } 2&& ;
2008-04-29 02:49:06 -04:00
2009-10-30 21:53:18 -04:00
M: fixnum (eql?) eq? ;
2008-04-29 02:49:06 -04:00
M: bignum (eql?) { bignum bignum } declare = ;
2009-10-30 21:53:18 -04:00
M: float (eql?) fp-bitwise= ;
M: sequence (eql?)
2dup [ length ] same? [ [ eql? ] 2all? ] [ 2drop f ] if ;
2008-04-29 02:49:06 -04:00
M: object (eql?) = ;
M: eql-wrapper equal?
over eql-wrapper? [ [ obj>> ] bi@ eql? ] [ 2drop f ] if ;
2009-10-30 21:53:18 -04:00
TUPLE: eq-wrapper { obj read-only } ;
C: <eq-wrapper> eq-wrapper
M: eq-wrapper equal?
over eq-wrapper? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
2009-11-10 22:06:36 -05:00
M: eq-wrapper hashcode*
nip obj>> identity-hashcode ;
SYMBOL: objects
: cache-eql-object ( obj quot -- value )
[ <eql-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
: cache-eq-object ( obj quot -- value )
[ <eq-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
: lookup-object ( obj -- n/f )
<eq-wrapper> objects get at ;
: put-object ( n obj -- )
<eq-wrapper> objects get set-at ;
! Constants need to be synced with
! vm/image.hpp
2011-11-23 21:49:33 -05:00
CONSTANT: image-magic 0x0f0e0d0c
2009-02-22 20:13:08 -05:00
CONSTANT: image-version 4
2007-09-20 18:09:08 -04:00
2009-02-22 20:13:08 -05:00
CONSTANT: data-base 1024
2007-09-20 18:09:08 -04:00
2009-02-22 20:13:08 -05:00
CONSTANT: header-size 10
2007-09-20 18:09:08 -04:00
2009-02-22 20:13:08 -05:00
CONSTANT: data-heap-size-offset 3
2007-09-20 18:09:08 -04:00
SYMBOL: sub-primitives
SYMBOL: special-objects
:: jit-conditional ( test-quot false-quot -- )
[ 0 test-quot call ] B{ } make length :> len
building get length extra-offset get + len +
[ extra-offset set false-quot call ] B{ } make
[ length test-quot call ] [ % ] bi ; inline
: make-jit ( quot -- parameters literals code )
[
0 extra-offset set
init-relocation
call( -- )
parameter-table get >array
literal-table get >array
relocation-table get >byte-array
] B{ } make 2array ;
: make-jit-no-params ( quot -- code )
make-jit 2nip ;
: jit-define ( quot n -- )
[ make-jit-no-params ] dip special-objects get set-at ;
: define-sub-primitive ( quot word -- )
[ make-jit 3array ] dip sub-primitives get set-at ;
: define-sub-primitives ( assoc -- )
[ swap define-sub-primitive ] assoc-each ;
: define-combinator-primitive ( quot non-tail-quot tail-quot word -- )
[
[
[ make-jit ]
[ make-jit-no-params ]
[ make-jit-no-params ]
tri*
] output>array
] dip
sub-primitives get set-at ;
SYMBOL: bootstrapping-image
2007-09-20 18:09:08 -04:00
! Image output format
SYMBOL: big-endian
SYMBOL: architecture
H{ } clone special-objects set-global
2007-09-20 18:09:08 -04:00
: emit ( cell -- ) bootstrapping-image get push ;
2007-09-20 18:09:08 -04:00
: emit-64 ( cell -- )
bootstrap-cell 8 = [
emit
] [
d>w/w big-endian get [ swap ] unless emit emit
] if ;
: emit-seq ( seq -- ) bootstrapping-image get push-all ;
2007-09-20 18:09:08 -04:00
: fixup ( value offset -- ) bootstrapping-image get set-nth ;
2007-09-20 18:09:08 -04:00
: heap-size ( -- size )
bootstrapping-image get length header-size - special-object-count -
2007-09-20 18:09:08 -04:00
bootstrap-cells ;
: here ( -- size ) heap-size data-base + ;
2008-03-31 02:19:21 -04:00
: here-as ( tag -- pointer ) here bitor ;
2007-09-20 18:09:08 -04:00
2009-10-20 13:45:00 -04:00
: (align-here) ( alignment -- )
[ here neg ] dip rem
[ bootstrap-cell /i [ 0 emit ] times ] unless-zero ;
2007-09-20 18:09:08 -04:00
: align-here ( -- )
2009-10-20 13:45:00 -04:00
data-alignment get (align-here) ;
2007-09-20 18:09:08 -04:00
2008-01-02 19:36:36 -05:00
: emit-fixnum ( n -- ) tag-fixnum emit ;
2007-09-20 18:09:08 -04:00
2009-11-10 22:06:36 -05:00
: emit-header ( n -- ) tag-header emit ;
: emit-object ( class quot -- addr )
[ type-number ] dip over here-as
[ swap emit-header call align-here ] dip ; inline
2007-09-20 18:09:08 -04:00
! Read any object for emitting.
GENERIC: prepare-object ( obj -- ptr )
2007-09-20 18:09:08 -04:00
! Image header
2009-11-10 22:06:36 -05:00
: emit-image-header ( -- )
2007-09-20 18:09:08 -04:00
image-magic emit
image-version emit
data-base emit ! relocation base at end of header
0 emit ! size of data heap set later
0 emit ! reloc base of code heap is 0
0 emit ! size of code heap is 0
0 emit ! reserved
0 emit ! reserved
0 emit ! reserved
0 emit ! reserved
special-object-count [ f prepare-object emit ] times ;
2007-09-20 18:09:08 -04:00
! Bignums
2008-06-08 16:32:55 -04:00
: bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
2007-09-20 18:09:08 -04:00
: bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
2007-09-20 18:09:08 -04:00
: bignum>sequence ( n -- seq )
2015-09-08 19:15:10 -04:00
! n is positive or zero.
2007-10-16 04:15:16 -04:00
[ dup 0 > ]
2008-03-31 02:19:21 -04:00
[ [ bignum-bits neg shift ] [ bignum-radix bitand ] bi ]
produce nip ;
2007-09-20 18:09:08 -04:00
: emit-bignum ( n -- )
dup dup 0 < [ neg ] when bignum>sequence
[ nip length 1 + emit-fixnum ]
2008-03-31 02:19:21 -04:00
[ drop 0 < 1 0 ? emit ]
[ nip emit-seq ]
2tri ;
2007-09-20 18:09:08 -04:00
M: bignum prepare-object
[
bignum [ emit-bignum ] emit-object
] cache-eql-object ;
2007-09-20 18:09:08 -04:00
! Fixnums
M: fixnum prepare-object
2015-09-08 19:15:10 -04:00
! When generating a 32-bit image on a 64-bit system,
! some fixnums should be bignums.
2008-03-12 02:54:29 -04:00
dup
bootstrap-most-negative-fixnum
bootstrap-most-positive-fixnum between?
[ tag-fixnum ] [ >bignum prepare-object ] if ;
2007-09-20 18:09:08 -04:00
2008-07-05 22:00:05 -04:00
TUPLE: fake-bignum n ;
C: <fake-bignum> fake-bignum
M: fake-bignum prepare-object n>> tag-fixnum ;
2008-07-05 22:00:05 -04:00
2007-09-20 18:09:08 -04:00
! Floats
M: float prepare-object
[
float [
2009-10-20 13:45:00 -04:00
8 (align-here) double>bits emit-64
] emit-object
] cache-eql-object ;
2007-09-20 18:09:08 -04:00
! Special objects
! Padded with fixnums for 8-byte alignment
M: f prepare-object drop \ f type-number ;
2007-09-20 18:09:08 -04:00
! Words
: word-sub-primitive ( word -- obj )
[ target-word ] with-global sub-primitives get at ;
2007-09-20 18:09:08 -04:00
: emit-word ( word -- )
[
2008-03-31 02:19:21 -04:00
[ subwords [ emit-word ] each ]
[
[
{
[ hashcode <fake-bignum> ]
[ name>> ]
[ vocabulary>> ]
[ def>> ]
[ props>> ]
[ pic-def>> ]
[ pic-tail-def>> ]
[ word-sub-primitive ]
[ drop 0 ] ! entry point
2008-03-31 02:19:21 -04:00
} cleave
] output>array [ prepare-object ] map!
2008-03-31 02:19:21 -04:00
] bi
\ word [ emit-seq ] emit-object
] keep put-object ;
2007-09-20 18:09:08 -04:00
2013-03-29 12:35:13 -04:00
ERROR: not-in-image vocabulary word ;
2007-09-20 18:09:08 -04:00
: transfer-word ( word -- word )
2008-03-31 02:19:21 -04:00
[ target-word ] keep or ;
2007-09-20 18:09:08 -04:00
: fixup-word ( word -- offset )
transfer-word dup lookup-object
[ ] [ [ vocabulary>> ] [ name>> ] bi not-in-image ] ?if ;
2007-09-20 18:09:08 -04:00
: fixup-words ( -- )
bootstrapping-image get [ dup word? [ fixup-word ] when ] map! drop ;
2007-09-20 18:09:08 -04:00
M: word prepare-object ;
2007-09-20 18:09:08 -04:00
! Wrappers
M: wrapper prepare-object
[ wrapped>> prepare-object wrapper [ emit ] emit-object ] cache-eql-object ;
2007-09-20 18:09:08 -04:00
! Strings
: native> ( object -- object )
big-endian get [ [ be> ] map ] [ [ le> ] map ] if ;
2008-04-30 17:11:55 -04:00
: emit-bytes ( seq -- )
bootstrap-cell <groups> native> emit-seq ;
2007-09-20 18:09:08 -04:00
2008-04-30 17:11:55 -04:00
: pad-bytes ( seq -- newseq )
dup length bootstrap-cell align 0 pad-tail ;
2007-09-20 18:09:08 -04:00
: extended-part ( str -- str' )
dup [ 128 < ] all? [ drop f ] [
[ -7 shift 1 bitxor ] { } map-as
big-endian get
[ [ 2 >be ] { } map-as ]
[ [ 2 >le ] { } map-as ] if
B{ } join
] if ;
: ascii-part ( str -- str' )
[
[ 128 mod ] [ 128 >= ] bi
[ 128 bitor ] when
] B{ } map-as ;
2007-09-20 18:09:08 -04:00
: emit-string ( string -- ptr )
[ length ] [ extended-part prepare-object ] [ ] tri
string [
[ emit-fixnum ]
[ emit ]
[ f prepare-object emit ascii-part pad-bytes emit-bytes ]
tri*
2007-09-20 18:09:08 -04:00
] emit-object ;
M: string prepare-object
2015-09-08 19:15:10 -04:00
! We pool strings so that each string is only written once
! to the image
[ emit-string ] cache-eql-object ;
2007-09-20 18:09:08 -04:00
: assert-empty ( seq -- )
length 0 assert= ;
: emit-dummy-array ( obj type -- ptr )
2008-03-31 02:19:21 -04:00
[ assert-empty ] [
[ 0 emit-fixnum ] emit-object
] bi* ;
2007-09-20 18:09:08 -04:00
M: byte-array prepare-object
[
byte-array [
dup length emit-fixnum
2009-10-20 13:45:00 -04:00
bootstrap-cell 4 = [ 0 emit 0 emit ] when
pad-bytes emit-bytes
] emit-object
] cache-eq-object ;
2007-09-20 18:09:08 -04:00
2008-03-26 04:57:48 -04:00
! Tuples
ERROR: tuple-removed class ;
: require-tuple-layout ( word -- layout )
dup tuple-layout [ ] [ tuple-removed ] ?if ;
2008-03-31 02:19:21 -04:00
: (emit-tuple) ( tuple -- pointer )
2008-09-03 00:21:08 -04:00
[ tuple-slots ]
[ class-of transfer-word require-tuple-layout ] bi prefix [ prepare-object ] map
tuple [ emit-seq ] emit-object ;
2008-03-31 02:19:21 -04:00
2008-03-26 04:57:48 -04:00
: emit-tuple ( tuple -- pointer )
2011-10-24 07:47:42 -04:00
dup class-of name>> "tombstone" =
[ [ (emit-tuple) ] cache-eql-object ]
[ [ (emit-tuple) ] cache-eq-object ]
if ;
2007-09-20 18:09:08 -04:00
M: tuple prepare-object emit-tuple ;
2007-09-20 18:09:08 -04:00
M: tombstone prepare-object
state>> "+tombstone+" "+empty+" ?
2011-11-06 18:57:24 -05:00
"hashtables.private" lookup-word def>> first
[ emit-tuple ] cache-eql-object ;
2007-09-20 18:09:08 -04:00
2008-03-26 04:57:48 -04:00
! Arrays
2008-11-06 02:58:07 -05:00
: emit-array ( array -- offset )
[ prepare-object ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
2007-09-20 18:09:08 -04:00
M: array prepare-object [ emit-array ] cache-eq-object ;
2008-11-06 02:58:07 -05:00
! This is a hack. We need to detect arrays which are tuple
! layout arrays so that they can be internalized, but making
! them a built-in type is not worth it.
PREDICATE: tuple-layout-array < array
dup length 5 >= [
{
[ first-unsafe tuple-class? ]
[ second-unsafe fixnum? ]
[ third-unsafe fixnum? ]
} 1&&
] [ drop f ] if ;
M: tuple-layout-array prepare-object
2008-11-06 02:58:07 -05:00
[
[ dup integer? [ <fake-bignum> ] when ] map
emit-array
] cache-eql-object ;
2007-09-20 18:09:08 -04:00
! Quotations
M: quotation prepare-object
[
array>> prepare-object
quotation [
2007-09-20 18:09:08 -04:00
emit ! array
f prepare-object emit ! cached-effect
f prepare-object emit ! cache-counter
0 emit ! entry point
2007-09-20 18:09:08 -04:00
] emit-object
] cache-eql-object ;
2007-09-20 18:09:08 -04:00
! End of the image
: emit-words ( -- )
all-words [ emit-word ] each ;
: emit-singletons ( -- )
t OBJ-CANONICAL-TRUE special-objects get set-at
0 >bignum OBJ-BIGNUM-ZERO special-objects get set-at
1 >bignum OBJ-BIGNUM-POS-ONE special-objects get set-at
-1 >bignum OBJ-BIGNUM-NEG-ONE special-objects get set-at ;
2016-02-28 12:49:41 -05:00
: create-global-hashtable ( -- global-hashtable )
2008-09-18 00:28:54 -04:00
{
dictionary source-files builtins
update-map implementors-map
} [ [ bootstrap-word ] [ get global-box boa ] bi ] H{ } map>assoc
2008-09-18 00:28:54 -04:00
{
class<=-cache class-not-cache classes-intersect-cache
2008-10-01 09:20:49 -04:00
class-and-cache class-or-cache next-method-quot-cache
} [ H{ } clone global-box boa ] H{ } map>assoc assoc-union
2016-02-28 12:49:41 -05:00
global-hashtable boa ;
: emit-global ( -- )
create-global-hashtable
OBJ-GLOBAL special-objects get set-at ;
2007-09-20 18:09:08 -04:00
: emit-jit-data ( -- )
{
{ JIT-IF-WORD if }
{ JIT-PRIMITIVE-WORD do-primitive }
{ JIT-DIP-WORD dip }
{ JIT-2DIP-WORD 2dip }
{ JIT-3DIP-WORD 3dip }
{ PIC-MISS-WORD inline-cache-miss }
{ PIC-MISS-TAIL-WORD inline-cache-miss-tail }
{ MEGA-LOOKUP-WORD mega-cache-lookup }
{ MEGA-MISS-WORD mega-cache-miss }
{ JIT-DECLARE-WORD declare }
{ C-TO-FACTOR-WORD c-to-factor }
{ LAZY-JIT-COMPILE-WORD lazy-jit-compile }
{ UNWIND-NATIVE-FRAMES-WORD unwind-native-frames }
{ GET-FPU-STATE-WORD fpu-state }
{ SET-FPU-STATE-WORD set-fpu-state }
{ SIGNAL-HANDLER-WORD signal-handler }
{ LEAF-SIGNAL-HANDLER-WORD leaf-signal-handler }
}
\ OBJ-UNDEFINED undefined-def 2array suffix [
swap execute( -- x ) special-objects get set-at
] assoc-each ;
: emit-special-object ( obj idx -- )
[ prepare-object ] [ header-size + ] bi* fixup ;
: emit-special-objects ( -- )
special-objects get [ swap emit-special-object ] assoc-each ;
2007-09-20 18:09:08 -04:00
: fixup-header ( -- )
heap-size data-heap-size-offset fixup ;
2010-01-27 23:30:35 -05:00
: build-generics ( -- )
[
all-words
[ generic? ] filter
[ make-generic ] each
] with-compilation-unit ;
2008-02-10 02:49:27 -05:00
: build-image ( -- image )
600,000 <vector> bootstrapping-image set
60,000 <hashtable> objects set
emit-image-header
"Building generic words..." print flush
2010-01-27 23:30:35 -05:00
build-generics
2007-09-20 18:09:08 -04:00
"Serializing words..." print flush
emit-words
"Serializing JIT data..." print flush
emit-jit-data
"Serializing global namespace..." print flush
emit-global
"Serializing singletons..." print flush
emit-singletons
"Serializing special object table..." print flush
emit-special-objects
2007-09-20 18:09:08 -04:00
"Performing word fixups..." print flush
fixup-words
"Performing header fixups..." print flush
fixup-header
"Image length: " write bootstrapping-image get length .
2007-09-20 18:09:08 -04:00
"Object cache size: " write objects get assoc-size .
\ last-word global delete-at
bootstrapping-image get ;
2007-09-20 18:09:08 -04:00
! Image output
: (write-image) ( image -- )
bootstrap-cell output-stream get
big-endian get
[ '[ _ >be _ stream-write ] each ]
[ '[ _ >le _ stream-write ] each ] if ;
2007-09-20 18:09:08 -04:00
2008-02-10 02:49:27 -05:00
: write-image ( image -- )
"Writing image to " write
architecture get boot-image-name resource-path
2008-03-31 02:19:21 -04:00
[ write "..." print flush ]
[ binary [ (write-image) ] with-file-writer ] bi ;
2007-09-20 18:09:08 -04:00
PRIVATE>
: make-image ( arch -- )
2012-07-19 14:24:45 -04:00
architecture associate H{
{ parser-quiet? f }
{ auto-use? f }
} assoc-union! [
2007-09-20 18:09:08 -04:00
"resource:/core/bootstrap/stage1.factor" run-file
2008-02-10 02:49:27 -05:00
build-image
write-image
2012-07-19 14:24:45 -04:00
] with-variables ;
2007-09-20 18:09:08 -04:00
: make-images ( -- )
image-names [ make-image ] each ;
: make-my-image ( -- )
my-arch-name make-image ;