]> gitweb.factorcode.org Git - factor.git/blob - basis/tools/deploy/shaker/shaker.factor
Specialized array overhaul
[factor.git] / basis / tools / deploy / shaker / shaker.factor
1 ! Copyright (C) 2007, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays accessors io.backend io.streams.c init fry
4 namespaces math make assocs kernel parser parser.notes lexer
5 strings.parser vocabs sequences sequences.deep sequences.private
6 words memory kernel.private continuations io vocabs.loader
7 system strings sets vectors quotations byte-arrays sorting
8 compiler.units definitions generic generic.standard
9 generic.single tools.deploy.config combinators classes
10 classes.builtin slots.private grouping ;
11 QUALIFIED: bootstrap.stage2
12 QUALIFIED: command-line
13 QUALIFIED: compiler.errors
14 QUALIFIED: continuations
15 QUALIFIED: definitions
16 QUALIFIED: init
17 QUALIFIED: layouts
18 QUALIFIED: source-files
19 QUALIFIED: source-files.errors
20 QUALIFIED: vocabs
21 IN: tools.deploy.shaker
22
23 ! This file is some hairy shit.
24
25 : strip-init-hooks ( -- )
26     "Stripping startup hooks" show
27     {
28         "alien.strings"
29         "command-line"
30         "cpu.x86"
31         "destructors"
32         "environment"
33         "libc"
34     }
35     [ init-hooks get delete-at ] each
36     deploy-threads? get [
37         "threads" init-hooks get delete-at
38     ] unless
39     native-io? [
40         "io.thread" init-hooks get delete-at
41     ] unless
42     strip-io? [
43         "io.files" init-hooks get delete-at
44         "io.backend" init-hooks get delete-at
45         "io.thread" init-hooks get delete-at
46     ] when
47     strip-dictionary? [
48         {
49             ! "compiler.units"
50             "vocabs"
51             "vocabs.cache"
52             "source-files.errors"
53         } [ init-hooks get delete-at ] each
54     ] when ;
55
56 : strip-debugger ( -- )
57     strip-debugger? "debugger" vocab and [
58         "Stripping debugger" show
59         "vocab:tools/deploy/shaker/strip-debugger.factor"
60         run-file
61     ] when ;
62
63 : strip-libc ( -- )
64     "libc" vocab [
65         "Stripping manual memory management debug code" show
66         "vocab:tools/deploy/shaker/strip-libc.factor"
67         run-file
68     ] when ;
69
70 : strip-destructors ( -- )
71     "Stripping destructor debug code" show
72     "vocab:tools/deploy/shaker/strip-destructors.factor"
73     run-file ;
74
75 : strip-call ( -- )
76     "Stripping stack effect checking from call( and execute(" show
77     "vocab:tools/deploy/shaker/strip-call.factor" run-file ;
78
79 : strip-cocoa ( -- )
80     "cocoa" vocab [
81         "Stripping unused Cocoa methods" show
82         "vocab:tools/deploy/shaker/strip-cocoa.factor"
83         run-file
84     ] when ;
85
86 : strip-word-names ( words -- )
87     "Stripping word names" show
88     [ f >>name f >>vocabulary drop ] each ;
89
90 : strip-word-defs ( words -- )
91     "Stripping symbolic word definitions" show
92     [ "no-def-strip" word-prop not ] filter
93     [ [ ] >>def drop ] each ;
94
95 : sift-assoc ( assoc -- assoc' ) [ nip ] assoc-filter ;
96
97 : strip-word-props ( stripped-props words -- )
98     "Stripping word properties" show
99     [
100         swap '[
101             [
102                 [ drop _ member? not ] assoc-filter sift-assoc
103                 >alist f like
104             ] change-props drop
105         ] each
106     ] [
107         H{ } clone '[
108             [ [ _ [ ] cache ] map ] change-props drop
109         ] each
110     ] bi ;
111
112 : stripped-word-props ( -- seq )
113     [
114         strip-dictionary? [
115             {
116                 "alias"
117                 "boa-check"
118                 "coercer"
119                 "combination"
120                 "compiled-generic-uses"
121                 "compiled-uses"
122                 "constant"
123                 "constraints"
124                 "custom-inlining"
125                 "decision-tree"
126                 "declared-effect"
127                 "default"
128                 "default-method"
129                 "default-output-classes"
130                 "derived-from"
131                 "ebnf-parser"
132                 "engines"
133                 "forgotten"
134                 "identities"
135                 "inline"
136                 "inlined-block"
137                 "input-classes"
138                 "instances"
139                 "interval"
140                 "intrinsic"
141                 "lambda"
142                 "loc"
143                 "local-reader"
144                 "local-reader?"
145                 "local-writer"
146                 "local-writer?"
147                 "local?"
148                 "low-order"
149                 "macro"
150                 "members"
151                 "memo-quot"
152                 "methods"
153                 "mixin"
154                 "method-class"
155                 "method-generic"
156                 "modular-arithmetic"
157                 "no-compile"
158                 "owner-generic"
159                 "outputs"
160                 "participants"
161                 "predicate"
162                 "predicate-definition"
163                 "predicating"
164                 "primitive"
165                 "reader"
166                 "reading"
167                 "recursive"
168                 "register"
169                 "register-size"
170                 "shuffle"
171                 "slots"
172                 "special"
173                 "specializer"
174                 "specializations"
175                 "struct-slots"
176                 ! UI needs this
177                 ! "superclass"
178                 "transform-n"
179                 "transform-quot"
180                 "type"
181                 "writer"
182                 "writing"
183             } %
184         ] when
185         
186         strip-prettyprint? [
187             {
188                 "delimiter"
189                 "flushable"
190                 "foldable"
191                 "inline"
192                 "lambda"
193                 "macro"
194                 "memo-quot"
195                 "parsing"
196                 "word-style"
197             } %
198         ] when
199     ] { } make ;
200
201 : strip-words ( props -- )
202     [ word? ] instances
203     deploy-word-props? get [ 2dup strip-word-props ] unless
204     deploy-word-defs? get [ dup strip-word-defs ] unless
205     strip-word-names? [ dup strip-word-names ] when
206     2drop ;
207
208 : compiler-classes ( -- seq )
209     { "compiler" "stack-checker" }
210     [ child-vocabs [ words ] map concat [ class? ] filter ]
211     map concat unique ;
212
213 : prune-decision-tree ( tree classes -- )
214     [ tuple class>type ] 2dip '[
215         dup array? [
216             [
217                 dup array? [
218                     [
219                         2 group
220                         [ drop _ key? not ] assoc-filter
221                         concat
222                     ] map
223                 ] when
224             ] map
225         ] when
226     ] change-nth ;
227
228 : strip-compiler-classes ( -- )
229     strip-dictionary? [
230         "Stripping compiler classes" show
231         [ single-generic? ] instances
232         compiler-classes '[ "decision-tree" word-prop _ prune-decision-tree ] each
233     ] when ;
234
235 : recursive-subst ( seq old new -- )
236     '[
237         _ _
238         {
239             ! old becomes new
240             { [ 3dup drop eq? ] [ 2nip ] }
241             ! recurse into arrays
242             { [ pick array? ] [ [ dup ] 2dip recursive-subst ] }
243             ! otherwise do nothing
244             [ 2drop ]
245         } cond
246     ] change-each ;
247
248 : strip-default-method ( generic new-default -- )
249     [
250         [ "decision-tree" word-prop ]
251         [ "default-method" word-prop ] bi
252     ] dip
253     recursive-subst ;
254
255 : new-default-method ( -- gensym )
256     [ [ "No method" throw ] (( -- * )) define-temp ] with-compilation-unit ;
257
258 : strip-default-methods ( -- )
259     ! In a development image, each generic has its own default method.
260     ! This gives better error messages for runtime type errors, but
261     ! takes up space. For deployment we merge them all together.
262     strip-debugger? [
263         "Stripping default methods" show
264         [ single-generic? ] instances
265         new-default-method '[ _ strip-default-method ] each
266     ] when ;
267
268 : strip-vocab-globals ( except names -- words )
269     [ child-vocabs [ words ] map concat ] map concat
270     swap [ first2 lookup ] map sift diff ;
271
272 : stripped-globals ( -- seq )
273     [
274         "inspector-hook" "inspector" lookup ,
275
276         {
277             continuations:error
278             continuations:error-continuation
279             continuations:error-thread
280             continuations:restarts
281             init:init-hooks
282             source-files:source-files
283             input-stream
284             output-stream
285             error-stream
286         } %
287
288         "io-thread" "io.thread" lookup ,
289
290         "disposables" "destructors" lookup ,
291
292         "functor-words" "functors.backend" lookup ,
293         
294         deploy-threads? [
295             "initial-thread" "threads" lookup ,
296         ] unless
297
298         strip-io? [ io-backend , ] when
299
300         { } {
301             "alarms"
302             "tools"
303             "io.launcher"
304             "random"
305             "stack-checker"
306             "bootstrap"
307             "listener"
308         } strip-vocab-globals %
309
310         strip-dictionary? [
311             "libraries" "alien" lookup ,
312
313             { { "yield-hook" "compiler.utilities" } }
314             { "cpu" "compiler" } strip-vocab-globals %
315
316             {
317                 gensym
318                 name>char-hook
319                 next-method-quot-cache
320                 class-and-cache
321                 class-not-cache
322                 class-or-cache
323                 class<=-cache
324                 classes-intersect-cache
325                 implementors-map
326                 update-map
327                 command-line:main-vocab-hook
328                 compiled-crossref
329                 compiled-generic-crossref
330                 compiler-impl
331                 compiler.errors:compiler-errors
332                 lexer-factory
333                 print-use-hook
334                 root-cache
335                 source-files.errors:error-types
336                 source-files.errors:error-observers
337                 vocabs:dictionary
338                 vocabs:load-vocab-hook
339                 vocabs:vocab-observers
340                 word
341                 parser-notes
342             } %
343
344             { } { "layouts" } strip-vocab-globals %
345
346             { } { "math.partial-dispatch" } strip-vocab-globals %
347
348             { } { "peg" } strip-vocab-globals %
349         ] when
350
351         strip-prettyprint? [
352             { } { "prettyprint.config" } strip-vocab-globals %
353         ] when
354
355         strip-debugger? [
356             {
357                 compiler.errors:compiler-errors
358                 continuations:thread-error-hook
359             } %
360             
361             deploy-ui? get [
362                 "ui-error-hook" "ui.gadgets.worlds" lookup ,
363             ] when
364         ] when
365
366         deploy-c-types? get [
367             "c-types" "alien.c-types" lookup ,
368         ] unless
369
370         "windows-messages" "windows.messages" lookup [ , ] when*
371     ] { } make ;
372
373 : strip-globals ( stripped-globals -- )
374     strip-globals? [
375         "Stripping globals" show
376         global swap
377         '[ drop _ member? not ] assoc-filter
378         [ drop string? not ] assoc-filter ! strip CLI args
379         sift-assoc
380         21 setenv
381     ] [ drop ] if ;
382
383 : strip-c-io ( -- )
384     strip-io?
385     deploy-io get 3 = os windows? not and
386     or [
387         [
388             c-io-backend forget
389             "io.streams.c" forget-vocab
390             "io-thread-running?" "io.thread" lookup [
391                 global delete-at
392             ] when*
393         ] with-compilation-unit
394     ] when ;
395
396 : compress ( pred post-process string -- )
397     "Compressing " prepend show
398     [ instances dup H{ } clone [ [ ] cache ] curry map ] dip call
399     become ; inline
400
401 : compress-object? ( obj -- ? )
402     {
403         { [ dup array? ] [ empty? ] }
404         { [ dup byte-array? ] [ drop t ] }
405         { [ dup string? ] [ drop t ] }
406         { [ dup wrapper? ] [ drop t ] }
407         [ drop f ]
408     } cond ;
409
410 : compress-objects ( -- )
411     [ compress-object? ] [ ] "objects" compress ;
412
413 : remain-compiled ( old new -- old new )
414     ! Quotations which were formerly compiled must remain
415     ! compiled.
416     2dup [
417         2dup [ quot-compiled? ] [ quot-compiled? not ] bi* and
418         [ nip jit-compile ] [ 2drop ] if
419     ] 2each ;
420
421 : compress-quotations ( -- )
422     [ quotation? ] [ remain-compiled ] "quotations" compress
423     [ quotation? ] instances [ f >>cached-effect f >>cache-counter drop ] each ;
424
425 SYMBOL: deploy-vocab
426
427 : [:c] ( -- word ) ":c" "debugger" lookup ;
428
429 : [print-error] ( -- word ) "print-error" "debugger" lookup ;
430
431 : deploy-boot-quot ( word -- )
432     [
433         [ boot ] %
434         init-hooks get values concat %
435         strip-debugger? [ , ] [
436             ! Don't reference 'try' directly since we don't want
437             ! to pull in the debugger and prettyprinter into every
438             ! deployed app
439             [:c]
440             [print-error]
441             '[
442                 [ _ execute( obj -- ) ] [
443                     _ execute( obj -- ) nl
444                     _ execute( obj -- )
445                 ] recover
446             ] %
447         ] if
448         strip-io? [ [ flush ] % ] unless
449         [ 0 exit ] %
450     ] [ ] make
451     set-boot-quot ;
452
453 : init-stripper ( -- )
454     t "quiet" set-global
455     f output-stream set-global ;
456
457 : next-method* ( method -- quot )
458     [ "method-class" word-prop ]
459     [ "method-generic" word-prop ] bi
460     next-method ;
461
462 : calls-next-method? ( method -- ? )
463     def>> flatten \ (call-next-method) swap memq? ;
464
465 : compute-next-methods ( -- )
466     [ standard-generic? ] instances [
467         "methods" word-prop values [ calls-next-method? ] filter
468         [ dup next-method* "next-method" set-word-prop ] each
469     ] each
470     "vocab:tools/deploy/shaker/next-methods.factor" run-file ;
471
472 : (clear-megamorphic-cache) ( i array -- )
473     ! Can't do any dispatch while clearing caches since that
474     ! might leave them in an inconsistent state.
475     2dup 1 slot < [
476         2dup [ f ] 2dip set-array-nth
477         [ 1 + ] dip (clear-megamorphic-cache)
478     ] [ 2drop ] if ;
479
480 : clear-megamorphic-cache ( array -- )
481     [ 0 ] dip (clear-megamorphic-cache) ;
482
483 : find-megamorphic-caches ( -- seq )
484     "Finding megamorphic caches" show
485     [ standard-generic? ] instances [ def>> third ] map ;
486
487 : clear-megamorphic-caches ( cache -- )
488     "Clearing megamorphic caches" show
489     [ clear-megamorphic-cache ] each ;
490
491 : strip ( -- )
492     init-stripper
493     strip-libc
494     strip-destructors
495     strip-call
496     strip-cocoa
497     strip-debugger
498     compute-next-methods
499     strip-init-hooks
500     strip-c-io
501     strip-default-methods
502     strip-compiler-classes
503     f 5 setenv ! we can't use the Factor debugger or Factor I/O anymore
504     deploy-vocab get vocab-main deploy-boot-quot
505     find-megamorphic-caches
506     stripped-word-props
507     stripped-globals strip-globals
508     compress-objects
509     compress-quotations
510     strip-words
511     clear-megamorphic-caches ;
512
513 : deploy-error-handler ( quot -- )
514     [
515         strip-debugger?
516         [ error-continuation get call>> callstack>array die 1 exit ]
517         ! Don't reference these words literally, if we're stripping the
518         ! debugger out we don't want to load the prettyprinter at all
519         [ [:c] execute( -- ) nl [print-error] execute( error -- ) flush ] if
520         1 exit
521     ] recover ; inline
522
523 : (deploy) ( final-image vocab config -- )
524     #! Does the actual work of a deployment in the slave
525     #! stage2 image
526     [
527         [
528             strip-debugger? [
529                 "debugger" require
530                 "inspector" require
531                 deploy-ui? get [
532                     "ui.debugger" require
533                 ] when
534             ] unless
535             deploy-vocab set
536             deploy-vocab get require
537             deploy-vocab get vocab-main [
538                 "Vocabulary has no MAIN: word." print flush 1 exit
539             ] unless
540             strip
541             "Saving final image" show
542             save-image-and-exit
543         ] deploy-error-handler
544     ] bind ;
545
546 : do-deploy ( -- )
547     "output-image" get
548     "deploy-vocab" get
549     "Deploying " write dup write "..." print
550     "deploy-config" get parse-file first
551     (deploy) ;
552
553 MAIN: do-deploy