factor/basis/bootstrap/image/image.factor

599 lines
14 KiB
Factor
Raw Normal View History

! Copyright (C) 2004, 2009 Slava Pestov.
2007-09-20 18:09:08 -04:00
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.strings arrays byte-arrays generic hashtables
2009-10-30 21:53:18 -04:00
hashtables.private io io.binary io.files io.encodings.binary
io.pathnames kernel kernel.private math namespaces make parser
prettyprint sequences strings sbufs vectors words quotations
assocs system layouts splitting grouping growable classes
classes.builtin classes.tuple classes.tuple.private vocabs
vocabs.loader source-files definitions debugger
quotations.private combinators combinators.short-circuit
math.order math.private accessors slots.private
generic.single.private compiler.units compiler.constants fry
locals bootstrap.image.syntax generalizations ;
2007-09-20 18:09:08 -04:00
IN: bootstrap.image
2008-11-07 22:09:42 -05:00
: arch ( os cpu -- arch )
{
{ "ppc" [ "-ppc" append ] }
{ "x86.64" [ "winnt" = "winnt" "unix" ? "-x86.64" append ] }
2008-11-07 22:09:42 -05:00
[ nip ]
} case ;
: my-arch ( -- arch )
2008-11-07 22:09:42 -05:00
os name>> cpu name>> arch ;
: boot-image-name ( arch -- string )
2008-12-06 19:58:45 -05:00
"boot." ".image" surround ;
: my-boot-image-name ( -- string )
my-arch boot-image-name ;
: images ( -- seq )
{
"x86.32"
2008-11-07 21:33:32 -05:00
"winnt-x86.64" "unix-x86.64"
"linux-ppc" "macosx-ppc"
} ;
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 -- ? )
2009-10-30 21:53:18 -04:00
{ [ [ class ] bi@ = ] [ (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
2009-10-30 21:53:18 -04:00
M: bignum (eql?) = ;
2009-10-30 21:53:18 -04:00
M: float (eql?) fp-bitwise= ;
M: sequence (eql?) 2dup [ length ] bi@ = [ [ 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 ;
2007-09-20 18:09:08 -04:00
! Constants
2009-02-22 20:13:08 -05:00
CONSTANT: image-magic HEX: 0f0e0d0c
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: userenv-size 70
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
CONSTANT: t-offset 6
CONSTANT: 0-offset 7
CONSTANT: 1-offset 8
CONSTANT: -1-offset 9
2007-09-20 18:09:08 -04:00
SYMBOL: sub-primitives
SYMBOL: jit-relocations
SYMBOL: jit-offset
: compute-offset ( rc -- offset )
[ building get length jit-offset get + ] dip
rc-absolute-cell = bootstrap-cell 4 ? - ;
: jit-rel ( rc rt -- )
over compute-offset 3array jit-relocations get push-all ;
SYMBOL: jit-parameters
: jit-parameter ( parameter -- )
jit-parameters get push ;
SYMBOL: jit-literals
: jit-literal ( literal -- )
jit-literals get push ;
: jit-vm ( offset rc -- )
[ jit-parameter ] dip rt-vm jit-rel ;
: jit-dlsym ( name library rc -- )
rt-dlsym jit-rel [ string>symbol jit-parameter ] bi@ ;
:: jit-conditional ( test-quot false-quot -- )
[ 0 test-quot call ] B{ } make length :> len
building get length jit-offset get + len +
[ jit-offset set false-quot call ] B{ } make
[ length test-quot call ] [ % ] bi ; inline
: make-jit ( quot -- jit-parameters jit-literals jit-code )
[
0 jit-offset set
V{ } clone jit-parameters set
V{ } clone jit-literals set
V{ } clone jit-relocations set
call( -- )
jit-parameters get >array
jit-literals get >array
jit-relocations get >array
] B{ } make prefix ;
: jit-define ( quot name -- )
[ make-jit 2nip ] dip set ;
: define-sub-primitive ( quot word -- )
[ make-jit 3array ] dip sub-primitives get set-at ;
: define-sub-primitive* ( quot non-tail-quot tail-quot word -- )
[
[ make-jit ]
[ make-jit 2nip ]
[ make-jit 2nip ]
tri* 5 narray
] dip
sub-primitives get set-at ;
2007-09-20 18:09:08 -04:00
! The image being constructed; a vector of word-size integers
SYMBOL: image
! Image output format
SYMBOL: big-endian
! Bootstrap architecture name
SYMBOL: architecture
RESET
2007-09-20 18:09:08 -04:00
! Boot quotation, set in stage1.factor
2009-11-20 01:55:16 -05:00
USERENV: bootstrap-startup-quot 20
! Bootstrap global namesapce
USERENV: bootstrap-global 21
2007-09-20 18:09:08 -04:00
! JIT parameters
USERENV: jit-prolog 23
USERENV: jit-primitive-word 24
USERENV: jit-primitive 25
USERENV: jit-word-jump 26
USERENV: jit-word-call 27
USERENV: jit-if-word 28
USERENV: jit-if 29
USERENV: jit-epilog 30
USERENV: jit-return 31
USERENV: jit-profiling 32
USERENV: jit-push 33
USERENV: jit-dip-word 34
USERENV: jit-dip 35
USERENV: jit-2dip-word 36
USERENV: jit-2dip 37
USERENV: jit-3dip-word 38
USERENV: jit-3dip 39
USERENV: jit-execute 40
USERENV: jit-declare-word 41
USERENV: callback-stub 48
2009-04-28 04:48:37 -04:00
! PIC stubs
USERENV: pic-load 49
USERENV: pic-tag 50
USERENV: pic-tuple 51
USERENV: pic-check-tag 52
USERENV: pic-check-tuple 53
USERENV: pic-hit 54
USERENV: pic-miss-word 55
USERENV: pic-miss-tail-word 56
2009-04-28 04:48:37 -04:00
! Megamorphic dispatch
USERENV: mega-lookup 57
USERENV: mega-lookup-word 58
USERENV: mega-miss-word 59
2007-12-26 20:40:46 -05:00
! Default definition for undefined words
USERENV: undefined-quot 60
: userenv-offset ( symbol -- n )
userenvs get at header-size + ;
2007-09-20 18:09:08 -04:00
: emit ( cell -- ) image get push ;
: emit-64 ( cell -- )
bootstrap-cell 8 = [
emit
] [
d>w/w big-endian get [ swap ] unless emit emit
] if ;
: emit-seq ( seq -- ) image get push-all ;
: fixup ( value offset -- ) image get set-nth ;
: heap-size ( -- size )
image get length header-size - userenv-size -
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
2009-11-10 22:06:36 -05:00
[ swap emit-header call align-here ] dip ;
2007-09-20 18:09:08 -04:00
inline
! Write an object to the image.
GENERIC: ' ( obj -- ptr )
! 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 ! pointer to t object
0 emit ! pointer to bignum 0
0 emit ! pointer to bignum 1
0 emit ! pointer to bignum -1
userenv-size [ f ' emit ] times ;
: emit-userenv ( symbol -- )
2008-03-31 02:19:21 -04:00
[ get ' ] [ userenv-offset ] bi fixup ;
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>seq ( n -- seq )
#! 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 -- )
2008-03-31 02:19:21 -04:00
dup dup 0 < [ neg ] when bignum>seq
[ 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 '
[
bignum [ emit-bignum ] emit-object
] cache-eql-object ;
2007-09-20 18:09:08 -04:00
! Fixnums
M: fixnum '
#! 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?
2008-01-02 19:36:36 -05:00
[ tag-fixnum ] [ >bignum ' ] 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 ' n>> tag-fixnum ;
2007-09-20 18:09:08 -04:00
! Floats
M: float '
[
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
2008-06-08 16:32:55 -04:00
: t, ( -- ) t t-offset fixup ;
2007-09-20 18:09:08 -04:00
M: f '
#! f is #define F RETAG(0,F_TYPE)
drop \ f type-number ;
2007-09-20 18:09:08 -04:00
2008-06-08 16:32:55 -04:00
: 0, ( -- ) 0 >bignum ' 0-offset fixup ;
: 1, ( -- ) 1 >bignum ' 1-offset fixup ;
: -1, ( -- ) -1 >bignum ' -1-offset fixup ;
2007-09-20 18:09:08 -04:00
! Words
: word-sub-primitive ( word -- obj )
global [ target-word ] bind 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>> , ]
[ drop 0 , ] ! count
[ word-sub-primitive , ]
[ drop 0 , ] ! xt
[ drop 0 , ] ! code
[ drop 0 , ] ! profiling
2008-03-31 02:19:21 -04:00
} cleave
] { } make [ ' ] map
] bi
\ word [ emit-seq ] emit-object
] keep put-object ;
2007-09-20 18:09:08 -04:00
: word-error ( word msg -- * )
[ % dup vocabulary>> % " " % name>> % ] "" make throw ;
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
2007-09-20 18:09:08 -04:00
[ ] [ "Not in image: " word-error ] ?if ;
: fixup-words ( -- )
image get [ dup word? [ fixup-word ] when ] map! drop ;
2007-09-20 18:09:08 -04:00
M: word ' ;
! Wrappers
M: wrapper '
[ wrapped>> ' 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 ' ] [ ] tri
string [
[ emit-fixnum ]
[ emit ]
[ f ' emit ascii-part pad-bytes emit-bytes ]
tri*
2007-09-20 18:09:08 -04:00
] emit-object ;
M: string '
#! 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
2008-04-30 17:11:55 -04:00
M: byte-array '
[
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 transfer-word require-tuple-layout ] bi prefix [ ' ] 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 )
dup class name>> "tombstone" =
[ [ (emit-tuple) ] cache-eql-object ]
[ [ (emit-tuple) ] cache-eq-object ]
if ;
2007-09-20 18:09:08 -04:00
M: tuple ' emit-tuple ;
M: tombstone '
2008-09-03 00:21:08 -04:00
state>> "((tombstone))" "((empty))" ?
"hashtables.private" lookup 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 )
[ ' ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
2007-09-20 18:09:08 -04:00
M: array ' [ 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 tuple-class? ]
[ second fixnum? ]
[ third fixnum? ]
tri and and
] [ drop f ] if ;
2008-11-06 02:58:07 -05:00
M: tuple-layout-array '
[
[ dup integer? [ <fake-bignum> ] when ] map
emit-array
] cache-eql-object ;
2007-09-20 18:09:08 -04:00
! Quotations
M: quotation '
[
array>> '
quotation [
2007-09-20 18:09:08 -04:00
emit ! array
2009-03-16 21:11:36 -04:00
f ' emit ! cached-effect
f ' emit ! cache-counter
0 emit ! xt
0 emit ! code
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-global ( -- )
2008-09-18 00:28:54 -04:00
{
dictionary source-files builtins
update-map implementors-map
} [ [ bootstrap-word ] [ get ] bi ] H{ } map>assoc
{
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
2008-09-18 00:28:54 -04:00
} [ H{ } clone ] H{ } map>assoc assoc-union
bootstrap-global set ;
2007-09-20 18:09:08 -04:00
: emit-jit-data ( -- )
\ if jit-if-word set
2008-01-02 19:36:36 -05:00
\ do-primitive jit-primitive-word set
\ dip jit-dip-word set
\ 2dip jit-2dip-word set
\ 3dip jit-3dip-word set
2009-04-28 04:48:37 -04:00
\ inline-cache-miss \ pic-miss-word set
\ inline-cache-miss-tail \ pic-miss-tail-word set
\ mega-cache-lookup \ mega-lookup-word set
\ mega-cache-miss \ mega-miss-word set
\ declare jit-declare-word set
[ undefined ] undefined-quot set ;
: emit-userenvs ( -- )
userenvs get keys [ emit-userenv ] each ;
2007-09-20 18:09:08 -04:00
: fixup-header ( -- )
heap-size data-heap-size-offset fixup ;
2008-02-10 02:49:27 -05:00
: build-image ( -- image )
800000 <vector> image set
20000 <hashtable> objects set
2009-11-10 22:06:36 -05:00
emit-image-header t, 0, 1, -1,
"Building generic words..." print flush
remake-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 user environment..." print flush
emit-userenvs
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 image get length .
"Object cache size: " write objects get assoc-size .
2008-02-10 02:49:27 -05:00
\ word global delete-at
image get ;
2007-09-20 18:09:08 -04:00
! Image output
: (write-image) ( image -- )
bootstrap-cell big-endian get
[ '[ _ >be write ] each ]
[ '[ _ >le 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 -- )
2008-02-10 02:49:27 -05:00
[
architecture set
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
2008-02-10 02:49:27 -05:00
] with-scope ;
2007-09-20 18:09:08 -04:00
: make-images ( -- )
images [ make-image ] each ;