From b03268f0471ab3f148901ab80ffca8dd3b0e120d Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Mon, 27 Sep 2010 18:57:14 -0500 Subject: [PATCH 01/15] Make secure-context persist longer than a millisecond when a server gets started. --- basis/io/servers/connection/connection.factor | 68 +++++++++++-------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/basis/io/servers/connection/connection.factor b/basis/io/servers/connection/connection.factor index fbe5421cea..6866a9d4a7 100644 --- a/basis/io/servers/connection/connection.factor +++ b/basis/io/servers/connection/connection.factor @@ -22,7 +22,8 @@ semaphore timeout encoding handler -server-stopped ; +server-stopped +secure-context ; SYMBOL: running-servers running-servers [ HS{ } clone ] initialize @@ -131,14 +132,24 @@ M: threaded-server handle-client* handler>> call( -- ) ; [ (accept-connection) ] if* ; +: with-existing-secure-context ( threaded-server quot -- ) + [ secure-context>> secure-context ] dip with-variable ; inline + : accept-loop ( server -- ) [ accept-connection ] [ accept-loop ] bi ; -: start-accept-loop ( server -- ) accept-loop ; +: start-accept-loop ( threaded-server server -- ) + '[ _ accept-loop ] with-existing-secure-context ; \ start-accept-loop NOTICE add-error-logging +: create-secure-context ( threaded-server -- threaded-server ) + dup secure>> [ + dup secure-config>> >>secure-context + ] when ; + : init-server ( threaded-server -- threaded-server ) + create-secure-context >>server-stopped dup semaphore>> [ dup max-connections>> [ @@ -153,48 +164,45 @@ ERROR: no-ports-configured threaded-server ; '[ [ _ |dispose ] map ] with-destructors ; : set-servers ( threaded-server -- threaded-server ) - dup dup listen-on [ no-ports-configured ] [ (make-servers) ] if-empty - >>servers ; + dup [ + dup dup listen-on [ no-ports-configured ] [ (make-servers) ] if-empty + >>servers + ] with-existing-secure-context ; : server-thread-name ( threaded-server addrspec -- string ) [ name>> ] [ addr>> present ] bi* " server on " glue ; -: (start-server) ( threaded-server -- ) - init-server - dup threaded-server [ - [ ] [ name>> ] bi - [ - set-servers - dup add-running-server - dup servers>> - [ - [ nip '[ _ [ start-accept-loop ] with-disposal ] ] - [ server-thread-name ] 2bi spawn drop - ] with each - ] with-logging - ] with-variable ; - PRIVATE> : start-server ( threaded-server -- threaded-server ) - #! Only create a secure-context if we want to listen on - #! a secure port, otherwise start-server won't work at - #! all if SSL is not available. - dup dup secure>> [ - dup secure-config>> [ - (start-server) - ] with-secure-context - ] [ - (start-server) - ] if ; + init-server + [ + dup threaded-server [ + [ ] [ name>> ] bi + [ + set-servers + dup add-running-server + dup servers>> + [ + [ '[ _ _ [ start-accept-loop ] with-disposal ] ] + [ server-thread-name ] 2bi spawn drop + ] with each + ] with-logging + ] with-variable + ] keep ; : server-running? ( threaded-server -- ? ) server-stopped>> [ value>> not ] [ f ] if* ; : stop-server ( threaded-server -- ) dup server-running? [ - [ [ f ] change-servers drop dispose-each ] [ remove-running-server ] + [ + [ + [ secure-context>> [ &dispose drop ] when* ] + [ [ f ] change-servers drop dispose-each ] bi + ] with-destructors + ] [ server-stopped>> raise-flag ] tri ] [ drop From 4ade3b6a5c2fe3e6ca7efb0cf4220879b0aacfe7 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Mon, 27 Sep 2010 19:00:54 -0500 Subject: [PATCH 02/15] Clean up io.servers.connection >insecure word --- basis/io/servers/connection/connection.factor | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/basis/io/servers/connection/connection.factor b/basis/io/servers/connection/connection.factor index 6866a9d4a7..940b20f762 100644 --- a/basis/io/servers/connection/connection.factor +++ b/basis/io/servers/connection/connection.factor @@ -70,23 +70,20 @@ GENERIC: handle-client* ( threaded-server -- ) insecure) ( obj -- obj ) +GENERIC: >insecure ( obj -- obj ) -M: inet (>insecure) ; -M: inet4 (>insecure) ; -M: inet6 (>insecure) ; -M: local (>insecure) ; -M: integer (>insecure) internet-server ; -M: string (>insecure) internet-server ; -M: array (>insecure) [ (>insecure) ] map ; -M: f (>insecure) ; - -: >insecure ( obj -- seq ) - (>insecure) dup sequence? [ 1array ] unless ; +M: inet >insecure 1array ; +M: inet4 >insecure 1array ; +M: inet6 >insecure 1array ; +M: local >insecure 1array ; +M: integer >insecure internet-server 1array ; +M: string >insecure internet-server 1array ; +M: array >insecure [ >insecure ] map ; +M: f >insecure ; : >secure ( addrspec -- addrspec' ) >insecure - [ dup { [ secure? ] [ not ] } 1|| [ ] unless ] map ; + [ dup secure? [ ] unless ] map ; : listen-on ( threaded-server -- addrspecs ) [ secure>> >secure ] [ insecure>> >insecure ] bi append From 0bbfa64b2478129a9e3e63bae34ed25f2375555f Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Mon, 27 Sep 2010 19:12:33 -0500 Subject: [PATCH 03/15] Squashed commit of the following: commit 54b3e19c7407707fabddd53872559c58cd5143d2 Author: Doug Coleman Date: Mon Sep 27 19:10:15 2010 -0500 Fix typo commit 3207516dc93e0e1edc9f119efcc79f4484eab244 Author: Doug Coleman Date: Mon Sep 27 19:08:30 2010 -0500 Rename io.servers.connection to io.servers --- basis/channels/remote/remote-docs.factor | 2 +- basis/concurrency/distributed/distributed-tests.factor | 4 ++-- basis/concurrency/distributed/distributed.factor | 2 +- basis/ftp/server/server-tests.factor | 2 +- basis/ftp/server/server.factor | 2 +- basis/furnace/sessions/sessions-tests.factor | 2 +- basis/http/http-tests.factor | 2 +- basis/http/server/remapping/remapping.factor | 2 +- basis/http/server/server-docs.factor | 4 ++-- basis/http/server/server.factor | 2 +- basis/io/servers/{connection => }/authors.txt | 0 .../connection-docs.factor => servers-docs.factor} | 8 ++++---- .../connection-tests.factor => servers-tests.factor} | 6 +++--- .../{connection/connection.factor => servers.factor} | 2 +- basis/io/servers/{connection => }/summary.txt | 0 basis/io/servers/{connection => }/tags.txt | 0 basis/io/sockets/sockets-docs.factor | 4 ++-- basis/mime/multipart/multipart-tests.factor | 2 +- basis/tools/deploy/deploy-tests.factor | 2 +- extra/fuel/remote/remote.factor | 3 +-- extra/google-tech-talk/google-tech-talk.factor | 2 +- extra/managed-server/managed-server.factor | 2 +- extra/time-server/time-server.factor | 2 +- extra/tty-server/tty-server.factor | 3 +-- extra/webapps/site-watcher/site-watcher.factor | 2 +- extra/webapps/todo/todo.factor | 2 +- extra/websites/concatenative/concatenative.factor | 2 +- 27 files changed, 32 insertions(+), 34 deletions(-) rename basis/io/servers/{connection => }/authors.txt (100%) rename basis/io/servers/{connection/connection-docs.factor => servers-docs.factor} (94%) rename basis/io/servers/{connection/connection-tests.factor => servers-tests.factor} (89%) rename basis/io/servers/{connection/connection.factor => servers.factor} (99%) rename basis/io/servers/{connection => }/summary.txt (100%) rename basis/io/servers/{connection => }/tags.txt (100%) diff --git a/basis/channels/remote/remote-docs.factor b/basis/channels/remote/remote-docs.factor index 266d774056..2215d959a3 100644 --- a/basis/channels/remote/remote-docs.factor +++ b/basis/channels/remote/remote-docs.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2007 Chris Double. ! See http://factorcode.org/license.txt for BSD license. USING: channels concurrency.distributed help.markup help.syntax -io.servers.connection ; +io.servers ; IN: channels.remote HELP: diff --git a/basis/concurrency/distributed/distributed-tests.factor b/basis/concurrency/distributed/distributed-tests.factor index 3a6693c440..ebe5bc5da2 100644 --- a/basis/concurrency/distributed/distributed-tests.factor +++ b/basis/concurrency/distributed/distributed-tests.factor @@ -1,7 +1,7 @@ USING: tools.test concurrency.distributed kernel io.files io.files.temp io.directories arrays io.sockets system calendar combinators threads math sequences concurrency.messaging -continuations accessors prettyprint io.servers.connection ; +continuations accessors prettyprint io.servers ; FROM: concurrency.messaging => receive send ; IN: concurrency.distributed.tests @@ -36,4 +36,4 @@ test-node-server [ test-node-client "thread-a" send 100 seconds receive-timeout ] unit-test -] with-threaded-server \ No newline at end of file +] with-threaded-server diff --git a/basis/concurrency/distributed/distributed.factor b/basis/concurrency/distributed/distributed.factor index f18f5279ea..153f0c9ad6 100644 --- a/basis/concurrency/distributed/distributed.factor +++ b/basis/concurrency/distributed/distributed.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2005 Chris Double. All Rights Reserved. ! See http://factorcode.org/license.txt for BSD license. USING: serialize sequences concurrency.messaging threads io -io.servers.connection io.encodings.binary assocs init +io.servers io.encodings.binary assocs init arrays namespaces kernel accessors ; FROM: io.sockets => host-name with-client ; IN: concurrency.distributed diff --git a/basis/ftp/server/server-tests.factor b/basis/ftp/server/server-tests.factor index 2954db0f8b..fa6afa30cc 100644 --- a/basis/ftp/server/server-tests.factor +++ b/basis/ftp/server/server-tests.factor @@ -1,6 +1,6 @@ USING: calendar ftp.server io.encodings.ascii io.files io.files.unique namespaces threads tools.test kernel -io.servers.connection ftp.client accessors urls +io.servers ftp.client accessors urls io.pathnames io.directories sequences fry io.backend continuations ; FROM: ftp.client => ftp-get ; diff --git a/basis/ftp/server/server.factor b/basis/ftp/server/server.factor index e6a47c3ffd..c1508f8ad5 100644 --- a/basis/ftp/server/server.factor +++ b/basis/ftp/server/server.factor @@ -5,7 +5,7 @@ combinators.short-circuit concurrency.promises continuations destructors ftp io io.directories io.encodings io.encodings.8-bit.latin1 io.encodings.binary io.encodings.utf8 io.files io.files.info io.files.types io.pathnames -io.servers.connection io.sockets io.streams.string io.timeouts +io.servers io.sockets io.streams.string io.timeouts kernel logging math math.bitwise math.parser namespaces sequences simple-tokenizer splitting strings threads tools.files unicode.case ; diff --git a/basis/furnace/sessions/sessions-tests.factor b/basis/furnace/sessions/sessions-tests.factor index 49311ee891..1ac3dbd51a 100644 --- a/basis/furnace/sessions/sessions-tests.factor +++ b/basis/furnace/sessions/sessions-tests.factor @@ -1,6 +1,6 @@ USING: tools.test http furnace.sessions furnace.actions http.server http.server.responses math namespaces make kernel -accessors io.sockets io.servers.connection prettyprint +accessors io.sockets io.servers prettyprint io.streams.string io.files io.files.temp io.directories splitting destructors sequences db db.tuples db.sqlite continuations urls math.parser furnace furnace.utilities ; diff --git a/basis/http/http-tests.factor b/basis/http/http-tests.factor index 7be7c43399..1a74e3fc6d 100644 --- a/basis/http/http-tests.factor +++ b/basis/http/http-tests.factor @@ -205,7 +205,7 @@ Set-Cookie: oo="bar; a=b"; comment="your mom"; httponly=yes ! Live-fire exercise USING: http.server.static furnace.sessions furnace.alloy furnace.actions furnace.auth furnace.auth.login furnace.db -io.servers.connection io.files io.files.temp io.directories io +io.servers io.files io.files.temp io.directories io threads http.server.responses http.server.redirection furnace.redirection http.server.dispatchers db.tuples ; diff --git a/basis/http/server/remapping/remapping.factor b/basis/http/server/remapping/remapping.factor index 36e769731b..6eed900acc 100644 --- a/basis/http/server/remapping/remapping.factor +++ b/basis/http/server/remapping/remapping.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: namespaces assocs kernel io.servers.connection ; +USING: namespaces assocs kernel io.servers ; IN: http.server.remapping SYMBOL: port-remapping diff --git a/basis/http/server/server-docs.factor b/basis/http/server/server-docs.factor index 7e8d230971..5d1b231f60 100644 --- a/basis/http/server/server-docs.factor +++ b/basis/http/server/server-docs.factor @@ -1,5 +1,5 @@ USING: help.markup help.syntax io.streams.string quotations strings urls -http vocabs.refresh math io.servers.connection assocs ; +http vocabs.refresh math io.servers assocs ; IN: http.server HELP: trivial-responder @@ -109,7 +109,7 @@ ARTICLE: "http.server.variables" "HTTP server variables" } ; ARTICLE: "http.server" "HTTP server" -"The " { $vocab-link "http.server" } " vocabulary implements an HTTP and HTTPS server on top of " { $vocab-link "io.servers.connection" } "." +"The " { $vocab-link "http.server" } " vocabulary implements an HTTP and HTTPS server on top of " { $vocab-link "io.servers" } "." { $subsections "http.server.responders" "http.server.requests" diff --git a/basis/http/server/server.factor b/basis/http/server/server.factor index 9e4a8ac4bf..c5bc88f81f 100644 --- a/basis/http/server/server.factor +++ b/basis/http/server/server.factor @@ -15,7 +15,7 @@ io.encodings.binary io.streams.limited io.streams.string io.streams.throwing -io.servers.connection +io.servers io.timeouts io.crlf fry logging logging.insomniac calendar urls urls.encoding diff --git a/basis/io/servers/connection/authors.txt b/basis/io/servers/authors.txt similarity index 100% rename from basis/io/servers/connection/authors.txt rename to basis/io/servers/authors.txt diff --git a/basis/io/servers/connection/connection-docs.factor b/basis/io/servers/servers-docs.factor similarity index 94% rename from basis/io/servers/connection/connection-docs.factor rename to basis/io/servers/servers-docs.factor index 4dd8efdbe3..051dfad975 100644 --- a/basis/io/servers/connection/connection-docs.factor +++ b/basis/io/servers/servers-docs.factor @@ -1,6 +1,6 @@ USING: calendar classes concurrency.semaphores help.markup help.syntax io io.sockets io.sockets.secure math quotations ; -IN: io.servers.connection +IN: io.servers ARTICLE: "server-config" "Threaded server configuration" "The " { $link threaded-server } " tuple has a variety of slots which can be set before starting the server with " { $link start-server } "." @@ -52,8 +52,8 @@ $nl ARTICLE: "server-examples" "Threaded server examples" "The " { $vocab-link "time-server" } " vocabulary implements a simple threaded server which sends the current time to the client. The " { $vocab-link "concurrency.distributed" } ", " { $vocab-link "ftp.server" } ", and " { $vocab-link "http.server" } " vocabularies demonstrate more complex usage of the threaded server library." ; -ARTICLE: "io.servers.connection" "Threaded servers" -"The " { $vocab-link "io.servers.connection" } " vocabulary implements a generic server abstraction for " { $link "network-connection" } ". A set of threads listen for connections, and additional threads are spawned for each client connection. In addition to this basic functionality, it provides some advanced features such as logging, connection limits and secure socket support." +ARTICLE: "io.servers" "Threaded servers" +"The " { $vocab-link "io.servers" } " vocabulary implements a generic server abstraction for " { $link "network-connection" } ". A set of threads listen for connections, and additional threads are spawned for each client connection. In addition to this basic functionality, it provides some advanced features such as logging, connection limits and secure socket support." { $subsections "server-examples" } "Creating threaded servers with client handler quotations:" { $subsections } @@ -82,7 +82,7 @@ ARTICLE: "io.servers.connection" "Threaded servers" "Additionally, the " { $link local-address } " and " { $subsections remote-address } " variables are set, as in " { $link with-client } "." ; -ABOUT: "io.servers.connection" +ABOUT: "io.servers" HELP: threaded-server { $var-description "In client handlers, stores the current threaded server instance." } diff --git a/basis/io/servers/connection/connection-tests.factor b/basis/io/servers/servers-tests.factor similarity index 89% rename from basis/io/servers/connection/connection-tests.factor rename to basis/io/servers/servers-tests.factor index 72f4706957..bcba7f7d90 100644 --- a/basis/io/servers/connection/connection-tests.factor +++ b/basis/io/servers/servers-tests.factor @@ -1,8 +1,8 @@ USING: accessors calendar concurrency.promises fry io -io.encodings.ascii io.servers.connection -io.servers.connection.private io.sockets kernel namespaces +io.encodings.ascii io.servers +io.servers.private io.sockets kernel namespaces sequences threads tools.test ; -IN: io.servers.connection +IN: io.servers [ t ] [ ascii listen-on empty? ] unit-test diff --git a/basis/io/servers/connection/connection.factor b/basis/io/servers/servers.factor similarity index 99% rename from basis/io/servers/connection/connection.factor rename to basis/io/servers/servers.factor index 940b20f762..66d0112561 100644 --- a/basis/io/servers/connection/connection.factor +++ b/basis/io/servers/servers.factor @@ -8,7 +8,7 @@ io io.sockets io.sockets.secure io.streams.duplex io.styles io.timeouts kernel logging make math math.parser namespaces present prettyprint random sequences sets strings threads ; FROM: namespaces => set ; -IN: io.servers.connection +IN: io.servers TUPLE: threaded-server < identity-tuple name diff --git a/basis/io/servers/connection/summary.txt b/basis/io/servers/summary.txt similarity index 100% rename from basis/io/servers/connection/summary.txt rename to basis/io/servers/summary.txt diff --git a/basis/io/servers/connection/tags.txt b/basis/io/servers/tags.txt similarity index 100% rename from basis/io/servers/connection/tags.txt rename to basis/io/servers/tags.txt diff --git a/basis/io/sockets/sockets-docs.factor b/basis/io/sockets/sockets-docs.factor index d0977dd3d0..95ad57a46d 100644 --- a/basis/io/sockets/sockets-docs.factor +++ b/basis/io/sockets/sockets-docs.factor @@ -52,7 +52,7 @@ $nl { { $link inet4 } " - a TCP/IP connection to an IPv4 address and port number; no name lookup is performed" } { { $link inet6 } " - a TCP/IP connection to an IPv6 address and port number; no name lookup is performed" } } -"The " { $vocab-link "io.servers.connection" } " library defines high-level wrappers around " { $link } " which makes it easy to listen for IPv4, IPv6 and secure socket connections simultaneously, perform logging, and optionally only allow connections from the loopback interface." +"The " { $vocab-link "io.servers" } " library defines high-level wrappers around " { $link } " which makes it easy to listen for IPv4, IPv6 and secure socket connections simultaneously, perform logging, and optionally only allow connections from the loopback interface." $nl "The " { $vocab-link "io.sockets.secure" } " vocabulary implements secure, encrypted sockets via SSL and TLS." ; @@ -170,7 +170,7 @@ HELP: { $code "f 1234 resolve-host" } "To start a server which listens for connections from the loopback interface only, use an address specifier returned by the following code, where 1234 is the desired port number:" { $code "\"localhost\" 1234 resolve-host" } - "Since " { $link resolve-host } " can return multiple address specifiers, your server code must listen on them all to work properly. The " { $vocab-link "io.servers.connection" } " vocabulary can be used to help with this." + "Since " { $link resolve-host } " can return multiple address specifiers, your server code must listen on them all to work properly. The " { $vocab-link "io.servers" } " vocabulary can be used to help with this." $nl "To start a TCP/IP server which listens for connections on a randomly-assigned port, set the port number in the address specifier to 0, and then read the " { $snippet "addr" } " slot of the server instance to obtain the actual port number it is listening on:" { $unchecked-example diff --git a/basis/mime/multipart/multipart-tests.factor b/basis/mime/multipart/multipart-tests.factor index 6c3094fe22..bfeb1335ee 100644 --- a/basis/mime/multipart/multipart-tests.factor +++ b/basis/mime/multipart/multipart-tests.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs continuations fry http.server io io.encodings.ascii io.files io.files.unique -io.servers.connection io.streams.duplex io.streams.string +io.servers io.streams.duplex io.streams.string kernel math.ranges mime.multipart multiline namespaces random sequences strings threads tools.test ; IN: mime.multipart.tests diff --git a/basis/tools/deploy/deploy-tests.factor b/basis/tools/deploy/deploy-tests.factor index fa446ad44c..e8888717ab 100644 --- a/basis/tools/deploy/deploy-tests.factor +++ b/basis/tools/deploy/deploy-tests.factor @@ -52,7 +52,7 @@ os macosx? [ ] each USING: http.client http.server http.server.dispatchers -http.server.responses http.server.static io.servers.connection ; +http.server.responses http.server.static io.servers ; SINGLETON: quit-responder diff --git a/extra/fuel/remote/remote.factor b/extra/fuel/remote/remote.factor index a8007bd858..e7b797fc19 100644 --- a/extra/fuel/remote/remote.factor +++ b/extra/fuel/remote/remote.factor @@ -1,8 +1,7 @@ ! Copyright (C) 2009, 2010 Jose Antonio Ortega Ruiz. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors debugger io io.encodings.utf8 io.servers.connection +USING: accessors debugger io io.encodings.utf8 io.servers kernel listener math namespaces ; - IN: fuel.remote ( port -- ) diff --git a/extra/webapps/site-watcher/site-watcher.factor b/extra/webapps/site-watcher/site-watcher.factor index 05fabfcf9d..a354544399 100644 --- a/extra/webapps/site-watcher/site-watcher.factor +++ b/extra/webapps/site-watcher/site-watcher.factor @@ -8,7 +8,7 @@ furnace.auth.features.registration furnace.auth.login furnace.boilerplate furnace.redirection html.forms http.server http.server.dispatchers kernel namespaces site-watcher site-watcher.db site-watcher.private urls validators io.sockets.secure.unix.debug -io.servers.connection io.files.temp db db.tuples sequences +io.servers io.files.temp db db.tuples sequences webapps.site-watcher.common webapps.site-watcher.watching webapps.site-watcher.spidering ; QUALIFIED: assocs diff --git a/extra/webapps/todo/todo.factor b/extra/webapps/todo/todo.factor index e5753f3c53..01ed2402f7 100644 --- a/extra/webapps/todo/todo.factor +++ b/extra/webapps/todo/todo.factor @@ -122,7 +122,7 @@ furnace.auth.features.edit-profile furnace.auth.features.deactivate-user db.sqlite furnace.alloy -io.servers.connection +io.servers io.sockets.secure ; : ( responder -- responder' ) diff --git a/extra/websites/concatenative/concatenative.factor b/extra/websites/concatenative/concatenative.factor index 35e4150ba9..61b4f7d887 100644 --- a/extra/websites/concatenative/concatenative.factor +++ b/extra/websites/concatenative/concatenative.factor @@ -1,7 +1,7 @@ ! Copyright (c) 2008, 2010 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. USING: accessors kernel sequences assocs io.files io.pathnames -io.sockets io.sockets.secure io.servers.connection +io.sockets io.sockets.secure io.servers namespaces db db.tuples db.sqlite smtp urls logging.insomniac html.templates.chloe From e48c28359e28fbed07847429465f094cf4970bfc Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Mon, 27 Sep 2010 20:20:48 -0500 Subject: [PATCH 04/15] Fix io.streams.throwing word and write docs for it. Fix typo in io.streams.limited docs --- basis/io/streams/limited/limited-docs.factor | 2 +- .../io/streams/throwing/throwing-docs.factor | 44 +++++++++++++++++++ .../io/streams/throwing/throwing-tests.factor | 5 +-- basis/io/streams/throwing/throwing.factor | 6 +-- 4 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 basis/io/streams/throwing/throwing-docs.factor diff --git a/basis/io/streams/limited/limited-docs.factor b/basis/io/streams/limited/limited-docs.factor index 5a06dedf0d..18b4545fde 100644 --- a/basis/io/streams/limited/limited-docs.factor +++ b/basis/io/streams/limited/limited-docs.factor @@ -38,7 +38,7 @@ HELP: limited-input { $description "Wraps the current " { $link input-stream } " in a " { $link limited-stream } "." } ; ARTICLE: "io.streams.limited" "Limited input streams" -"The " { $vocab-link "io.streams.limited" } " vocabulary wraps a stream to behave as if it had only a limited number of bytes, either throwing an error or returning " { $link f } " upon reaching the end. Limiting a non-seekable stream keeps a byte count and triggers the end-of-stream behavior when this byte count has been reached. However, limiting a seekable stream creates a window of bytes that supports seeking and re-reading of bytes in that window." $nl +"The " { $vocab-link "io.streams.limited" } " vocabulary wraps a stream to behave as if it had only a limited number of bytes. Limiting a seekable stream creates a window of bytes that supports seeking and re-reading of bytes in that window. If it is desirable for a stream to throw an exception upon exhaustion, use the " { $vocab-link "io.streams.throwing" } " vocabulary in conjunction with this one." $nl "Wrap a stream in a limited stream:" { $subsections limited-stream } "Wrap the current " { $link input-stream } " in a limited stream:" diff --git a/basis/io/streams/throwing/throwing-docs.factor b/basis/io/streams/throwing/throwing-docs.factor new file mode 100644 index 0000000000..14ceb6c790 --- /dev/null +++ b/basis/io/streams/throwing/throwing-docs.factor @@ -0,0 +1,44 @@ +! Copyright (C) 2010 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax io kernel quotations words +math ; +IN: io.streams.throwing + +HELP: stream-exhausted +{ $values + { "n" integer } { "stream" "an input stream" } { "word" word } +} +{ $description "The exception that gets thrown when a stream is exhausted." } ; + +HELP: stream-throw-on-eof +{ $values + { "stream" "an input stream" } { "quot" quotation } +} +{ $description "Wraps a stream in a " { $link } " tuple and calls the quotation with this stream as the " { $link input-stream } " variable. Causes a " { $link stream-exhausted } " exception to be thrown upon stream exhaustion. The stream is left open after this combinator returns." } +"This example will throw a " { $link stream-exhausted } " exception:" +{ $unchecked-example """USING: io.streams.throwing prettyprint ; +"abc" [ 4 read ] stream-throw-on-eof""" +"" +} ; + +HELP: throw-on-eof +{ $values + { "quot" quotation } +} +{ $description "Wraps the value stored in the " { $link input-stream } " variable and causes a stream read that exhausts the input stream to throw a " { $link stream-exhausted } " exception. The stream is left open after this combinator returns." } $nl +"This example will throw a " { $link stream-exhausted } " exception:" +{ $unchecked-example """USING: io.streams.throwing prettyprint ; +"abc" [ [ 4 read ] throw-on-eof ] with-string-reader""" +"" +} ; + +ARTICLE: "io.streams.throwing" "Throwing exceptions on stream exhaustion" +"The " { $vocab-link "io.streams.throwing" } " vocabulary implements combinators for changing the behavior of a stream to throw an exception upon exhaustion instead of returning " { $link f } "." $nl +"A general combinator to wrap any stream:" +{ $subsections stream-throw-on-eof } +"A combinator for the " { $link input-stream } " variable:" +{ $subsections throw-on-eof } +"The exception itself:" +{ $subsections stream-exhausted } ; + +ABOUT: "io.streams.throwing" diff --git a/basis/io/streams/throwing/throwing-tests.factor b/basis/io/streams/throwing/throwing-tests.factor index 1c9e32914b..f1567be842 100644 --- a/basis/io/streams/throwing/throwing-tests.factor +++ b/basis/io/streams/throwing/throwing-tests.factor @@ -15,9 +15,8 @@ IN: io.streams.throwing.tests [ [ - "asdf" &dispose [ - [ 4 swap stream-read ] - [ stream-read1 ] bi + "asdf" [ + 4 read read1 ] stream-throw-on-eof ] with-destructors ] [ stream-exhausted? ] must-fail-with diff --git a/basis/io/streams/throwing/throwing.factor b/basis/io/streams/throwing/throwing.factor index f2cdeab4f7..0b1f214d07 100644 --- a/basis/io/streams/throwing/throwing.factor +++ b/basis/io/streams/throwing/throwing.factor @@ -6,12 +6,12 @@ IN: io.streams.throwing ERROR: stream-exhausted n stream word ; - throws-on-eof-stream +> stream-element-type ; M: throws-on-eof-stream dispose stream>> dispose ; @@ -41,7 +41,7 @@ M: throws-on-eof-stream stream-read-until PRIVATE> : stream-throw-on-eof ( ..a stream quot: ( ..a stream' -- ..b ) -- ..b ) - [ ] dip call ; inline + [ ] dip with-input-stream* ; inline : throw-on-eof ( ..a quot: ( ..a -- ..b ) -- ..b ) [ input-stream get ] dip with-input-stream* ; inline From 53aed0805aae562fe36f369fcb8f7000e4ba4cb6 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 26 Sep 2010 21:16:50 -0700 Subject: [PATCH 05/15] compiler.cfg.alias-analysis: fix bug in lazy alias class instantiation --- basis/compiler/cfg/alias-analysis/alias-analysis.factor | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/basis/compiler/cfg/alias-analysis/alias-analysis.factor b/basis/compiler/cfg/alias-analysis/alias-analysis.factor index 775bf65fe5..697a9dfcdd 100644 --- a/basis/compiler/cfg/alias-analysis/alias-analysis.factor +++ b/basis/compiler/cfg/alias-analysis/alias-analysis.factor @@ -14,7 +14,8 @@ compiler.cfg.representations.preferred ; FROM: namespaces => set ; IN: compiler.cfg.alias-analysis -! We try to eliminate redundant slot operations using some simple heuristics. +! We try to eliminate redundant slot operations using some +! simple heuristics. ! ! All heap-allocated objects which are loaded from the stack, or ! other object slots are pessimistically assumed to belong to @@ -108,7 +109,7 @@ SYMBOL: heap-ac 2dup eq? [ 2drop ] [ [ ac>vregs ] dip [ vregs>acs get '[ [ _ ] dip _ set-at ] each ] - [ acs>vregs get at push-all ] + [ ac>vregs push-all ] 2bi ] if ; @@ -129,7 +130,7 @@ ERROR: vreg-not-new vreg ; #! Set alias class of newly-seen vreg. vreg vregs>acs get key? [ vreg vreg-not-new ] when ac vreg vregs>acs get set-at - vreg ac acs>vregs get push-at ; + vreg ac ac>vregs push ; : live-slot ( slot#/f vreg -- vreg' ) #! If the slot number is unknown, we never reuse a previous From 6b5fffc026f7e4a9b76de439655231750f3ec293 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 26 Sep 2010 22:20:50 -0700 Subject: [PATCH 06/15] compiler: preliminary implementation of tracking derived pointers in GC maps --- .../cfg/instructions/instructions.factor | 16 ++- .../linear-scan/assignment/assignment.factor | 8 +- .../cfg/liveness/liveness-tests.factor | 41 +++++++- basis/compiler/cfg/liveness/liveness.factor | 98 +++++++++++++++---- .../compiler/codegen/fixup/fixup-tests.factor | 11 ++- basis/compiler/codegen/fixup/fixup.factor | 62 +++++++++--- basis/compiler/tests/alien.factor | 22 ----- basis/compiler/tests/codegen.factor | 58 +++++++++-- basis/cpu/architecture/architecture.factor | 2 +- basis/cpu/x86/x86.factor | 4 +- vm/contexts.cpp | 6 +- vm/gc_info.cpp | 6 +- vm/gc_info.hpp | 40 +++++--- vm/slot_visitor.hpp | 39 ++++++-- vm/vm.hpp | 10 +- 15 files changed, 315 insertions(+), 108 deletions(-) diff --git a/basis/compiler/cfg/instructions/instructions.factor b/basis/compiler/cfg/instructions/instructions.factor index c51d41443a..210489f8b0 100644 --- a/basis/compiler/cfg/instructions/instructions.factor +++ b/basis/compiler/cfg/instructions/instructions.factor @@ -830,13 +830,16 @@ UNION: conditional-branch-insn UNION: ##read ##slot ##slot-imm ##vm-field ##alien-global ; UNION: ##write ##set-slot ##set-slot-imm ##set-vm-field ; -! Instructions that contain subroutine calls to functions which -! can callback arbitrary Factor code -UNION: factor-call-insn +UNION: alien-call-insn ##alien-invoke ##alien-indirect ##alien-assembly ; +! Instructions that contain subroutine calls to functions which +! can callback arbitrary Factor code +UNION: factor-call-insn +alien-call-insn ; + ! Instructions that contain subroutine calls to functions which ! allocate memory UNION: gc-map-insn @@ -848,15 +851,10 @@ factor-call-insn ; M: gc-map-insn clone call-next-method [ clone ] change-gc-map ; ! Each one has a gc-map slot -TUPLE: gc-map scrub-d scrub-r gc-roots ; +TUPLE: gc-map scrub-d scrub-r gc-roots derived-roots ; : ( -- gc-map ) gc-map new ; -UNION: alien-call-insn -##alien-invoke -##alien-indirect -##alien-assembly ; - ! Instructions that clobber registers. They receive inputs and ! produce outputs in spill slots. UNION: hairy-clobber-insn diff --git a/basis/compiler/cfg/linear-scan/assignment/assignment.factor b/basis/compiler/cfg/linear-scan/assignment/assignment.factor index 9a66307a93..96235b6807 100644 --- a/basis/compiler/cfg/linear-scan/assignment/assignment.factor +++ b/basis/compiler/cfg/linear-scan/assignment/assignment.factor @@ -146,9 +146,15 @@ RENAMING: assign [ vreg>reg ] [ vreg>reg ] [ vreg>reg ] M: vreg-insn assign-registers-in-insn [ assign-insn-defs ] [ assign-insn-uses ] [ assign-insn-temps ] tri ; +: assign-gc-roots ( gc-map -- ) + [ [ vreg>spill-slot ] map ] change-gc-roots drop ; + +: assign-derived-roots ( gc-map -- ) + [ [ [ vreg>spill-slot ] bi@ ] assoc-map ] change-derived-roots drop ; + M: gc-map-insn assign-registers-in-insn [ [ assign-insn-defs ] [ assign-insn-uses ] [ assign-insn-temps ] tri ] - [ gc-map>> [ [ vreg>spill-slot ] map ] change-gc-roots drop ] + [ gc-map>> [ assign-gc-roots ] [ assign-derived-roots ] bi ] bi ; M: insn assign-registers-in-insn drop ; diff --git a/basis/compiler/cfg/liveness/liveness-tests.factor b/basis/compiler/cfg/liveness/liveness-tests.factor index a6bd82183a..ba870fbc75 100644 --- a/basis/compiler/cfg/liveness/liveness-tests.factor +++ b/basis/compiler/cfg/liveness/liveness-tests.factor @@ -205,4 +205,43 @@ V{ [ H{ { 0 0 } } ] [ 2 get 4 get edge-live-in ] unit-test -[ H{ { 1 1 } } ] [ 3 get 4 get edge-live-in ] unit-test \ No newline at end of file +[ H{ { 1 1 } } ] [ 3 get 4 get edge-live-in ] unit-test + + +V{ + T{ ##prologue } + T{ ##branch } +} 0 test-bb + +V{ + T{ ##peek f 0 D 0 } + T{ ##tagged>integer f 1 0 } + T{ ##call-gc f T{ gc-map } } + T{ ##replace f 0 D 0 } + T{ ##call-gc f T{ gc-map } } + T{ ##replace f 1 D 0 } + T{ ##branch } +} 1 test-bb + +V{ + T{ ##epilogue } + T{ ##return } +} 2 test-bb + +0 1 edge +1 2 edge + +H{ + { 0 tagged-rep } + { 1 int-rep } +} representations set + +[ ] [ cfg new 0 get >>entry dup cfg set compute-live-sets ] unit-test + +[ V{ { 1 0 } } ] [ 1 get instructions>> 2 swap nth gc-map>> derived-roots>> ] unit-test + +[ { 0 } ] [ 1 get instructions>> 2 swap nth gc-map>> gc-roots>> ] unit-test + +[ V{ { 1 0 } } ] [ 1 get instructions>> 4 swap nth gc-map>> derived-roots>> ] unit-test + +[ { 0 } ] [ 1 get instructions>> 4 swap nth gc-map>> gc-roots>> ] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/liveness/liveness.factor b/basis/compiler/cfg/liveness/liveness.factor index 25d78a8d8f..772e4f390f 100644 --- a/basis/compiler/cfg/liveness/liveness.factor +++ b/basis/compiler/cfg/liveness/liveness.factor @@ -1,15 +1,28 @@ ! Copyright (C) 2009, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel accessors assocs fry deques dlists namespaces -sequences sets compiler.cfg compiler.cfg.def-use -compiler.cfg.instructions compiler.cfg.registers -compiler.cfg.utilities compiler.cfg.predecessors -compiler.cfg.rpo cpu.architecture ; +USING: arrays kernel accessors assocs fry locals combinators +deques dlists namespaces sequences sets compiler.cfg +compiler.cfg.def-use compiler.cfg.instructions +compiler.cfg.registers compiler.cfg.utilities +compiler.cfg.predecessors compiler.cfg.rpo cpu.architecture ; FROM: namespaces => set ; IN: compiler.cfg.liveness -! See http://en.wikipedia.org/wiki/Liveness_analysis +! Similar to http://en.wikipedia.org/wiki/Liveness_analysis, +! with three additions: +! 1) With SSA, it is not sufficient to have a single live-in set +! per block. There is also there is an edge-live-in set per +! edge, consisting of phi inputs from each predecessor. +! 2) Liveness analysis annotates call sites with GC maps +! indicating the spill slots in the stack frame that contain +! tagged pointers, and thus have to be visited if a GC occurs +! inside the call. +! 3) GC maps can contain derived pointers. A derived pointer is +! a pointer into the middle of a data heap object. Each derived +! pointer has a base pointer, to keep it up to date when objects +! are moved by the garbage collector. This extends live +! intervals and inserts new ##phi instructions. SYMBOL: live-ins : live-in ( bb -- set ) @@ -27,6 +40,8 @@ SYMBOL: edge-live-ins : edge-live-in ( predecessor basic-block -- set ) edge-live-ins get at at ; +SYMBOL: base-pointers + GENERIC: visit-insn ( live-set insn -- live-set ) : kill-defs ( live-set insn -- live-set ) @@ -35,20 +50,64 @@ GENERIC: visit-insn ( live-set insn -- live-set ) : gen-uses ( live-set insn -- live-set ) uses-vregs [ over conjoin ] each ; inline -M: vreg-insn visit-insn [ kill-defs ] [ gen-uses ] bi ; +M: vreg-insn visit-insn + [ kill-defs ] [ gen-uses ] bi ; -! Our liveness analysis annotates call sites with GC maps -! indicating the spill slots in the stack frame that contain -! tagged pointers, and thus have to be visited if a GC occurs -! inside the call. +DEFER: lookup-base-pointer + +GENERIC: lookup-base-pointer* ( insn -- vreg/f ) + +M: ##tagged>integer lookup-base-pointer* src>> ; + +M: ##unbox-any-c-ptr lookup-base-pointer* + ! If the input to unbox-any-c-ptr was an alien and not a + ! byte array, then the derived pointer will be outside of + ! the data heap. The GC has to handle this case and ignore + ! it. + src>> ; + +M: ##copy lookup-base-pointer* src>> lookup-base-pointer ; + +M: ##add-imm lookup-base-pointer* src1>> lookup-base-pointer ; + +M: ##sub-imm lookup-base-pointer* src1>> lookup-base-pointer ; + +M: ##add lookup-base-pointer* + ! If both operands have a base pointer, then the user better + ! not be doing memory reads and writes on the object, since + ! we don't give it a base pointer in that case at all. + [ src1>> ] [ src2>> ] bi [ lookup-base-pointer ] bi@ xor ; + +M: ##sub lookup-base-pointer* + src1>> lookup-base-pointer ; + +M: vreg-insn lookup-base-pointer* drop f ; + +: lookup-base-pointer ( vreg -- vreg/f ) + base-pointers get [ insn-of lookup-base-pointer* ] cache ; + +:: visit-derived-root ( vreg derived-roots gc-roots -- ) + vreg lookup-base-pointer :> base + base [ + { vreg base } derived-roots push + base gc-roots adjoin + ] when ; + +: visit-gc-root ( vreg derived-roots gc-roots -- ) + pick rep-of { + { tagged-rep [ nip adjoin ] } + { int-rep [ visit-derived-root ] } + [ 2drop 2drop ] + } case ; + +: gc-roots ( live-set -- derived-roots gc-roots ) + V{ } clone HS{ } clone + [ '[ drop _ _ visit-gc-root ] assoc-each ] 2keep + members ; : fill-gc-map ( live-set insn -- live-set ) - representations get [ - gc-map>> over keys - [ rep-of tagged-rep? ] filter - >>gc-roots - ] when - drop ; + [ representations get [ dup gc-roots ] [ f f ] if ] dip + gc-map>> [ gc-roots<< ] [ derived-roots<< ] bi ; M: gc-map-insn visit-insn [ kill-defs ] [ fill-gc-map ] [ gen-uses ] tri ; @@ -60,9 +119,6 @@ M: insn visit-insn drop ; : transfer-liveness ( live-set instructions -- live-set' ) [ clone ] [ ] bi* [ visit-insn ] each ; -: local-live-in ( instructions -- live-set ) - [ H{ } ] dip transfer-liveness keys ; - SYMBOL: work-list : add-to-work-list ( basic-blocks -- ) @@ -98,11 +154,13 @@ SYMBOL: work-list : compute-live-sets ( cfg -- ) needs-predecessors + dup compute-insns work-list set H{ } clone live-ins set H{ } clone edge-live-ins set H{ } clone live-outs set + H{ } clone base-pointers set post-order add-to-work-list work-list get [ liveness-step ] slurp-deque ; diff --git a/basis/compiler/codegen/fixup/fixup-tests.factor b/basis/compiler/codegen/fixup/fixup-tests.factor index f068861126..70dcdf8988 100644 --- a/basis/compiler/codegen/fixup/fixup-tests.factor +++ b/basis/compiler/codegen/fixup/fixup-tests.factor @@ -9,13 +9,14 @@ STRUCT: gc-info { scrub-d-count uint } { scrub-r-count uint } { gc-root-count uint } +{ derived-root-count uint } { return-address-count uint } ; SINGLETON: fake-cpu fake-cpu \ cpu set -M: fake-cpu gc-root-offsets ; +M: fake-cpu gc-root-offset ; [ ] [ [ @@ -27,7 +28,7 @@ M: fake-cpu gc-root-offsets ; 50 % - T{ gc-map f B{ 0 1 1 1 0 } B{ 1 0 } V{ 1 3 } } gc-map-here + T{ gc-map f B{ 0 1 1 1 0 } B{ 1 0 } V{ 1 3 } V{ { 2 4 } } } gc-map-here emit-gc-info ] B{ } make @@ -54,7 +55,10 @@ M: fake-cpu gc-root-offsets ; f t f t } underlying>> % - ! Return addresses - 4 bytes + ! Derived pointers + uint-array{ -1 -1 4 } underlying>> % + + ! Return addresses uint-array{ 100 } underlying>> % ! GC info footer - 16 bytes @@ -62,6 +66,7 @@ M: fake-cpu gc-root-offsets ; { scrub-d-count 5 } { scrub-r-count 2 } { gc-root-count 4 } + { derived-root-count 3 } { return-address-count 1 } } (underlying)>> % ] B{ } make diff --git a/basis/compiler/codegen/fixup/fixup.factor b/basis/compiler/codegen/fixup/fixup.factor index b4ef317b67..7df85c390d 100644 --- a/basis/compiler/codegen/fixup/fixup.factor +++ b/basis/compiler/codegen/fixup/fixup.factor @@ -2,8 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: arrays bit-arrays byte-arrays byte-vectors generic assocs hashtables io.binary kernel kernel.private math namespaces make -sequences words quotations strings alien.accessors alien.strings -layouts system combinators math.bitwise math.order +sequences words quotations strings sorting alien.accessors +alien.strings layouts system combinators math.bitwise math.order combinators.short-circuit combinators.smart accessors growable fry memoize compiler.constants compiler.cfg.instructions cpu.architecture ; @@ -144,12 +144,14 @@ MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ; ! - ! - ! - +! uint[] ! uint[] ! uint ! uint ! uint -! uint - +! uint +! int +! SYMBOLS: return-addresses gc-maps ; : gc-map-needed? ( gc-map -- ? ) @@ -160,6 +162,7 @@ SYMBOLS: return-addresses gc-maps ; [ scrub-d>> empty? ] [ scrub-r>> empty? ] [ gc-roots>> empty? ] + [ derived-roots>> empty? ] } 1&& not ] when ; @@ -169,33 +172,64 @@ SYMBOLS: return-addresses gc-maps ; compiled-offset return-addresses get push ] [ drop ] if ; +: longest ( seqs -- n ) + [ length ] [ max ] map-reduce ; + : emit-scrub ( seqs -- n ) ! seqs is a sequence of sequences of 0/1 - dup [ length ] [ max ] map-reduce + dup longest [ '[ [ 0 = ] ?{ } map-as _ f pad-tail % ] each ] keep ; : integers>bits ( seq n -- bit-array ) [ '[ [ t ] dip _ set-nth ] each ] keep ; +: largest-spill-slot ( seqs -- n ) + [ [ 0 ] [ supremum 1 + ] if-empty ] [ max ] map-reduce ; + : emit-gc-roots ( seqs -- n ) ! seqs is a sequence of sequences of integers 0..n-1 - dup [ [ 0 ] [ supremum 1 + ] if-empty ] [ max ] map-reduce + dup largest-spill-slot [ '[ _ integers>bits % ] each ] keep ; : emit-uint ( n -- ) building get push-uint ; +: emit-uints ( n -- ) + [ emit-uint ] each ; + +: gc-root-offsets ( gc-map -- offsets ) + gc-roots>> [ gc-root-offset ] map ; + +: emit-gc-info-bitmaps ( -- scrub-d-count scrub-r-count gc-root-count ) + [ + gc-maps get { + [ [ scrub-d>> ] map emit-scrub ] + [ [ scrub-r>> ] map emit-scrub ] + [ [ gc-root-offsets ] map emit-gc-roots ] + } cleave + ] ?{ } make underlying>> % ; + +: emit-base-table ( alist longest -- ) + -1 swap assoc-union! seq>> emit-uints ; + +: derived-root-offsets ( gc-map -- offsets ) + derived-roots>> [ [ gc-root-offset ] bi@ ] assoc-map ; + +: emit-base-tables ( -- count ) + gc-maps get [ derived-root-offsets ] map + dup [ keys ] map largest-spill-slot + [ '[ _ emit-base-table ] each ] keep ; + +: emit-return-addresses ( -- ) + return-addresses get emit-uints ; + : gc-info ( -- byte-array ) [ return-addresses get empty? [ 0 emit-uint ] [ - gc-maps get - [ - [ [ scrub-d>> ] map emit-scrub ] - [ [ scrub-r>> ] map emit-scrub ] - [ [ gc-roots>> gc-root-offsets ] map emit-gc-roots ] tri - ] ?{ } make underlying>> % - return-addresses get [ emit-uint ] each - [ emit-uint ] tri@ + emit-gc-info-bitmaps + emit-base-tables + emit-return-addresses + 4array emit-uints return-addresses get length emit-uint ] if ] B{ } make ; diff --git a/basis/compiler/tests/alien.factor b/basis/compiler/tests/alien.factor index 65e67e66d2..60e132bb76 100755 --- a/basis/compiler/tests/alien.factor +++ b/basis/compiler/tests/alien.factor @@ -823,25 +823,3 @@ TUPLE: some-tuple x ; aa-indirect-1 >>x ] compile-call ] unit-test - -! Write barrier elimination was being done before scheduling and -! GC check insertion, and didn't take subroutine calls into -! account. Oops... -: write-barrier-elim-in-wrong-place ( -- obj ) - ! A callback used below - void { } cdecl [ compact-gc ] alien-callback - ! Allocate an object A in the nursery - 1 f - ! Subroutine call promotes the object to tenured - swap void { } cdecl alien-indirect - ! Allocate another object B in the nursery, store it into - ! the first - 1 f over set-first - ! Now object A's card should be marked and minor GC should - ! promote B to aging - minor-gc - ! Do stuff - [ 100 [ ] times ] infer. - ; - -[ { { f } } ] [ write-barrier-elim-in-wrong-place ] unit-test diff --git a/basis/compiler/tests/codegen.factor b/basis/compiler/tests/codegen.factor index e9127f71e4..4c4e8de94d 100644 --- a/basis/compiler/tests/codegen.factor +++ b/basis/compiler/tests/codegen.factor @@ -4,7 +4,8 @@ sequences tools.test namespaces.private slots.private sequences.private byte-arrays alien alien.accessors layouts words definitions compiler.units io combinators vectors grouping make alien.c-types combinators.short-circuit math.order -math.libm math.parser math.functions alien.syntax ; +math.libm math.parser math.functions alien.syntax memory +stack-checker ; FROM: math => float ; QUALIFIED: namespaces.private IN: compiler.tests.codegen @@ -463,6 +464,13 @@ TUPLE: myseq { underlying1 byte-array read-only } { underlying2 byte-array read- [ [ HEX: f bitand ] bi@ [ shift ] [ drop -3 shift ] 2bi ] compile-call ] unit-test +! Alias analysis bug +[ t ] [ + [ + 10 10 [ underlying>> ] keep eq? + ] compile-call +] unit-test + ! GC root offsets were computed wrong on x86 : gc-root-messup ( a -- b ) dup [ @@ -473,9 +481,45 @@ TUPLE: myseq { underlying1 byte-array read-only } { underlying2 byte-array read- [ ] [ 2000 [ "hello" clone dup gc-root-messup first eq? t assert= ] times ] unit-test -! Alias analysis bug -[ t ] [ - [ - 10 10 [ underlying>> ] keep eq? - ] compile-call -] unit-test +! Write barrier elimination was being done before scheduling and +! GC check insertion, and didn't take subroutine calls into +! account. Oops... +: write-barrier-elim-in-wrong-place ( -- obj ) + ! A callback used below + void { } cdecl [ compact-gc ] alien-callback + ! Allocate an object A in the nursery + 1 f + ! Subroutine call promotes the object to tenured + swap void { } cdecl alien-indirect + ! Allocate another object B in the nursery, store it into + ! the first + 1 f over set-first + ! Now object A's card should be marked and minor GC should + ! promote B to aging + minor-gc + ! Do stuff + [ 100 [ ] times ] infer. + ; + +[ { { f } } ] [ write-barrier-elim-in-wrong-place ] unit-test + +! GC maps must support derived pointers +: (derived-pointer-test-1) ( -- byte-array ) + 2 ; + +: derived-pointer-test-1 ( -- byte-array ) + ! A callback used below + void { } cdecl [ compact-gc ] alien-callback + ! Put the construction in a word since instruction selection + ! eliminates the untagged pointer entirely if the value is a + ! byte array + (derived-pointer-test-1) { c-ptr } declare + ! Store into an array, an untagged pointer to the payload + ! is now an available expression + 123 over 0 set-alien-unsigned-1 + ! GC, moving the array and derived pointer + swap void { } cdecl alien-indirect + ! Store into the array again + 231 over 1 set-alien-unsigned-1 ; + +[ B{ 123 231 } ] [ derived-pointer-test-1 ] unit-test diff --git a/basis/cpu/architecture/architecture.factor b/basis/cpu/architecture/architecture.factor index 4f6e2677f3..3f2100b787 100644 --- a/basis/cpu/architecture/architecture.factor +++ b/basis/cpu/architecture/architecture.factor @@ -225,7 +225,7 @@ M: object vm-stack-space 0 ; ! %store-memory work HOOK: complex-addressing? cpu ( -- ? ) -HOOK: gc-root-offsets cpu ( seq -- seq' ) +HOOK: gc-root-offset cpu ( spill-slot -- n ) HOOK: %load-immediate cpu ( reg val -- ) HOOK: %load-reference cpu ( reg obj -- ) diff --git a/basis/cpu/x86/x86.factor b/basis/cpu/x86/x86.factor index a13b44197d..6f72e44b9a 100644 --- a/basis/cpu/x86/x86.factor +++ b/basis/cpu/x86/x86.factor @@ -503,8 +503,8 @@ M:: x86 %check-nursery-branch ( label size cc temp1 temp2 -- ) { cc/<= [ label JG ] } } case ; -M: x86 gc-root-offsets - [ n>> spill-offset special-offset cell + cell /i ] map f like ; +M: x86 gc-root-offset + n>> spill-offset special-offset cell + cell /i ; M: x86 %call-gc ( gc-map -- ) \ minor-gc %call diff --git a/vm/contexts.cpp b/vm/contexts.cpp index 3d3008c2ab..099a320cfd 100644 --- a/vm/contexts.cpp +++ b/vm/contexts.cpp @@ -60,9 +60,9 @@ void context::scrub_stacks(gc_info *info, cell index) u8 *bitmap = info->gc_info_bitmap(); { - cell base = info->scrub_d_base(index); + cell base = info->callsite_scrub_d(index); - for(int loc = 0; loc < info->scrub_d_count; loc++) + for(cell loc = 0; loc < info->scrub_d_count; loc++) { if(bitmap_p(bitmap,base + loc)) { @@ -75,7 +75,7 @@ void context::scrub_stacks(gc_info *info, cell index) } { - cell base = info->scrub_r_base(index); + cell base = info->callsite_scrub_r(index); for(int loc = 0; loc < info->scrub_r_count; loc++) { diff --git a/vm/gc_info.cpp b/vm/gc_info.cpp index 9a3252aa2c..7c727aac0d 100644 --- a/vm/gc_info.cpp +++ b/vm/gc_info.cpp @@ -3,17 +3,17 @@ namespace factor { -int gc_info::return_address_index(cell return_address) +cell gc_info::return_address_index(cell return_address) { u32 *return_address_array = return_addresses(); - for(int i = 0; i < return_address_count; i++) + for(cell i = 0; i < return_address_count; i++) { if(return_address == return_address_array[i]) return i; } - return -1; + return gc_info_missing_value; } } diff --git a/vm/gc_info.hpp b/vm/gc_info.hpp index dbbe11b9d7..eee7b1a8e8 100644 --- a/vm/gc_info.hpp +++ b/vm/gc_info.hpp @@ -1,15 +1,23 @@ namespace factor { +const u32 gc_info_missing_value = (u32)-1; + struct gc_info { - int scrub_d_count; - int scrub_r_count; - int gc_root_count; - int return_address_count; + u32 scrub_d_count; + u32 scrub_r_count; + u32 gc_root_count; + u32 derived_root_count; + u32 return_address_count; + + cell callsite_bitmap_size() + { + return scrub_d_count + scrub_r_count + gc_root_count; + } cell total_bitmap_size() { - return return_address_count * (scrub_d_count + scrub_r_count + gc_root_count); + return return_address_count * callsite_bitmap_size(); } cell total_bitmap_bytes() @@ -19,33 +27,43 @@ struct gc_info { u32 *return_addresses() { - return (u32 *)((u8 *)this - return_address_count * sizeof(u32)); + return (u32 *)this - return_address_count; + } + + u32 *base_pointer_map() + { + return return_addresses() - return_address_count * derived_root_count; } u8 *gc_info_bitmap() { - return (u8 *)return_addresses() - total_bitmap_bytes(); + return (u8 *)base_pointer_map() - total_bitmap_bytes(); } - cell scrub_d_base(cell index) + cell callsite_scrub_d(cell index) { return index * scrub_d_count; } - cell scrub_r_base(cell index) + cell callsite_scrub_r(cell index) { return return_address_count * scrub_d_count + index * scrub_r_count; } - cell spill_slot_base(cell index) + cell callsite_gc_roots(cell index) { return return_address_count * scrub_d_count + return_address_count * scrub_r_count + index * gc_root_count; } - int return_address_index(cell return_address); + cell lookup_base_pointer(cell index, cell derived_root) + { + return base_pointer_map()[index * derived_root_count + derived_root]; + } + + cell return_address_index(cell return_address); }; } diff --git a/vm/slot_visitor.hpp b/vm/slot_visitor.hpp index d4479ee102..303fc37544 100755 --- a/vm/slot_visitor.hpp +++ b/vm/slot_visitor.hpp @@ -292,27 +292,52 @@ struct call_frame_slot_visitor { gc_info *info = compiled->block_gc_info(); assert(return_address < compiled->size()); - int index = info->return_address_index(return_address); - if(index == -1) + u32 callsite = info->return_address_index(return_address); + if(callsite == gc_info_missing_value) return; #ifdef DEBUG_GC_MAPS std::cout << "call frame code block " << compiled << " with offset " << return_address << std::endl; #endif - u8 *bitmap = info->gc_info_bitmap(); - cell base = info->spill_slot_base(index); cell *stack_pointer = (cell *)(parent->frame_successor(frame) + 1); + u8 *bitmap = info->gc_info_bitmap(); - for(int spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) + /* Subtract old value of base pointer from every derived pointer. */ + for(cell spill_slot = 0; spill_slot < info->derived_root_count; spill_slot++) { - if(bitmap_p(bitmap,base + spill_slot)) + cell base_pointer = info->lookup_base_pointer(callsite, spill_slot); + if(base_pointer != gc_info_missing_value) { #ifdef DEBUG_GC_MAPS - std::cout << "visiting spill slot " << spill_slot << std::endl; + std::cout << "visiting derived root " << spill_slot + << " with base pointer " << base_pointer + << std::endl; +#endif + stack_pointer[spill_slot] -= stack_pointer[base_pointer]; + } + } + + /* Update all GC roots, including base pointers. */ + cell callsite_gc_roots = info->callsite_gc_roots(callsite); + + for(cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) + { + if(bitmap_p(bitmap,callsite_gc_roots + spill_slot)) + { +#ifdef DEBUG_GC_MAPS + std::cout << "visiting GC root " << spill_slot << std::endl; #endif visitor->visit_handle(stack_pointer + spill_slot); } } + + /* Add the base pointers to obtain new derived pointer values. */ + for(cell spill_slot = 0; spill_slot < info->derived_root_count; spill_slot++) + { + cell base_pointer = info->lookup_base_pointer(callsite, spill_slot); + if(base_pointer != gc_info_missing_value) + stack_pointer[spill_slot] += stack_pointer[base_pointer]; + } } }; diff --git a/vm/vm.hpp b/vm/vm.hpp index d9c7186c4e..f940bd5937 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -329,14 +329,16 @@ struct factor_vm return (Type *)allot_object(Type::type_number,size); } + inline bool in_data_heap_p(cell pointer) + { + return (pointer >= data->seg->start && pointer < data->seg->end); + } + inline void check_data_pointer(object *pointer) { #ifdef FACTOR_DEBUG if(!(current_gc && current_gc->op == collect_growing_heap_op)) - { - assert((cell)pointer >= data->seg->start - && (cell)pointer < data->seg->end); - } + assert(in_data_heap_p((cell)pointer)); #endif } From 6f7b58f6c910c624a3863b717dbbc8bd7b487d52 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 26 Sep 2010 22:47:55 -0700 Subject: [PATCH 07/15] mason.release.branch: fix test failure --- extra/mason/release/branch/branch-tests.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/mason/release/branch/branch-tests.factor b/extra/mason/release/branch/branch-tests.factor index 463f8b13c1..8327ae985d 100644 --- a/extra/mason/release/branch/branch-tests.factor +++ b/extra/mason/release/branch/branch-tests.factor @@ -1,7 +1,7 @@ IN: mason.release.branch.tests USING: mason.release.branch mason.config tools.test namespaces ; -[ { "git" "push" "joe@blah.com:/my/git" "master:clean-linux-x86-32" } ] [ +[ { "git" "push" "-f" "joe@blah.com:/my/git" "master:clean-linux-x86-32" } ] [ [ "joe" branch-username set "blah.com" branch-host set From 7d6475df0b9bcd4a8954e9def6c995aef2af0200 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 27 Sep 2010 20:29:09 -0700 Subject: [PATCH 08/15] New boot image location: http://downloads.factorcode.org/images/ --- basis/bootstrap/image/download/download.factor | 2 +- basis/bootstrap/image/upload/upload.factor | 2 +- build-support/factor.cmd | 2 +- build-support/factor.sh | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/basis/bootstrap/image/download/download.factor b/basis/bootstrap/image/download/download.factor index eeaccd9347..15a0e679c5 100644 --- a/basis/bootstrap/image/download/download.factor +++ b/basis/bootstrap/image/download/download.factor @@ -4,7 +4,7 @@ USING: http.client checksums checksums.md5 splitting assocs kernel io.files bootstrap.image sequences io urls ; IN: bootstrap.image.download -CONSTANT: url URL" http://factorcode.org/images/latest/" +CONSTANT: url URL" http://downloads.factorcode.org/images/latest/" : download-checksums ( -- alist ) url "checksums.txt" >url derive-url http-get nip diff --git a/basis/bootstrap/image/upload/upload.factor b/basis/bootstrap/image/upload/upload.factor index 7f25ce9c01..29f84c8151 100644 --- a/basis/bootstrap/image/upload/upload.factor +++ b/basis/bootstrap/image/upload/upload.factor @@ -10,7 +10,7 @@ SYMBOL: upload-images-destination : destination ( -- dest ) upload-images-destination get - "slava@factorcode.org:/var/www/factorcode.org/newsite/images/latest/" + "slava_pestov@downloads.factorcode.org:downloads.factorcode.org/images/latest/" or ; : checksums ( -- temp ) "checksums.txt" temp-file ; diff --git a/build-support/factor.cmd b/build-support/factor.cmd index 57a41f24eb..4a3d48654c 100644 --- a/build-support/factor.cmd +++ b/build-support/factor.cmd @@ -46,7 +46,7 @@ nmake /nologo /f Nmakefile %_target% if errorlevel 1 goto fail echo Fetching %_bootimage_version% boot image... -cscript /nologo build-support\http-get.vbs http://factorcode.org/images/%_bootimage_path%/%_bootimage% %_bootimage% +cscript /nologo build-support\http-get.vbs http://downloads.factorcode.org/images/%_bootimage_path%/%_bootimage% %_bootimage% if errorlevel 1 goto fail echo Bootstrapping... diff --git a/build-support/factor.sh b/build-support/factor.sh index 9da4ae295a..08af7a5c39 100755 --- a/build-support/factor.sh +++ b/build-support/factor.sh @@ -447,7 +447,7 @@ update_boot_images() { $DELETE $BOOT_IMAGE.{?,??} > /dev/null 2>&1 $DELETE temp/staging.*.image > /dev/null 2>&1 if [[ -f $BOOT_IMAGE ]] ; then - get_url http://factorcode.org/images/latest/checksums.txt + get_url http://downloads.factorcode.org/images/latest/checksums.txt factorcode_md5=`cat checksums.txt|grep $BOOT_IMAGE|cut -f2 -d' '`; set_md5sum case $OS in @@ -469,7 +469,7 @@ update_boot_images() { get_boot_image() { $ECHO "Downloading boot image $BOOT_IMAGE." - get_url http://factorcode.org/images/latest/$BOOT_IMAGE + get_url http://downloads.factorcode.org/images/latest/$BOOT_IMAGE } get_url() { From 794d371444c624e9acbe8baf504acab70cdff9d8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 27 Sep 2010 20:37:37 -0700 Subject: [PATCH 09/15] vm: fix compiler warning --- vm/contexts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/contexts.cpp b/vm/contexts.cpp index 099a320cfd..b31c42f0f4 100644 --- a/vm/contexts.cpp +++ b/vm/contexts.cpp @@ -77,7 +77,7 @@ void context::scrub_stacks(gc_info *info, cell index) { cell base = info->callsite_scrub_r(index); - for(int loc = 0; loc < info->scrub_r_count; loc++) + for(cell loc = 0; loc < info->scrub_r_count; loc++) { if(bitmap_p(bitmap,base + loc)) { From acdcc9ac26db329ec85ba3aef444137297e6ceed Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 27 Sep 2010 21:14:22 -0700 Subject: [PATCH 10/15] websites.factorcode: new factorcode.org site, just like the old factorcode.org site --- .../concatenative/concatenative.factor | 20 +-- extra/websites/factorcode/bg_header.jpg | Bin 0 -> 1792 bytes extra/websites/factorcode/factorcode.factor | 17 +++ extra/websites/factorcode/index.fhtml | 80 ++++++++++ extra/websites/factorcode/logo.png | Bin 0 -> 9130 bytes extra/websites/factorcode/master.css | 144 ++++++++++++++++++ 6 files changed, 252 insertions(+), 9 deletions(-) create mode 100644 extra/websites/factorcode/bg_header.jpg create mode 100644 extra/websites/factorcode/factorcode.factor create mode 100644 extra/websites/factorcode/index.fhtml create mode 100644 extra/websites/factorcode/logo.png create mode 100644 extra/websites/factorcode/master.css diff --git a/extra/websites/concatenative/concatenative.factor b/extra/websites/concatenative/concatenative.factor index 61b4f7d887..379ba32a57 100644 --- a/extra/websites/concatenative/concatenative.factor +++ b/extra/websites/concatenative/concatenative.factor @@ -26,7 +26,8 @@ webapps.wiki webapps.user-admin webapps.help webapps.mason -webapps.mason.backend ; +webapps.mason.backend +websites.factorcode ; IN: websites.concatenative : test-db ( -- db ) "resource:test.db" ; @@ -44,11 +45,11 @@ IN: websites.concatenative } ensure-tables ] with-db ; -TUPLE: factor-website < dispatcher ; +TUPLE: concatenative-website < dispatcher ; : ( responder -- responder' ) - { factor-website "page" } >>template ; + { concatenative-website "page" } >>template ; : ( responder -- responder' ) "Factor website" @@ -64,8 +65,8 @@ TUPLE: factor-website < dispatcher ; "6LeJWQgAAAAAAFlYV7SuBClE9uSpGtV_ZS-qVON7" >>public-key "6LeJWQgAAAAAALh-XJgSSQ6xKygRgJ8-029Ip2Xv" >>private-key ; -: ( -- responder ) - factor-website new-dispatcher +: ( -- responder ) + concatenative-website new-dispatcher URL" /wiki/view/Front Page" "" add-responder ; SYMBOL: key-password @@ -84,7 +85,7 @@ SYMBOL: dh-file "vocab:openssl/test/server.pem" key-file set-global "password" key-password set-global common-configuration - + "wiki" add-responder "user-admin" add-responder "pastebin" add-responder @@ -102,7 +103,7 @@ SYMBOL: dh-file : init-production ( -- ) common-configuration - + "wiki" add-responder "user-admin" add-responder test-db "concatenative.org" add-responder @@ -111,6 +112,7 @@ SYMBOL: dh-file test-db "builds.factorcode.org" add-responder home "docs" append-path "docs.factorcode.org" add-responder home "cgi" append-path "gitweb.factorcode.org" add-responder + "new.factorcode.org" add-responder main-responder set-global ; : ( -- config ) @@ -119,7 +121,7 @@ SYMBOL: dh-file dh-file get >>dh-file key-password get >>password ; -: ( -- threaded-server ) +: ( -- threaded-server ) >>secure-config 8080 >>insecure @@ -129,4 +131,4 @@ SYMBOL: dh-file test-db start-expiring test-db start-update-task http-insomniac - start-server ; + start-server ; diff --git a/extra/websites/factorcode/bg_header.jpg b/extra/websites/factorcode/bg_header.jpg new file mode 100644 index 0000000000000000000000000000000000000000..10dbd74e8acdbe80927dce4af7f5ad0b6d1dcf08 GIT binary patch literal 1792 zcmex=R-tZb|xz{bJG4g_o*9GqNST$~&{V890g0&u{{ z%)-LP#>T_J!6U@S!zUyHk`WOE%L_s%0VoC6gTnZKfI*OhL79nznNg5|Nsy6Qkn#T! zh6)BoFaWv}1{hhGnK&V$j4&}E&Bz3FumDgw2P4q^KzWFqFk|9HCg#a3q9KNkjf#P+ zf`t)sdG=REXwFh_;TAQ zXY)=|Jzv2yau2kvUJji!pLXA=q# zNMMr@An8Peb^1T51_NnswV^_~Ae`iI1OxVTk@iz-zyHKj>DQM=&A;uNE#Hy+cK&z! zZKZKh#T(PRbV3((i&iW;8m9r`L_X>k{g$!l=sYkl6vz{aSbbDX3&s@#s*HlEgmMC1 zyMU%V>IQN5R)Gx^`|=8#BB1FYML?^Exrgc z9M0AG=-Ra>FliCY7`XHA)rBp;{M1Mzz3ie$yp%lf$F~l zWgLvaYQw6Vj@CNn-Pirk5N-bV)qjRuwfzG3!G7SiRG+}}`U-nl!zb2H3>>U)SQwu$ zTQR)7!ahNpL(%yJ8)F3H0tepT4fzflg7XVB1Q-~2Ua@8fFxNeZPf(vA=di%v&SA|v zmiz`y7L7`Va}Cy|j8C|L1|ca~`+|kx{tmtaL5wb+80S_syt`mlv;A+*{qL*)ZaKGK z;N`df48^~vIr}+ture__FuY-4PwM=^G{IVggMmr?!Kx)p4GiiJxGn*0X1v3|_f~^} z;Q|8(gKdNH0tN=jJB!Q@h;TxcGcbJ9FkxU~;7{Or!MKz`wnMgy#bK2}Lx95nn*d13 B)&>9o literal 0 HcmV?d00001 diff --git a/extra/websites/factorcode/factorcode.factor b/extra/websites/factorcode/factorcode.factor new file mode 100644 index 0000000000..edf2468024 --- /dev/null +++ b/extra/websites/factorcode/factorcode.factor @@ -0,0 +1,17 @@ +! Copyright (c) 2010 Slava Pestov +! See http://factorcode.org/license.txt for BSD license. +USING: accessors http.server http.server.dispatchers +http.server.static kernel namespaces sequences ; +IN: websites.factorcode + +SYMBOL: users + +: ( -- website ) + + "resource:extra/websites/factorcode/" >>default + users get [ + [ "/home/" "/www/" surround ] keep add-responder + ] each ; + +: init-testing ( -- ) + main-responder set-global ; diff --git a/extra/websites/factorcode/index.fhtml b/extra/websites/factorcode/index.fhtml new file mode 100644 index 0000000000..5a565bba84 --- /dev/null +++ b/extra/websites/factorcode/index.fhtml @@ -0,0 +1,80 @@ +<% USING: namespaces http.client kernel io.files splitting random io io.encodings.utf8 sequences ; %> + + + + + + + + Factor programming language + + + + + +
Factor programming language
+ + + + + + + + + +
+ +

Why Factor?

+ +

The Factor programming language combines powerful language features with a full-featured library. The implementation is fully compiled for performance, while still supporting interactive development. Factor applications are portable between all common platforms. Factor can deploy stand-alone applications on all platforms. Full source code for the Factor project is available under a BSD license.

+ + + +

Most of the above links point to pages on the concatenative.org wiki.

+
+ +

Show me some code!

+ +

Factor belongs to the family of concatenative languages: this means that, at the lowest level, a Factor program is a series of words (functions) that manipulate a stack of references to dynamically-typed values. This gives the language a powerful foundation which allows many abstractions and paradigms to be built on top. Reload this page to see a random code example below.

+ +
+<%
+"/var/www/factorcode.org/newsite/examples.txt" utf8 file-lines
+{ "----" } split random "\n" join write
+%>
+
+ +

See the example programs page on the wiki for more.

+ +
+ +

Downloads

+ +

To download a binary, follow the link corresponding to your computer's CPU/OS configuration. Binary packages are the recommended route for new users who wish to try Factor.

+ +<% +"http://builds.factorcode.org/downloads" http-get nip write +%> + +

Source code is stored in our GIT repository. Source can can be browsed online via github or gitweb.

+ +

More

+ + + + + diff --git a/extra/websites/factorcode/logo.png b/extra/websites/factorcode/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9907d2c727437aad7843ed0abe3ffb06c487ebb7 GIT binary patch literal 9130 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 Date: Mon, 27 Sep 2010 21:15:08 -0700 Subject: [PATCH 11/15] websites.factorcode: enable .fhtml --- extra/websites/factorcode/factorcode.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/websites/factorcode/factorcode.factor b/extra/websites/factorcode/factorcode.factor index edf2468024..36450509b3 100644 --- a/extra/websites/factorcode/factorcode.factor +++ b/extra/websites/factorcode/factorcode.factor @@ -8,7 +8,7 @@ SYMBOL: users : ( -- website ) - "resource:extra/websites/factorcode/" >>default + "resource:extra/websites/factorcode/" enable-fhtml >>default users get [ [ "/home/" "/www/" surround ] keep add-responder ] each ; From 5b60d592c089528eb833ce02c5c54ec7ad357feb Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 27 Sep 2010 21:17:29 -0700 Subject: [PATCH 12/15] websites.factorcode: add examples --- extra/websites/factorcode/examples.txt | 57 ++++++++++++++++++++++++++ extra/websites/factorcode/index.fhtml | 2 +- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 extra/websites/factorcode/examples.txt diff --git a/extra/websites/factorcode/examples.txt b/extra/websites/factorcode/examples.txt new file mode 100644 index 0000000000..420035c5fb --- /dev/null +++ b/extra/websites/factorcode/examples.txt @@ -0,0 +1,57 @@ +USING: io math sequences ; + +"Hello world" print +10 [ "Hello, Factor" print ] times +"Hello, " "Factor" append print +---- +USING: io kernel sequences +http.client xml xml.data xml.traversal ; + +"http://factorcode.org" http-get nip string>xml +"a" deep-tags-named +[ "href" attr ] map +[ print ] each +---- +USING: accessors kernel math math.constants +math.functions prettyprint ; +IN: shapes + +TUPLE: circle radius ; +TUPLE: rectangle width height ; + +GENERIC: area ( shape -- area ) +M: circle area radius>> sq pi * ; +M: rectangle area [ width>> ] [ height>> ] bi * ; + +rectangle new 10 >>width 20 >>height area . +---- +USING: accessors smtp ; + +<email> + "john@foobar.com" >>from + { "jane@foobar.com" } >>to + "Up for lunch?" >>subject + "At Tracy's." >>body +send-email +---- +USING: io.files io.encodings.utf8 kernel +sequences splitting ; + +"table.txt" utf8 [ + file-lines + [ "|" split ] map flip [ "|" join ] map +] 2keep +set-file-lines +---- +USING: sequences xml.syntax xml.writer ; + +{ "three" "blind" "mice" } +[ [XML <li><-></li> XML] ] map +[XML <ul><-></ul> XML] +pprint-xml +---- +USING: inspector io.files.info io.pathnames system tools.files ; + +home directory. +home file-system-info free-space>> . +image file-info describe diff --git a/extra/websites/factorcode/index.fhtml b/extra/websites/factorcode/index.fhtml index 5a565bba84..64013ef580 100644 --- a/extra/websites/factorcode/index.fhtml +++ b/extra/websites/factorcode/index.fhtml @@ -44,7 +44,7 @@
 <%
-"/var/www/factorcode.org/newsite/examples.txt" utf8 file-lines
+"resource:extra/websites/factorcode/examples.txt" utf8 file-lines
 { "----" } split random "\n" join write
 %>
 
From 18d4d01e4863501c4aa8b4d07422c2a80fc370c4 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 27 Sep 2010 21:45:31 -0700 Subject: [PATCH 13/15] furnace.utilities: clean up --- basis/furnace/utilities/utilities.factor | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/basis/furnace/utilities/utilities.factor b/basis/furnace/utilities/utilities.factor index dc90ad4e8c..94762d7591 100644 --- a/basis/furnace/utilities/utilities.factor +++ b/basis/furnace/utilities/utilities.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: namespaces make assocs sequences kernel classes splitting words vocabs.loader accessors strings combinators arrays @@ -27,10 +27,12 @@ ERROR: no-such-word name vocab ; : each-responder ( quot -- ) nested-responders swap each ; inline -: base-path ( string -- pair ) +ERROR: no-such-responder responder ; + +: base-path ( string -- seq ) dup responder-nesting get [ second class superclasses [ name>> = ] with any? ] with find nip - [ first ] [ "No such responder: " swap append throw ] ?if ; + [ first ] [ no-such-responder ] ?if ; : resolve-base-path ( string -- string' ) "$" ?head [ From 55c98bbf7046d4a02e9156bdca47579705e6e997 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 27 Sep 2010 21:45:46 -0700 Subject: [PATCH 14/15] websites.factorcode: update index.fhtml --- extra/webapps/mason/utils/utils.factor | 4 ++-- extra/websites/factorcode/index.fhtml | 31 ++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/extra/webapps/mason/utils/utils.factor b/extra/webapps/mason/utils/utils.factor index 05435893f5..bffc78970a 100644 --- a/extra/webapps/mason/utils/utils.factor +++ b/extra/webapps/mason/utils/utils.factor @@ -44,13 +44,13 @@ IN: webapps.mason.utils "http://downloads.factorcode.org/" prepend ; : package-url ( builder -- url ) - [ URL" $mason-app/package" ] dip + [ URL" http://builds.factorcode.org/package" ] dip [ os>> "os" set-query-param ] [ cpu>> "cpu" set-query-param ] bi adjust-url ; : release-url ( builder -- url ) - [ URL" $mason-app/release" ] dip + [ URL" http://builds.factorcode.org/release" ] dip [ os>> "os" set-query-param ] [ cpu>> "cpu" set-query-param ] bi adjust-url ; diff --git a/extra/websites/factorcode/index.fhtml b/extra/websites/factorcode/index.fhtml index 64013ef580..fa07da9296 100644 --- a/extra/websites/factorcode/index.fhtml +++ b/extra/websites/factorcode/index.fhtml @@ -1,4 +1,7 @@ -<% USING: namespaces http.client kernel io.files splitting random io io.encodings.utf8 sequences ; %> +<% USING: namespaces http.client kernel io.files splitting random io io.encodings.utf8 sequences +webapps.mason.version.data webapps.mason.backend webapps.mason.grids webapps.mason.downloads +webapps.mason.utils html.elements accessors +xml.writer ; %> @@ -58,11 +61,31 @@

Downloads

+<% [ %> +

To download a binary, follow the link corresponding to your computer's CPU/OS configuration. Binary packages are the recommended route for new users who wish to try Factor.

-<% -"http://builds.factorcode.org/downloads" http-get nip write -%> +

Stable release: +<% latest-version > =href a> ] [ version>> write ] bi %> +

+ + + <% release-grid write-xml %> +
+ +

Source code: +<% latest-version > download-url =href a> ] [ version>> write ] bi %> +

+ +

Development release

+ + + <% package-grid write-xml %> +
+ +<% ] with-mason-db %> + +

Stable and development releases are built and uploaded by the build farm. Follow @FactorBuilds on Twitter to receive notifications. If you're curious, take a look at the build farm dashboard.

Source code is stored in our GIT repository. Source can can be browsed online via github or gitweb.

From 2374126ed861abc3cd555b7c7c3b2258f83b2bc6 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 27 Sep 2010 21:46:40 -0700 Subject: [PATCH 15/15] websites.factorcode: FIX TYPO --- extra/websites/factorcode/index.fhtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/websites/factorcode/index.fhtml b/extra/websites/factorcode/index.fhtml index fa07da9296..ab901eaaff 100644 --- a/extra/websites/factorcode/index.fhtml +++ b/extra/websites/factorcode/index.fhtml @@ -85,7 +85,7 @@ xml.writer ; %> <% ] with-mason-db %> -

Stable and development releases are built and uploaded by the build farm. Follow @FactorBuilds on Twitter to receive notifications. If you're curious, take a look at the build farm dashboard.

+

Stable and development releases are built and uploaded by the build farm. Follow @FactorBuilds on Twitter to receive notifications. If you're curious, take a look at the build farm dashboard.

Source code is stored in our GIT repository. Source can can be browsed online via github or gitweb.