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