1 ! Copyright (C) 2007, 2010 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.libraries arrays assocs byte-arrays classes
4 classes.builtin combinators combinators.private command-line
5 compiler.crossref compiler.errors compiler.units continuations
6 definitions fry generic generic.single generic.standard grouping
7 hashtables init io io.backend io.encodings.utf8 io.files io.pathnames
8 io.streams.c kernel kernel.private locals make math memoize memory
9 namespaces parser parser.notes quotations sequences sequences.deep
10 sequences.private sets slots.private source-files source-files.errors
11 strings strings.parser system tools.deploy.config vocabs vocabs.loader
12 vocabs.loader.private vocabs.parser words ;
13 QUALIFIED: classes.private
14 IN: tools.deploy.shaker
16 ! This file is some hairy shit.
18 : add-command-line-hook ( -- )
21 command-line set-global
22 ] "command-line" startup-hooks get set-at ;
24 : set-stop-after-last-window? ( -- )
25 get-namestack [ "stop-after-last-window?" swap key? ] any? [
26 "ui-stop-after-last-window?" "ui.backend" lookup-word [
27 "stop-after-last-window?" get swap set-global
31 : strip-startup-hooks ( -- )
32 "Stripping startup hooks" show
38 [ startup-hooks get delete-at ] each
40 "threads" startup-hooks get delete-at
43 "io.backend" startup-hooks get delete-at
51 } [ startup-hooks get delete-at ] each
54 : strip-debugger ( -- )
55 strip-debugger? "debugger" lookup-vocab and [
56 "Stripping debugger" show
57 "vocab:tools/deploy/shaker/strip-debugger.factor"
61 : strip-ui-error-hook ( -- )
62 strip-debugger? deploy-ui? get and "ui" lookup-vocab and [
63 "Installing generic UI error hook" show
64 "vocab:tools/deploy/shaker/strip-ui-error-hook.factor"
70 "Stripping manual memory management debug code" show
71 "vocab:tools/deploy/shaker/strip-libc.factor"
75 : strip-destructors ( -- )
76 "Stripping destructor debug code" show
77 "vocab:tools/deploy/shaker/strip-destructors.factor"
81 "Stripping stack effect checking from call( and execute(" show
82 "vocab:tools/deploy/shaker/strip-call.factor" run-file ;
85 "cocoa" lookup-vocab [
86 "Stripping unused Cocoa methods" show
87 "vocab:tools/deploy/shaker/strip-cocoa.factor"
91 : strip-gobject ( -- )
92 "gobject-introspection.types" lookup-vocab [
93 "Stripping GObject type info" show
94 "vocab:tools/deploy/shaker/strip-gobject.factor"
98 : strip-gtk-icon ( -- )
99 "ui.backend.gtk" lookup-vocab [
100 "Stripping GTK icon loading code" show
101 "vocab:tools/deploy/shaker/strip-gtk-icon.factor"
105 : strip-specialized-arrays ( -- )
106 strip-dictionary? "specialized-arrays" lookup-vocab and [
107 "Stripping specialized arrays" show
108 "vocab:tools/deploy/shaker/strip-specialized-arrays.factor"
112 : strip-word-names ( words -- )
113 "Stripping word names" show
114 [ f >>name f >>vocabulary drop ] each ;
116 : strip-word-defs ( words -- )
117 "Stripping symbolic word definitions" show
118 [ [ ] >>def drop ] each ;
120 : strip-word-props ( stripped-props words -- )
121 "Stripping word properties" show
124 [ drop _ member? ] assoc-reject sift-values
129 : stripped-word-props ( -- seq )
144 "default-output-classes"
187 "predicate-definition"
228 deploy-c-types? get [
229 { "c-type" "struct-slots" "struct-align" } %
233 : strip-words ( props -- )
235 deploy-word-props? get [ 2dup strip-word-props ] unless
236 deploy-word-defs? get [ dup strip-word-defs ] unless
237 strip-word-names? [ dup strip-word-names strip-stack-traces ] when
240 : strip-memoized ( -- )
241 "Clearing memoized word caches" show
242 [ memoized? ] instances [ reset-memoized ] each ;
244 : compiler-classes ( -- set )
245 { "compiler" "stack-checker" } [
246 loaded-child-vocab-names
247 [ vocab-words ] map concat
249 ] map concat fast-set ;
251 : prune-decision-tree ( tree classes -- )
252 [ tuple class>type ] 2dip '[
258 [ drop _ in? ] assoc-reject
266 : strip-compiler-classes ( -- )
268 "Stripping compiler classes" show
269 [ single-generic? ] instances
270 compiler-classes '[ "decision-tree" word-prop _ prune-decision-tree ] each
273 : recursive-subst ( seq old new -- )
278 { [ 2over eq? ] [ 2nip ] }
279 ! recurse into arrays
280 { [ pick array? ] [ [ dup ] 2dip recursive-subst ] }
281 ! otherwise do nothing
286 : strip-default-method ( generic new-default -- )
288 [ "decision-tree" word-prop ]
289 [ "default-method" word-prop ] bi
293 : new-default-method ( -- gensym )
294 [ [ "No method" throw ] ( -- * ) define-temp ] with-compilation-unit ;
296 : strip-default-methods ( -- )
297 ! In a development image, each generic has its own default method.
298 ! This gives better error messages for runtime type errors, but
299 ! takes up space. For deployment we merge them all together.
301 "Stripping default methods" show
302 [ single-generic? ] instances
303 new-default-method '[ _ strip-default-method ] each
306 : vocab-tree-globals ( except names -- words )
307 [ loaded-child-vocab-names [ vocab-words ] map concat ] map concat
308 swap [ first2 lookup-word ] map sift diff ;
310 : stripped-globals ( -- seq )
312 "inspector-hook" "inspector" lookup-word ,
314 source-files:source-files
316 continuations:error-continuation
317 continuations:error-thread
318 continuations:restarts
321 "disposables" "destructors" lookup-word ,
323 "functor-words" "functors.backend" lookup-word ,
329 } vocab-tree-globals %
331 ! Don't want to strip globals from test programs
332 { } { "tools" } vocab-tree-globals
333 { } { "tools.deploy.test" } vocab-tree-globals diff %
335 deploy-unicode? get [
336 { } { "unicode" } vocab-tree-globals %
340 "libraries" "alien" lookup-word ,
342 { { "yield-hook" "compiler.utilities" } }
343 { "cpu" "compiler" } vocab-tree-globals %
348 classes.private:next-method-quot-cache
349 classes.private:class-and-cache
350 classes.private:class-not-cache
351 classes.private:class-or-cache
352 classes.private:class<=-cache
353 classes.private:classes-intersect-cache
354 classes.private:implementors-map
355 classes.private:update-map
357 compiler.crossref:compiled-crossref
358 compiler.crossref:generic-call-site-crossref
360 compiler.errors:compiler-errors
365 source-files.errors:error-types
366 source-files.errors:error-observers
369 vocabs:vocab-observers
370 vocabs.loader:add-vocab-root-hook
371 vocabs.parser:manifest
376 { } { "layouts" } vocab-tree-globals %
378 { } { "math.partial-dispatch" } vocab-tree-globals %
380 { } { "math.vectors.simd" } vocab-tree-globals %
382 { } { "peg" } vocab-tree-globals %
386 { } { "prettyprint.config" } vocab-tree-globals %
390 \ compiler.errors:compiler-errors ,
394 : cleared-globals ( -- seq )
407 "io-thread" "io.thread" lookup-word ,
410 "initial-thread" "threads" lookup-word ,
413 strip-io? [ io-backend , ] when
419 } vocab-tree-globals %
421 "windows-messages" "windows.messages" lookup-word [ , ] when*
424 : strip-global? ( name stripped-globals -- ? )
425 '[ _ member? ] [ tuple? ] bi or ;
427 : clear-global? ( name cleared-globals -- ? )
428 '[ _ member? ] [ string? ] bi or ;
430 : strip-globals ( -- )
432 "Stripping globals" show
433 stripped-globals :> to-strip
434 cleared-globals :> to-clear
436 [ drop to-strip strip-global? ] assoc-reject!
439 swap to-clear clear-global?
440 [ f swap value<< ] [ drop ] if
446 ! On all platforms, if deploy-io is 1, we strip out C streams.
447 ! On Unix, if deploy-io is 3, we strip out C streams as well.
448 ! On Windows, even if deploy-io is 3, C streams are still used
449 ! for the console, so don't strip it there.
451 native-io? os windows? not and
453 "Stripping C I/O" show
454 "vocab:tools/deploy/shaker/strip-c-io.factor" run-file
457 : compress ( pred post-process string -- )
458 "Compressing " prepend show
459 [ instances dup H{ } clone [ [ ] cache ] curry map ] dip call
462 : compress-object? ( obj -- ? )
464 { [ dup array? ] [ empty? ] }
465 { [ dup byte-array? ] [ drop t ] }
466 { [ dup string? ] [ drop t ] }
467 { [ dup wrapper? ] [ drop t ] }
471 : compress-objects ( -- )
472 [ compress-object? ] [ ] "objects" compress ;
474 : remain-compiled ( old new -- old new )
475 ! Quotations which were formerly compiled must remain
478 2dup [ quotation-compiled? ] [ quotation-compiled? not ] bi* and
479 [ nip jit-compile ] [ 2drop ] if
482 : compress-quotations ( -- )
483 [ quotation? ] [ remain-compiled ] "quotations" compress
484 [ quotation? ] instances [ f >>cached-effect f >>cache-counter drop ] each ;
488 : [:c] ( -- word ) ":c" "debugger" lookup-word ;
490 : [print-error] ( -- word ) "print-error" "debugger" lookup-word ;
492 : deploy-startup-quot ( word -- )
495 startup-hooks get values concat %
496 strip-debugger? [ , ] [
497 ! Don't reference 'try' directly since we don't want
498 ! to pull in the debugger and prettyprinter into every
503 [ _ execute( obj -- ) ] [
504 _ execute( obj -- ) nl
509 strip-io? [ [ flush ] % ] unless
514 : startup-stripper ( -- )
515 t parser-quiet? set-global
516 f output-stream set-global
517 [ V{ "resource:" } clone vocab-roots set-global ]
518 "vocabs.loader" startup-hooks get-global set-at ;
520 : next-method* ( method -- quot )
521 [ "method-class" word-prop ]
522 [ "method-generic" word-prop ] bi
525 : calls-next-method? ( method -- ? )
526 def>> flatten \ (call-next-method) swap member-eq? ;
528 : compute-next-methods ( -- )
529 [ standard-generic? ] instances [
530 "methods" word-prop values [ calls-next-method? ] filter
531 [ dup next-method* "next-method" set-word-prop ] each
533 "vocab:tools/deploy/shaker/next-methods.factor" run-file ;
535 : (clear-megamorphic-cache) ( i array -- )
536 ! Can't do any dispatch while clearing caches since that
537 ! might leave them in an inconsistent state.
539 2dup [ f ] 2dip set-array-nth
540 [ 1 + ] dip (clear-megamorphic-cache)
543 : clear-megamorphic-cache ( array -- )
544 [ 0 ] dip (clear-megamorphic-cache) ;
546 : find-megamorphic-caches ( -- seq )
547 "Finding megamorphic caches" show
548 [ standard-generic? ] instances [ def>> third ] map ;
550 : clear-megamorphic-caches ( cache -- )
551 "Clearing megamorphic caches" show
552 [ clear-megamorphic-cache ] each ;
554 : write-vocab-manifest ( vocab-manifest-out -- )
555 "Writing vocabulary manifest to " write dup print flush
556 loaded-vocab-names "VOCABS:" prefix
557 deploy-libraries get [ lookup-library path>> ] map members
558 "LIBRARIES:" prefix append
559 swap utf8 set-file-lines ;
561 : prepare-deploy-libraries ( -- )
562 "Preparing deployed libraries" show
563 deploy-libraries get [
565 [ path>> >deployed-library-path ] [ abi>> ] bi make-library
570 "deploy-libraries" "alien.libraries" lookup-word forget
571 "deploy-library" "alien.libraries" lookup-word forget
572 ">deployed-library-path" "alien.libraries.private" lookup-word forget
573 ] with-compilation-unit ;
575 : strip ( vocab-manifest-out -- )
576 [ write-vocab-manifest ] when*
578 prepare-deploy-libraries
587 strip-specialized-arrays
590 add-command-line-hook
592 strip-default-methods
593 strip-compiler-classes
594 ! we can't use the Factor debugger or Factor I/O anymore
595 f ERROR-HANDLER-QUOT set-special-object
596 deploy-vocab get vocab-main deploy-startup-quot
597 find-megamorphic-caches
604 clear-megamorphic-caches ;
606 : die-with ( error original-error -- * )
607 ! We don't want DCE to drop the error before the die call!
608 [ die 1 exit ] ( a -- * ) call-effect-unsafe ;
610 : die-with2 ( error original-error -- * )
611 ! We don't want DCE to drop the error before the die call!
612 [ die 1 exit ] ( a b -- * ) call-effect-unsafe ;
614 : deploy-error-handler ( quot -- )
617 [ original-error get die-with2 ]
618 ! Don't reference these words literally, if we're stripping the
619 ! debugger out we don't want to load the prettyprinter at all
620 [ [:c] execute( -- ) nl [print-error] execute( error -- ) flush ] if
624 : (deploy) ( final-image vocab-manifest-out vocab config -- )
625 ! Does the actual work of a deployment in the slave
631 "tools.errors" require
634 "ui.debugger" require
637 [ deploy-vocab namespaces:set ] [ require ] [
639 "Vocabulary has no MAIN: word." print flush 1 exit
642 set-stop-after-last-window?
644 "Saving final image" show
646 ] deploy-error-handler
651 "vocab-manifest-out" get
653 "Deploying " write dup write "..." print
654 "deploy-config" get parse-file first