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