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