diff --git a/.gitignore b/.gitignore index b52c593b49..a839a6ff19 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ Factor/factor *.a *.dll *.lib +*.res *.image *.dylib factor diff --git a/GNUmakefile b/GNUmakefile new file mode 100755 index 0000000000..4447dfbede --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,223 @@ +ifdef CONFIG + CC = gcc + CPP = g++ + AR = ar + LD = ld + + VERSION = 0.92 + + BUNDLE = Factor.app + LIBPATH = -L/usr/X11R6/lib + + CFLAGS = -Wall $(SITE_CFLAGS) + + ifdef DEBUG + CFLAGS += -g -DFACTOR_DEBUG + else + CFLAGS += -O3 + endif + + include $(CONFIG) + + ENGINE = $(DLL_PREFIX)factor$(DLL_SUFFIX)$(DLL_EXTENSION) + EXECUTABLE = factor$(EXE_SUFFIX)$(EXE_EXTENSION) + CONSOLE_EXECUTABLE = factor$(EXE_SUFFIX)$(CONSOLE_EXTENSION) + + DLL_OBJS = $(PLAF_DLL_OBJS) \ + vm/aging_collector.o \ + vm/alien.o \ + vm/arrays.o \ + vm/bignum.o \ + vm/booleans.o \ + vm/byte_arrays.o \ + vm/callbacks.o \ + vm/callstack.o \ + vm/code_blocks.o \ + vm/code_heap.o \ + vm/compaction.o \ + vm/contexts.o \ + vm/data_heap.o \ + vm/data_heap_checker.o \ + vm/debug.o \ + vm/dispatch.o \ + vm/entry_points.o \ + vm/errors.o \ + vm/factor.o \ + vm/free_list.o \ + vm/full_collector.o \ + vm/gc.o \ + vm/image.o \ + vm/inline_cache.o \ + vm/instruction_operands.o \ + vm/io.o \ + vm/jit.o \ + vm/math.o \ + vm/nursery_collector.o \ + vm/object_start_map.o \ + vm/objects.o \ + vm/primitives.o \ + vm/profiler.o \ + vm/quotations.o \ + vm/run.o \ + vm/strings.o \ + vm/to_tenured_collector.o \ + vm/tuples.o \ + vm/utilities.o \ + vm/vm.o \ + vm/words.o + + EXE_OBJS = $(PLAF_EXE_OBJS) + + FFI_TEST_LIBRARY = libfactor-ffi-test$(SHARED_DLL_EXTENSION) + + TEST_OBJS = vm/ffi_test.o +endif + +default: + $(MAKE) `./build-support/factor.sh make-target` + +help: + @echo "Run '$(MAKE)' with one of the following parameters:" + @echo "" + @echo "freebsd-x86-32" + @echo "freebsd-x86-64" + @echo "linux-x86-32" + @echo "linux-x86-64" + @echo "linux-ppc" + @echo "linux-arm" + @echo "openbsd-x86-32" + @echo "openbsd-x86-64" + @echo "netbsd-x86-32" + @echo "netbsd-x86-64" + @echo "macosx-x86-32" + @echo "macosx-x86-64" + @echo "macosx-ppc" + @echo "solaris-x86-32" + @echo "solaris-x86-64" + @echo "wince-arm" + @echo "winnt-x86-32" + @echo "winnt-x86-64" + @echo "" + @echo "Additional modifiers:" + @echo "" + @echo "DEBUG=1 compile VM with debugging information" + @echo "SITE_CFLAGS=... additional optimization flags" + @echo "NO_UI=1 don't link with X11 libraries (ignored on Mac OS X)" + @echo "X11=1 force link with X11 libraries instead of Cocoa (only on Mac OS X)" + +openbsd-x86-32: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.openbsd.x86.32 + +openbsd-x86-64: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.openbsd.x86.64 + +freebsd-x86-32: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.freebsd.x86.32 + +freebsd-x86-64: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.freebsd.x86.64 + +netbsd-x86-32: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.netbsd.x86.32 + +netbsd-x86-64: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.netbsd.x86.64 + +macosx-ppc: + $(MAKE) factor factor-ffi-test macosx.app CONFIG=vm/Config.macosx.ppc + +macosx-x86-32: + $(MAKE) factor factor-ffi-test macosx.app CONFIG=vm/Config.macosx.x86.32 + +macosx-x86-64: + $(MAKE) factor factor-ffi-test macosx.app CONFIG=vm/Config.macosx.x86.64 + +linux-x86-32: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.linux.x86.32 + +linux-x86-64: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.linux.x86.64 + +linux-ppc: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.linux.ppc + +linux-arm: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.linux.arm + +solaris-x86-32: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.solaris.x86.32 + +solaris-x86-64: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.solaris.x86.64 + +winnt-x86-32: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.windows.nt.x86.32 + $(MAKE) factor-console CONFIG=vm/Config.windows.nt.x86.32 + +winnt-x86-64: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.windows.nt.x86.64 + $(MAKE) factor-console CONFIG=vm/Config.windows.nt.x86.64 + +wince-arm: + $(MAKE) factor factor-ffi-test CONFIG=vm/Config.windows.ce.arm + +ifdef CONFIG + +macosx.app: factor + mkdir -p $(BUNDLE)/Contents/MacOS + mkdir -p $(BUNDLE)/Contents/Frameworks + mv $(EXECUTABLE) $(BUNDLE)/Contents/MacOS/factor + ln -s Factor.app/Contents/MacOS/factor ./factor + cp $(ENGINE) $(BUNDLE)/Contents/Frameworks/$(ENGINE) + + install_name_tool \ + -change libfactor.dylib \ + @executable_path/../Frameworks/libfactor.dylib \ + Factor.app/Contents/MacOS/factor + +$(ENGINE): $(DLL_OBJS) + $(TOOLCHAIN_PREFIX)$(LINKER) $(ENGINE) $(DLL_OBJS) + +factor: $(EXE_OBJS) $(ENGINE) + $(TOOLCHAIN_PREFIX)$(CPP) $(LIBS) $(LIBPATH) -L. $(LINK_WITH_ENGINE) \ + $(CFLAGS) -o $(EXECUTABLE) $(EXE_OBJS) + +factor-console: $(EXE_OBJS) $(ENGINE) + $(TOOLCHAIN_PREFIX)$(CPP) $(LIBS) $(LIBPATH) -L. $(LINK_WITH_ENGINE) \ + $(CFLAGS) $(CFLAGS_CONSOLE) -o $(CONSOLE_EXECUTABLE) $(EXE_OBJS) + +factor-ffi-test: $(FFI_TEST_LIBRARY) + +$(FFI_TEST_LIBRARY): vm/ffi_test.o + $(TOOLCHAIN_PREFIX)$(CC) $(LIBPATH) $(CFLAGS) $(FFI_TEST_CFLAGS) $(SHARED_FLAG) -o $(FFI_TEST_LIBRARY) $(TEST_OBJS) + +vm/resources.o: + $(TOOLCHAIN_PREFIX)$(WINDRES) vm/factor.rs vm/resources.o + +vm/ffi_test.o: vm/ffi_test.c + $(TOOLCHAIN_PREFIX)$(CC) -c $(CFLAGS) $(FFI_TEST_CFLAGS) -o $@ $< + +.cpp.o: + $(TOOLCHAIN_PREFIX)$(CPP) -c $(CFLAGS) -o $@ $< + +.S.o: + $(TOOLCHAIN_PREFIX)$(CC) -x assembler-with-cpp -c $(CFLAGS) -o $@ $< + +.mm.o: + $(TOOLCHAIN_PREFIX)$(CPP) -c $(CFLAGS) -o $@ $< + +.SUFFIXES: .mm + +endif + +clean: + rm -f vm/*.o + rm -f factor.dll + rm -f libfactor.* + rm -f libfactor-ffi-test.* + rm -f Factor.app/Contents/Frameworks/libfactor.dylib + +tags: + etags vm/*.{cpp,hpp,mm,S,c} + +.PHONY: factor factor-console factor-ffi-test tags clean macosx.app diff --git a/Makefile b/Makefile deleted file mode 100755 index 2ea43706f4..0000000000 --- a/Makefile +++ /dev/null @@ -1,219 +0,0 @@ -CC = gcc -CPP = g++ -AR = ar -LD = ld - -EXECUTABLE = factor -CONSOLE_EXECUTABLE = factor-console -TEST_LIBRARY = factor-ffi-test -VERSION = 0.92 - -BUNDLE = Factor.app -LIBPATH = -L/usr/X11R6/lib -CFLAGS = -Wall - -ifdef DEBUG - CFLAGS += -g -DFACTOR_DEBUG -else - CFLAGS += -O3 -endif - -ifdef REENTRANT - CFLAGS += -DFACTOR_REENTRANT -endif - -CFLAGS += $(SITE_CFLAGS) - -ENGINE = $(DLL_PREFIX)factor$(DLL_SUFFIX)$(DLL_EXTENSION) - -ifdef CONFIG - include $(CONFIG) -endif - -DLL_OBJS = $(PLAF_DLL_OBJS) \ - vm/aging_collector.o \ - vm/alien.o \ - vm/arrays.o \ - vm/bignum.o \ - vm/booleans.o \ - vm/byte_arrays.o \ - vm/callbacks.o \ - vm/callstack.o \ - vm/code_block.o \ - vm/code_heap.o \ - vm/compaction.o \ - vm/contexts.o \ - vm/data_heap.o \ - vm/debug.o \ - vm/dispatch.o \ - vm/errors.o \ - vm/factor.o \ - vm/free_list.o \ - vm/full_collector.o \ - vm/gc.o \ - vm/image.o \ - vm/inline_cache.o \ - vm/io.o \ - vm/jit.o \ - vm/math.o \ - vm/nursery_collector.o \ - vm/object_start_map.o \ - vm/primitives.o \ - vm/profiler.o \ - vm/quotations.o \ - vm/run.o \ - vm/strings.o \ - vm/to_tenured_collector.o \ - vm/tuples.o \ - vm/utilities.o \ - vm/vm.o \ - vm/words.o - -EXE_OBJS = $(PLAF_EXE_OBJS) - -TEST_OBJS = vm/ffi_test.o - -default: - $(MAKE) `./build-support/factor.sh make-target` - -help: - @echo "Run '$(MAKE)' with one of the following parameters:" - @echo "" - @echo "freebsd-x86-32" - @echo "freebsd-x86-64" - @echo "linux-x86-32" - @echo "linux-x86-64" - @echo "linux-ppc" - @echo "linux-arm" - @echo "openbsd-x86-32" - @echo "openbsd-x86-64" - @echo "netbsd-x86-32" - @echo "netbsd-x86-64" - @echo "macosx-x86-32" - @echo "macosx-x86-64" - @echo "macosx-ppc" - @echo "solaris-x86-32" - @echo "solaris-x86-64" - @echo "wince-arm" - @echo "winnt-x86-32" - @echo "winnt-x86-64" - @echo "" - @echo "Additional modifiers:" - @echo "" - @echo "DEBUG=1 compile VM with debugging information" - @echo "SITE_CFLAGS=... additional optimization flags" - @echo "NO_UI=1 don't link with X11 libraries (ignored on Mac OS X)" - @echo "X11=1 force link with X11 libraries instead of Cocoa (only on Mac OS X)" - -openbsd-x86-32: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.openbsd.x86.32 - -openbsd-x86-64: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.openbsd.x86.64 - -freebsd-x86-32: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.freebsd.x86.32 - -freebsd-x86-64: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.freebsd.x86.64 - -netbsd-x86-32: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.netbsd.x86.32 - -netbsd-x86-64: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.netbsd.x86.64 - -macosx-ppc: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) macosx.app CONFIG=vm/Config.macosx.ppc - -macosx-x86-32: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) macosx.app CONFIG=vm/Config.macosx.x86.32 - -macosx-x86-64: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) macosx.app CONFIG=vm/Config.macosx.x86.64 - -linux-x86-32: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.linux.x86.32 - -linux-x86-64: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.linux.x86.64 - -linux-ppc: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.linux.ppc - -linux-arm: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.linux.arm - -solaris-x86-32: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.solaris.x86.32 - -solaris-x86-64: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.solaris.x86.64 - -winnt-x86-32: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.windows.nt.x86.32 - $(MAKE) $(CONSOLE_EXECUTABLE) CONFIG=vm/Config.windows.nt.x86.32 - -winnt-x86-64: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.windows.nt.x86.64 - $(MAKE) $(CONSOLE_EXECUTABLE) CONFIG=vm/Config.windows.nt.x86.64 - -wince-arm: - $(MAKE) $(EXECUTABLE) $(TEST_LIBRARY) CONFIG=vm/Config.windows.ce.arm - -macosx.app: factor - mkdir -p $(BUNDLE)/Contents/MacOS - mkdir -p $(BUNDLE)/Contents/Frameworks - mv $(EXECUTABLE) $(BUNDLE)/Contents/MacOS/factor - ln -s Factor.app/Contents/MacOS/factor ./factor - cp $(ENGINE) $(BUNDLE)/Contents/Frameworks/$(ENGINE) - - install_name_tool \ - -change libfactor.dylib \ - @executable_path/../Frameworks/libfactor.dylib \ - Factor.app/Contents/MacOS/factor - -$(EXECUTABLE): $(DLL_OBJS) $(EXE_OBJS) - $(TOOLCHAIN_PREFIX)$(LINKER) $(ENGINE) $(DLL_OBJS) - $(TOOLCHAIN_PREFIX)$(CPP) $(LIBS) $(LIBPATH) -L. $(LINK_WITH_ENGINE) \ - $(CFLAGS) -o $@$(EXE_SUFFIX)$(EXE_EXTENSION) $(EXE_OBJS) - -$(CONSOLE_EXECUTABLE): $(DLL_OBJS) $(EXE_OBJS) - $(TOOLCHAIN_PREFIX)$(LINKER) $(ENGINE) $(DLL_OBJS) - $(TOOLCHAIN_PREFIX)$(CPP) $(LIBS) $(LIBPATH) -L. $(LINK_WITH_ENGINE) \ - $(CFLAGS) $(CFLAGS_CONSOLE) -o factor$(EXE_SUFFIX)$(CONSOLE_EXTENSION) $(EXE_OBJS) - -$(TEST_LIBRARY): vm/ffi_test.o - $(TOOLCHAIN_PREFIX)$(CC) $(LIBPATH) $(CFLAGS) $(FFI_TEST_CFLAGS) $(SHARED_FLAG) -o libfactor-ffi-test$(SHARED_DLL_EXTENSION) $(TEST_OBJS) - -clean: - rm -f vm/*.o - rm -f factor.dll - rm -f libfactor.* - rm -f libfactor-ffi-test.* - rm -f Factor.app/Contents/Frameworks/libfactor.dylib - -tags: - etags vm/*.{cpp,hpp,mm,S,c} - -vm/resources.o: - $(TOOLCHAIN_PREFIX)$(WINDRES) vm/factor.rs vm/resources.o - -vm/ffi_test.o: vm/ffi_test.c - $(TOOLCHAIN_PREFIX)$(CC) -c $(CFLAGS) $(FFI_TEST_CFLAGS) -o $@ $< - -.c.o: - $(TOOLCHAIN_PREFIX)$(CC) -c $(CFLAGS) -o $@ $< - -.cpp.o: - $(TOOLCHAIN_PREFIX)$(CPP) -c $(CFLAGS) -o $@ $< - -.S.o: - $(TOOLCHAIN_PREFIX)$(CC) -x assembler-with-cpp -c $(CFLAGS) -o $@ $< - -.mm.o: - $(TOOLCHAIN_PREFIX)$(CPP) -c $(CFLAGS) -o $@ $< - -.PHONY: factor tags clean - -.SUFFIXES: .mm diff --git a/Nmakefile b/Nmakefile new file mode 100755 index 0000000000..e964105d9f --- /dev/null +++ b/Nmakefile @@ -0,0 +1,77 @@ +LINK_FLAGS = /nologo shell32.lib +CL_FLAGS = /nologo /O2 /W3 + +EXE_OBJS = factor.dll.lib vm\main-windows-nt.obj vm\factor.res + +DLL_OBJS = vm\os-windows-nt.obj \ + vm\os-windows.obj \ + vm\aging_collector.obj \ + vm\alien.obj \ + vm\arrays.obj \ + vm\bignum.obj \ + vm\booleans.obj \ + vm\byte_arrays.obj \ + vm\callbacks.obj \ + vm\callstack.obj \ + vm\code_blocks.obj \ + vm\code_heap.obj \ + vm\compaction.obj \ + vm\contexts.obj \ + vm\data_heap.obj \ + vm\data_heap_checker.obj \ + vm\debug.obj \ + vm\dispatch.obj \ + vm\entry_points.obj \ + vm\errors.obj \ + vm\factor.obj \ + vm\free_list.obj \ + vm\full_collector.obj \ + vm\gc.obj \ + vm\image.obj \ + vm\inline_cache.obj \ + vm\instruction_operands.obj \ + vm\io.obj \ + vm\jit.obj \ + vm\math.obj \ + vm\nursery_collector.obj \ + vm\object_start_map.obj \ + vm\objects.obj \ + vm\primitives.obj \ + vm\profiler.obj \ + vm\quotations.obj \ + vm\run.obj \ + vm\strings.obj \ + vm\to_tenured_collector.obj \ + vm\tuples.obj \ + vm\utilities.obj \ + vm\vm.obj \ + vm\words.obj + +.cpp.obj: + cl /EHsc $(CL_FLAGS) /Fo$@ /c $< + +.rs.res: + rc $< + +all: factor.com factor.exe + +factor.dll.lib: $(DLL_OBJS) + link $(LINK_FLAGS) /implib:factor.dll.lib /out:factor.dll /dll $(DLL_OBJS) + +factor.com: $(EXE_OBJS) + link $(LINK_FLAGS) /out:factor.com /SUBSYSTEM:console $(EXE_OBJS) + +factor.exe: $(EXE_OBJS) + link $(LINK_FLAGS) /out:factor.exe /SUBSYSTEM:windows $(EXE_OBJS) + +clean: + del vm\*.obj + del factor.lib + del factor.com + del factor.exe + del factor.dll + del factor.dll.lib + +.PHONY: all clean + +.SUFFIXES: .rs diff --git a/basis/alarms/alarms-docs.factor b/basis/alarms/alarms-docs.factor index 82134e825e..396011a351 100644 --- a/basis/alarms/alarms-docs.factor +++ b/basis/alarms/alarms-docs.factor @@ -1,16 +1,37 @@ +USING: help.markup help.syntax calendar quotations system ; IN: alarms -USING: help.markup help.syntax calendar quotations ; HELP: alarm { $class-description "An alarm. Can be passed to " { $link cancel-alarm } "." } ; +HELP: current-alarm +{ $description "A symbol that contains the currently executing alarm, availble only to the alarm quotation. One use for this symbol is if a repeated alarm wishes to cancel itself from executing in the future." +} +{ $examples + { $unchecked-example + """USING: alarms calendar io threads ;""" + """[""" + """ "Hi, this should only get printed once..." print flush""" + """ current-alarm get cancel-alarm""" + """] 1 seconds every""" + "" + } +} ; + HELP: add-alarm -{ $values { "quot" quotation } { "time" timestamp } { "frequency" { $maybe duration } } { "alarm" alarm } } -{ $description "Creates and registers an alarm. If " { $snippet "frequency" } " is " { $link f } ", this will be a one-time alarm, otherwise it will fire with the given frequency. The quotation will be called from the alarm thread." } ; +{ $values { "quot" quotation } { "start" duration } { "interval" { $maybe "duration/f" } } { "alarm" alarm } } +{ $description "Creates and registers an alarm to start at " { $snippet "start" } " offset from the current time. If " { $snippet "interval" } " is " { $link f } ", this will be a one-time alarm, otherwise it will fire with the given frequency, with scheduling happening before the quotation is called in order to ensure that the next event will happen on time. The quotation will be called from a new thread spawned by the alarm thread. If a repeated alarm's quotation throws an exception, the alarm will not be rescheduled." } ; HELP: later { $values { "quot" quotation } { "duration" duration } { "alarm" alarm } } -{ $description "Creates and registers an alarm which calls the quotation once at " { $snippet "time" } " from now." } ; +{ $description "Creates and registers an alarm which calls the quotation once at " { $snippet "duration" } " offset from now." } +{ $examples + { $unchecked-example + "USING: alarms io calendar ;" + """[ "Break's over!" print flush ] 15 minutes drop""" + "" + } +} ; HELP: cancel-alarm { $values { "alarm" alarm } } @@ -20,16 +41,29 @@ HELP: every { $values { "quot" quotation } { "duration" duration } { "alarm" alarm } } -{ $description "Creates and registers an alarm which calls the quotation repeatedly, using " { $snippet "dt" } " as the frequency." } ; +{ $description "Creates and registers an alarm which calls the quotation repeatedly, using " { $snippet "dt" } " as the frequency. If the quotation throws an exception that is not caught inside it, the alarm scheduler will cancel the alarm and will not reschedule it again." } +{ $examples + { $unchecked-example + "USING: alarms io calendar ;" + """[ "Hi Buddy." print flush ] 10 seconds every drop""" + "" + } +} ; ARTICLE: "alarms" "Alarms" -"The " { $vocab-link "alarms" } " vocabulary provides a lightweight way to schedule one-time and recurring tasks without spawning a new thread." -{ $subsections - alarm - add-alarm - later - cancel-alarm -} +"The " { $vocab-link "alarms" } " vocabulary provides a lightweight way to schedule one-time and recurring tasks without spawning a new thread. Alarms use " { $link nano-count } ", so they continue to work across system clock changes." $nl +"The alarm class:" +{ $subsections alarm } +"Register a recurring alarm:" +{ $subsections every } +"Register a one-time alarm:" +{ $subsections later } +"The currently executing alarm:" +{ $subsections current-alarm } +"Low-level interface to add alarms:" +{ $subsections add-alarm } +"Cancelling an alarm:" +{ $subsections cancel-alarm } "Alarms do not persist across image saves. Saving and restoring an image has the effect of calling " { $link cancel-alarm } " on all " { $link alarm } " instances." ; ABOUT: "alarms" diff --git a/basis/alarms/alarms.factor b/basis/alarms/alarms.factor index 9943d39ad1..9ab30a1fa4 100644 --- a/basis/alarms/alarms.factor +++ b/basis/alarms/alarms.factor @@ -1,48 +1,66 @@ ! Copyright (C) 2005, 2008 Slava Pestov, Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs boxes calendar -combinators.short-circuit fry heaps init kernel math.order -namespaces quotations threads ; +USING: accessors assocs boxes calendar combinators.short-circuit +continuations fry heaps init kernel math.order +namespaces quotations threads math system ; IN: alarms TUPLE: alarm { quot callable initial: [ ] } - { time timestamp } + { start integer } interval { entry box } ; -> [ alarms get-global heap-delete ] if-box? ; + +nanoseconds ( obj -- duration/f ) +M: f >nanoseconds ; +M: real >nanoseconds >integer ; +M: duration >nanoseconds duration>nanoseconds >integer ; -: ( quot time frequency -- alarm ) - check-alarm alarm boa ; +: ( quot start interval -- alarm ) + alarm new + swap >nanoseconds >>interval + swap >nanoseconds nano-count + >>start + swap >>quot + >>entry ; : register-alarm ( alarm -- ) - [ dup time>> alarms get-global heap-push* ] + [ dup start>> alarms get-global heap-push* ] [ entry>> >box ] bi notify-alarm-thread ; -: alarm-expired? ( alarm now -- ? ) - [ time>> ] dip before=? ; +: alarm-expired? ( alarm n -- ? ) + [ start>> ] dip <= ; : reschedule-alarm ( alarm -- ) - dup '[ _ interval>> time+ now max ] change-time register-alarm ; + dup interval>> nano-count + >>start register-alarm ; : call-alarm ( alarm -- ) [ entry>> box> drop ] - [ quot>> "Alarm execution" spawn drop ] - [ dup interval>> [ reschedule-alarm ] [ drop ] if ] tri ; + [ dup interval>> [ reschedule-alarm ] [ drop ] if ] + [ + [ ] [ quot>> ] [ ] tri + '[ + _ current-alarm + [ + _ [ _ dup interval>> [ cancel-alarm ] [ drop ] if rethrow ] + recover + ] with-variable + ] "Alarm execution" spawn drop + ] tri ; -: (trigger-alarms) ( alarms now -- ) +: (trigger-alarms) ( alarms n -- ) over heap-empty? [ 2drop ] [ @@ -54,11 +72,10 @@ ERROR: bad-alarm-frequency frequency ; ] if ; : trigger-alarms ( alarms -- ) - now (trigger-alarms) ; + nano-count (trigger-alarms) ; -: next-alarm ( alarms -- timestamp/f ) - dup heap-empty? - [ drop f ] [ heap-peek drop time>> ] if ; +: next-alarm ( alarms -- nanos/f ) + dup heap-empty? [ drop f ] [ heap-peek drop start>> ] if ; : alarm-thread-loop ( -- ) alarms get-global @@ -75,18 +92,13 @@ ERROR: bad-alarm-frequency frequency ; [ alarm-thread-loop t ] "Alarms" spawn-server alarm-thread set-global ; -[ init-alarms ] "alarms" add-init-hook +[ init-alarms ] "alarms" add-startup-hook PRIVATE> -: add-alarm ( quot time frequency -- alarm ) +: add-alarm ( quot start interval -- alarm ) [ register-alarm ] keep ; -: later ( quot duration -- alarm ) - hence f add-alarm ; +: later ( quot duration -- alarm ) f add-alarm ; -: every ( quot duration -- alarm ) - [ hence ] keep add-alarm ; - -: cancel-alarm ( alarm -- ) - entry>> [ alarms get-global heap-delete ] if-box? ; +: every ( quot duration -- alarm ) dup add-alarm ; diff --git a/basis/alien/arrays/arrays.factor b/basis/alien/arrays/arrays.factor old mode 100755 new mode 100644 index ee75d22c2c..7eed1a0664 --- a/basis/alien/arrays/arrays.factor +++ b/basis/alien/arrays/arrays.factor @@ -20,6 +20,8 @@ M: array heap-size unclip [ array-length ] [ heap-size ] bi* * ; M: array c-type-align first c-type-align ; +M: array c-type-align-first first c-type-align-first ; + M: array c-type-stack-align? drop f ; M: array unbox-parameter drop void* unbox-parameter ; @@ -55,6 +57,9 @@ M: string-type heap-size M: string-type c-type-align drop void* c-type-align ; +M: string-type c-type-align-first + drop void* c-type-align-first ; + M: string-type c-type-stack-align? drop void* c-type-stack-align? ; @@ -97,5 +102,5 @@ M: string-type c-type-setter { char* utf8 } char* typedef char* uchar* typedef -char char* "pointer-c-type" set-word-prop +char char* "pointer-c-type" set-word-prop uchar uchar* "pointer-c-type" set-word-prop diff --git a/basis/alien/c-types/c-types-docs.factor b/basis/alien/c-types/c-types-docs.factor old mode 100755 new mode 100644 index a0dea4e539..b221051efc --- a/basis/alien/c-types/c-types-docs.factor +++ b/basis/alien/c-types/c-types-docs.factor @@ -66,12 +66,12 @@ HELP: unbox-return { $notes "This is an internal word used by the compiler when compiling callbacks." } ; HELP: define-deref -{ $values { "name" "a word name" } } +{ $values { "c-type" "a C type" } } { $description "Defines a word " { $snippet "*name" } " with stack effect " { $snippet "( c-ptr -- value )" } " for reading a value with C type " { $snippet "name" } " stored at an alien pointer." } { $notes "This is an internal word called when defining C types, there is no need to call it on your own." } ; HELP: define-out -{ $values { "name" "a word name" } } +{ $values { "c-type" "a C type" } } { $description "Defines a word " { $snippet "<" { $emphasis "name" } ">" } " with stack effect " { $snippet "( value -- array )" } ". This word allocates a byte array large enough to hold a value with C type " { $snippet "name" } ", and writes the value at the top of the stack to the array." } { $notes "This is an internal word called when defining C types, there is no need to call it on your own." } ; diff --git a/basis/alien/c-types/c-types-tests.factor b/basis/alien/c-types/c-types-tests.factor old mode 100755 new mode 100644 diff --git a/basis/alien/c-types/c-types.factor b/basis/alien/c-types/c-types.factor old mode 100755 new mode 100644 index cfbed5378d..347d157a79 --- a/basis/alien/c-types/c-types.factor +++ b/basis/alien/c-types/c-types.factor @@ -30,8 +30,9 @@ TUPLE: abstract-c-type { unboxer-quot callable } { getter callable } { setter callable } -size -align ; +{ size integer } +{ align integer } +{ align-first integer } ; TUPLE: c-type < abstract-c-type boxer @@ -104,10 +105,9 @@ M: word c-type GENERIC: c-struct? ( c-type -- ? ) -M: object c-struct? - drop f ; -M: c-type-name c-struct? - dup void? [ drop f ] [ c-type c-struct? ] if ; +M: object c-struct? drop f ; + +M: c-type-name c-struct? dup void? [ drop f ] [ c-type c-struct? ] if ; ! These words being foldable means that words need to be ! recompiled if a C type is redefined. Even so, folding the @@ -172,6 +172,12 @@ M: abstract-c-type c-type-align align>> ; M: c-type-name c-type-align c-type c-type-align ; +GENERIC: c-type-align-first ( name -- n ) + +M: c-type-name c-type-align-first c-type c-type-align-first ; + +M: abstract-c-type c-type-align-first align-first>> ; + GENERIC: c-type-stack-align? ( name -- ? ) M: c-type c-type-stack-align? stack-align?>> ; @@ -212,13 +218,13 @@ M: c-type-name unbox-return c-type unbox-return ; : little-endian? ( -- ? ) 1 *char 1 = ; foldable -GENERIC: heap-size ( name -- size ) foldable +GENERIC: heap-size ( name -- size ) M: c-type-name heap-size c-type heap-size ; M: abstract-c-type heap-size size>> ; -GENERIC: stack-size ( name -- size ) foldable +GENERIC: stack-size ( name -- size ) M: c-type-name stack-size c-type stack-size ; @@ -291,20 +297,17 @@ M: long-long-type box-parameter ( n c-type -- ) M: long-long-type box-return ( c-type -- ) f swap box-parameter ; -: define-deref ( name -- ) - [ CHAR: * prefix "alien.c-types" create ] [ c-getter 0 prefix ] bi +: define-deref ( c-type -- ) + [ name>> CHAR: * prefix "alien.c-types" create ] [ c-getter 0 prefix ] bi (( c-ptr -- value )) define-inline ; -: define-out ( name -- ) - [ "alien.c-types" constructor-word ] +: define-out ( c-type -- ) + [ name>> "alien.c-types" constructor-word ] [ dup c-setter '[ _ heap-size (byte-array) [ 0 @ ] keep ] ] bi (( value -- c-ptr )) define-inline ; : define-primitive-type ( c-type name -- ) - [ typedef ] - [ name>> define-deref ] - [ name>> define-out ] - tri ; + [ typedef ] [ define-deref ] [ define-out ] tri ; : if-void ( c-type true false -- ) pick void? [ drop nip call ] [ nip call ] if ; inline @@ -324,6 +327,13 @@ SYMBOLS: ptrdiff_t intptr_t uintptr_t size_t char* uchar* ; +: 8-byte-alignment ( c-type -- c-type ) + { + { [ cpu ppc? os macosx? and ] [ 4 >>align 8 >>align-first ] } + { [ cpu x86.32? os windows? not and ] [ 4 >>align 4 >>align-first ] } + [ 8 >>align 8 >>align-first ] + } cond ; + [ c-ptr >>class @@ -332,8 +342,9 @@ SYMBOLS: [ [ >c-ptr ] 2dip set-alien-cell ] >>setter bootstrap-cell >>size bootstrap-cell >>align + bootstrap-cell >>align-first [ >c-ptr ] >>unboxer-quot - "box_alien" >>boxer + "allot_alien" >>boxer "alien_offset" >>unboxer \ void* define-primitive-type @@ -343,8 +354,8 @@ SYMBOLS: [ alien-signed-8 ] >>getter [ set-alien-signed-8 ] >>setter 8 >>size - cpu x86.32? os windows? not and 4 8 ? >>align - "box_signed_8" >>boxer + 8-byte-alignment + "from_signed_8" >>boxer "to_signed_8" >>unboxer \ longlong define-primitive-type @@ -354,8 +365,8 @@ SYMBOLS: [ alien-unsigned-8 ] >>getter [ set-alien-unsigned-8 ] >>setter 8 >>size - cpu x86.32? os windows? not and 4 8 ? >>align - "box_unsigned_8" >>boxer + 8-byte-alignment + "from_unsigned_8" >>boxer "to_unsigned_8" >>unboxer \ ulonglong define-primitive-type @@ -366,7 +377,8 @@ SYMBOLS: [ set-alien-signed-cell ] >>setter bootstrap-cell >>size bootstrap-cell >>align - "box_signed_cell" >>boxer + bootstrap-cell >>align-first + "from_signed_cell" >>boxer "to_fixnum" >>unboxer \ long define-primitive-type @@ -377,7 +389,8 @@ SYMBOLS: [ set-alien-unsigned-cell ] >>setter bootstrap-cell >>size bootstrap-cell >>align - "box_unsigned_cell" >>boxer + bootstrap-cell >>align-first + "from_unsigned_cell" >>boxer "to_cell" >>unboxer \ ulong define-primitive-type @@ -388,7 +401,8 @@ SYMBOLS: [ set-alien-signed-4 ] >>setter 4 >>size 4 >>align - "box_signed_4" >>boxer + 4 >>align-first + "from_signed_4" >>boxer "to_fixnum" >>unboxer \ int define-primitive-type @@ -399,7 +413,8 @@ SYMBOLS: [ set-alien-unsigned-4 ] >>setter 4 >>size 4 >>align - "box_unsigned_4" >>boxer + 4 >>align-first + "from_unsigned_4" >>boxer "to_cell" >>unboxer \ uint define-primitive-type @@ -410,7 +425,8 @@ SYMBOLS: [ set-alien-signed-2 ] >>setter 2 >>size 2 >>align - "box_signed_2" >>boxer + 2 >>align-first + "from_signed_2" >>boxer "to_fixnum" >>unboxer \ short define-primitive-type @@ -421,7 +437,8 @@ SYMBOLS: [ set-alien-unsigned-2 ] >>setter 2 >>size 2 >>align - "box_unsigned_2" >>boxer + 2 >>align-first + "from_unsigned_2" >>boxer "to_cell" >>unboxer \ ushort define-primitive-type @@ -432,7 +449,8 @@ SYMBOLS: [ set-alien-signed-1 ] >>setter 1 >>size 1 >>align - "box_signed_1" >>boxer + 1 >>align-first + "from_signed_1" >>boxer "to_fixnum" >>unboxer \ char define-primitive-type @@ -443,7 +461,8 @@ SYMBOLS: [ set-alien-unsigned-1 ] >>setter 1 >>size 1 >>align - "box_unsigned_1" >>boxer + 1 >>align-first + "from_unsigned_1" >>boxer "to_cell" >>unboxer \ uchar define-primitive-type @@ -453,7 +472,8 @@ SYMBOLS: [ [ >c-bool ] 2dip set-alien-unsigned-4 ] >>setter 4 >>size 4 >>align - "box_boolean" >>boxer + 4 >>align-first + "from_boolean" >>boxer "to_boolean" >>unboxer ] [ @@ -461,10 +481,11 @@ SYMBOLS: [ [ >c-bool ] 2dip set-alien-unsigned-1 ] >>setter 1 >>size 1 >>align - "box_boolean" >>boxer + 1 >>align-first + "from_boolean" >>boxer "to_boolean" >>unboxer - \ bool define-primitive-type ] if + \ bool define-primitive-type math:float >>class @@ -473,7 +494,8 @@ SYMBOLS: [ [ >float ] 2dip set-alien-float ] >>setter 4 >>size 4 >>align - "box_float" >>boxer + 4 >>align-first + "from_float" >>boxer "to_float" >>unboxer float-rep >>rep [ >float ] >>unboxer-quot @@ -485,8 +507,8 @@ SYMBOLS: [ alien-double ] >>getter [ [ >float ] 2dip set-alien-double ] >>setter 8 >>size - cpu x86.32? os windows? not and 4 8 ? >>align - "box_double" >>boxer + 8-byte-alignment + "from_double" >>boxer "to_double" >>unboxer double-rep >>rep [ >float ] >>unboxer-quot @@ -516,6 +538,9 @@ M: ulonglong-2-rep rep-component-type drop ulonglong ; M: float-4-rep rep-component-type drop float ; M: double-2-rep rep-component-type drop double ; +: rep-length ( rep -- n ) + 16 swap rep-component-type heap-size /i ; foldable + : (unsigned-interval) ( bytes -- from to ) [ 0 ] dip 8 * 2^ 1 - ; foldable : unsigned-interval ( c-type -- from to ) heap-size (unsigned-interval) ; foldable : (signed-interval) ( bytes -- from to ) 8 * 1 - 2^ [ neg ] [ 1 - ] bi ; foldable @@ -528,4 +553,6 @@ M: double-2-rep rep-component-type drop double ; { [ dup { uchar ushort uint ulong ulonglong } member-eq? ] [ unsigned-interval ] } } cond ; foldable -: c-type-clamp ( value c-type -- value' ) c-type-interval clamp ; inline +: c-type-clamp ( value c-type -- value' ) + dup { float double } member-eq? + [ drop ] [ c-type-interval clamp ] if ; inline diff --git a/basis/alien/destructors/destructors.factor b/basis/alien/destructors/destructors.factor old mode 100755 new mode 100644 diff --git a/basis/alien/libraries/libraries-docs.factor b/basis/alien/libraries/libraries-docs.factor old mode 100755 new mode 100644 diff --git a/basis/alien/libraries/libraries.factor b/basis/alien/libraries/libraries.factor old mode 100755 new mode 100644 diff --git a/basis/alien/remote-control/remote-control.factor b/basis/alien/remote-control/remote-control.factor index 6a5644cceb..ae694bed9c 100644 --- a/basis/alien/remote-control/remote-control.factor +++ b/basis/alien/remote-control/remote-control.factor @@ -19,8 +19,8 @@ IN: alien.remote-control dup optimized? [ execute ] [ drop f ] if ; inline : init-remote-control ( -- ) - \ eval-callback ?callback 16 setenv - \ yield-callback ?callback 17 setenv - \ sleep-callback ?callback 18 setenv ; + \ eval-callback ?callback 16 set-special-object + \ yield-callback ?callback 17 set-special-object + \ sleep-callback ?callback 18 set-special-object ; MAIN: init-remote-control diff --git a/basis/base64/base64.factor b/basis/base64/base64.factor index eb2c9193a3..1a0648cef8 100644 --- a/basis/base64/base64.factor +++ b/basis/base64/base64.factor @@ -13,7 +13,8 @@ ERROR: malformed-base64 ; read1 2dup swap member? [ drop read1-ignoring ] [ nip ] if ; : read-ignoring ( ignoring n -- str ) - [ drop read1-ignoring ] with map harvest + [ drop read1-ignoring ] with { } map-integers + [ { f 0 } member? not ] filter [ f ] [ >string ] if-empty ; : ch>base64 ( ch -- ch ) @@ -42,7 +43,7 @@ SYMBOL: column [ write1-lines ] each ; : encode3 ( seq -- ) - be> 4 [ + be> 4 iota [ -6 * shift HEX: 3f bitand ch>base64 write1-lines ] with each ; inline diff --git a/basis/binary-search/binary-search-tests.factor b/basis/binary-search/binary-search-tests.factor index f2ea7503f4..a797219a01 100644 --- a/basis/binary-search/binary-search-tests.factor +++ b/basis/binary-search/binary-search-tests.factor @@ -1,4 +1,4 @@ -USING: binary-search math.order vectors kernel tools.test ; +USING: binary-search math.order sequences kernel tools.test ; IN: binary-search.tests [ f ] [ 3 { } [ <=> ] with search drop ] unit-test @@ -7,7 +7,7 @@ IN: binary-search.tests [ 3 ] [ 4 { 1 2 3 4 5 6 } [ <=> ] with search drop ] unit-test [ 2 ] [ 3.5 { 1 2 3 4 5 6 7 8 } [ <=> ] with search drop ] unit-test [ 4 ] [ 5.5 { 1 2 3 4 5 6 7 8 } [ <=> ] with search drop ] unit-test -[ 10 ] [ 10 20 >vector [ <=> ] with search drop ] unit-test +[ 10 ] [ 10 20 iota [ <=> ] with search drop ] unit-test [ t ] [ "hello" { "alligator" "cat" "fish" "hello" "ikarus" "java" } sorted-member? ] unit-test [ 3 ] [ "hey" { "alligator" "cat" "fish" "hello" "ikarus" "java" } sorted-index ] unit-test diff --git a/basis/bit-arrays/bit-arrays-tests.factor b/basis/bit-arrays/bit-arrays-tests.factor index 7397791ab5..f08db68441 100644 --- a/basis/bit-arrays/bit-arrays-tests.factor +++ b/basis/bit-arrays/bit-arrays-tests.factor @@ -40,7 +40,7 @@ IN: bit-arrays.tests 100 [ drop 100 [ 2 random zero? ] replicate dup >bit-array >array = - ] all? + ] all-integers? ] unit-test [ ?{ f } ] [ diff --git a/basis/bit-arrays/bit-arrays.factor b/basis/bit-arrays/bit-arrays.factor index f5613da6b5..4fafc528fd 100644 --- a/basis/bit-arrays/bit-arrays.factor +++ b/basis/bit-arrays/bit-arrays.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2007, 2008 Slava Pestov. +! Copyright (C) 2007, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: alien.c-types alien.data accessors math alien.accessors kernel kernel.private sequences sequences.private byte-arrays @@ -25,7 +25,7 @@ TUPLE: bit-array : (set-bits) ( bit-array n -- ) [ [ length bits>cells ] keep ] dip swap underlying>> - '[ 2 shift [ _ _ ] dip set-alien-unsigned-4 ] each ; inline + '[ 2 shift [ _ _ ] dip set-alien-unsigned-4 ] each-integer ; inline : clean-up ( bit-array -- ) ! Zero bits after the end. @@ -99,7 +99,7 @@ SYNTAX: ?{ \ } [ >bit-array ] parse-literal ; ] if ; : bit-array>integer ( bit-array -- n ) - 0 swap underlying>> dup length [ + 0 swap underlying>> dup length iota [ alien-unsigned-1 swap 8 shift bitor ] with each ; diff --git a/basis/bit-vectors/bit-vectors-tests.factor b/basis/bit-vectors/bit-vectors-tests.factor index 5af44b59f7..a8a856ffd0 100644 --- a/basis/bit-vectors/bit-vectors-tests.factor +++ b/basis/bit-vectors/bit-vectors-tests.factor @@ -4,7 +4,7 @@ IN: bit-vectors.tests [ 0 ] [ 123 length ] unit-test : do-it ( seq -- ) - 1234 swap [ [ even? ] dip push ] curry each ; + 1234 swap [ [ even? ] dip push ] curry each-integer ; [ t ] [ 3 dup do-it diff --git a/basis/bootstrap/bootstrap-error.factor b/basis/bootstrap/bootstrap-error.factor index 01eb002e44..7cae86b186 100644 --- a/basis/bootstrap/bootstrap-error.factor +++ b/basis/bootstrap/bootstrap-error.factor @@ -2,7 +2,8 @@ USING: continuations kernel io debugger vocabs words system namespaces ; :c :error + "listener" vocab [ restarts. vocab-main execute ] -[ die ] if* +[ error get die ] if* 1 exit diff --git a/basis/bootstrap/compiler/compiler.factor b/basis/bootstrap/compiler/compiler.factor old mode 100755 new mode 100644 index 3b7848251b..2d0613a7f5 --- a/basis/bootstrap/compiler/compiler.factor +++ b/basis/bootstrap/compiler/compiler.factor @@ -76,7 +76,7 @@ gc "." write flush { - + 2/ < <= > >= shift + + * 2/ < <= > >= shift } compile-unoptimized "." write flush diff --git a/basis/bootstrap/finish-bootstrap.factor b/basis/bootstrap/finish-bootstrap.factor index ab08aa87a9..70ccaedad4 100644 --- a/basis/bootstrap/finish-bootstrap.factor +++ b/basis/bootstrap/finish-bootstrap.factor @@ -3,7 +3,7 @@ namespaces eval kernel vocabs.loader io ; [ boot - do-init-hooks + do-startup-hooks [ (command-line) parse-command-line load-vocab-roots @@ -14,4 +14,4 @@ namespaces eval kernel vocabs.loader io ; output-stream get [ stream-flush ] when* 0 exit ] [ print-error 1 exit ] recover -] set-boot-quot +] set-startup-quot diff --git a/basis/bootstrap/finish-staging.factor b/basis/bootstrap/finish-staging.factor index 49f504fd41..4512d84053 100644 --- a/basis/bootstrap/finish-staging.factor +++ b/basis/bootstrap/finish-staging.factor @@ -1,11 +1,10 @@ -USING: init command-line system namespaces kernel vocabs.loader -io ; +USING: init command-line system namespaces kernel vocabs.loader io ; [ boot - do-init-hooks + do-startup-hooks (command-line) parse-command-line "run" get run output-stream get [ stream-flush ] when* 0 exit -] set-boot-quot +] set-startup-quot diff --git a/basis/bootstrap/image/image.factor b/basis/bootstrap/image/image.factor index 2178b5d4cb..90b4c3ae6f 100644 --- a/basis/bootstrap/image/image.factor +++ b/basis/bootstrap/image/image.factor @@ -1,6 +1,6 @@ -! Copyright (C) 2004, 2009 Slava Pestov. +! Copyright (C) 2004, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: alien arrays byte-arrays generic hashtables +USING: alien alien.strings arrays byte-arrays generic hashtables hashtables.private io io.binary io.files io.encodings.binary io.pathnames kernel kernel.private math namespaces make parser prettyprint sequences strings sbufs vectors words quotations @@ -10,7 +10,7 @@ vocabs.loader source-files definitions debugger quotations.private combinators combinators.short-circuit math.order math.private accessors slots.private generic.single.private compiler.units compiler.constants fry -bootstrap.image.syntax ; +locals bootstrap.image.syntax generalizations ; IN: bootstrap.image : arch ( os cpu -- arch ) @@ -71,6 +71,9 @@ C: eq-wrapper M: eq-wrapper equal? over eq-wrapper? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ; +M: eq-wrapper hashcode* + nip obj>> identity-hashcode ; + SYMBOL: objects : cache-eql-object ( obj quot -- value ) @@ -90,7 +93,7 @@ CONSTANT: image-version 4 CONSTANT: data-base 1024 -CONSTANT: userenv-size 70 +CONSTANT: special-objects-size 70 CONSTANT: header-size 10 @@ -104,31 +107,62 @@ SYMBOL: sub-primitives SYMBOL: jit-relocations -: compute-offset ( rc -- offset ) - [ building get length ] dip rc-absolute-cell = bootstrap-cell 4 ? - ; +SYMBOL: jit-offset + +: compute-offset ( -- offset ) + building get length jit-offset get + ; : jit-rel ( rc rt -- ) - over compute-offset 3array jit-relocations get push-all ; + compute-offset 3array jit-relocations get push-all ; + +SYMBOL: jit-parameters + +: jit-parameter ( parameter -- ) + jit-parameters get push ; SYMBOL: jit-literals : jit-literal ( literal -- ) jit-literals get push ; -: make-jit ( quot -- jit-literals jit-data ) +: jit-vm ( offset rc -- ) + [ jit-parameter ] dip rt-vm jit-rel ; + +: jit-dlsym ( name library rc -- ) + rt-dlsym jit-rel [ string>symbol jit-parameter ] bi@ ; + +:: jit-conditional ( test-quot false-quot -- ) + [ 0 test-quot call ] B{ } make length :> len + building get length jit-offset get + len + + [ jit-offset set false-quot call ] B{ } make + [ length test-quot call ] [ % ] bi ; inline + +: make-jit ( quot -- jit-parameters jit-literals jit-code ) [ + 0 jit-offset set + V{ } clone jit-parameters set V{ } clone jit-literals set V{ } clone jit-relocations set call( -- ) + jit-parameters get >array jit-literals get >array jit-relocations get >array ] B{ } make prefix ; : jit-define ( quot name -- ) - [ make-jit nip ] dip set ; + [ make-jit 2nip ] dip set ; : define-sub-primitive ( quot word -- ) - [ make-jit 2array ] dip sub-primitives get set-at ; + [ make-jit 3array ] dip sub-primitives get set-at ; + +: define-combinator-primitive ( quot non-tail-quot tail-quot word -- ) + [ + [ make-jit ] + [ make-jit 2nip ] + [ make-jit 2nip ] + tri* 5 narray + ] dip + sub-primitives get set-at ; ! The image being constructed; a vector of word-size integers SYMBOL: image @@ -142,57 +176,58 @@ SYMBOL: architecture RESET ! Boot quotation, set in stage1.factor -USERENV: bootstrap-boot-quot 20 +SPECIAL-OBJECT: bootstrap-startup-quot 20 ! Bootstrap global namesapce -USERENV: bootstrap-global 21 +SPECIAL-OBJECT: bootstrap-global 21 ! JIT parameters -USERENV: jit-prolog 23 -USERENV: jit-primitive-word 24 -USERENV: jit-primitive 25 -USERENV: jit-word-jump 26 -USERENV: jit-word-call 27 -USERENV: jit-word-special 28 -USERENV: jit-if-word 29 -USERENV: jit-if 30 -USERENV: jit-epilog 31 -USERENV: jit-return 32 -USERENV: jit-profiling 33 -USERENV: jit-push-immediate 34 -USERENV: jit-dip-word 35 -USERENV: jit-dip 36 -USERENV: jit-2dip-word 37 -USERENV: jit-2dip 38 -USERENV: jit-3dip-word 39 -USERENV: jit-3dip 40 -USERENV: jit-execute-word 41 -USERENV: jit-execute-jump 42 -USERENV: jit-execute-call 43 -USERENV: jit-declare-word 44 +SPECIAL-OBJECT: jit-prolog 23 +SPECIAL-OBJECT: jit-primitive-word 24 +SPECIAL-OBJECT: jit-primitive 25 +SPECIAL-OBJECT: jit-word-jump 26 +SPECIAL-OBJECT: jit-word-call 27 +SPECIAL-OBJECT: jit-if-word 28 +SPECIAL-OBJECT: jit-if 29 +SPECIAL-OBJECT: jit-epilog 30 +SPECIAL-OBJECT: jit-return 31 +SPECIAL-OBJECT: jit-profiling 32 +SPECIAL-OBJECT: jit-push 33 +SPECIAL-OBJECT: jit-dip-word 34 +SPECIAL-OBJECT: jit-dip 35 +SPECIAL-OBJECT: jit-2dip-word 36 +SPECIAL-OBJECT: jit-2dip 37 +SPECIAL-OBJECT: jit-3dip-word 38 +SPECIAL-OBJECT: jit-3dip 39 +SPECIAL-OBJECT: jit-execute 40 +SPECIAL-OBJECT: jit-declare-word 41 -USERENV: callback-stub 45 +SPECIAL-OBJECT: c-to-factor-word 42 +SPECIAL-OBJECT: lazy-jit-compile-word 43 +SPECIAL-OBJECT: unwind-native-frames-word 44 + +SPECIAL-OBJECT: callback-stub 48 ! PIC stubs -USERENV: pic-load 47 -USERENV: pic-tag 48 -USERENV: pic-tuple 49 -USERENV: pic-check-tag 50 -USERENV: pic-check-tuple 51 -USERENV: pic-hit 52 -USERENV: pic-miss-word 53 -USERENV: pic-miss-tail-word 54 +SPECIAL-OBJECT: pic-load 49 +SPECIAL-OBJECT: pic-tag 50 +SPECIAL-OBJECT: pic-tuple 51 +SPECIAL-OBJECT: pic-check-tag 52 +SPECIAL-OBJECT: pic-check-tuple 53 +SPECIAL-OBJECT: pic-hit 54 +SPECIAL-OBJECT: pic-miss-word 55 +SPECIAL-OBJECT: pic-miss-tail-word 56 ! Megamorphic dispatch -USERENV: mega-lookup 57 -USERENV: mega-lookup-word 58 -USERENV: mega-miss-word 59 +SPECIAL-OBJECT: mega-lookup 57 +SPECIAL-OBJECT: mega-lookup-word 58 +SPECIAL-OBJECT: mega-miss-word 59 ! Default definition for undefined words -USERENV: undefined-quot 60 +SPECIAL-OBJECT: undefined-quot 60 -: userenv-offset ( symbol -- n ) - userenvs get at header-size + ; +: special-object-offset ( symbol -- n ) + special-objects get at header-size + ; : emit ( cell -- ) image get push ; @@ -208,7 +243,7 @@ USERENV: undefined-quot 60 : fixup ( value offset -- ) image get set-nth ; : heap-size ( -- size ) - image get length header-size - userenv-size - + image get length header-size - special-objects-size - bootstrap-cells ; : here ( -- size ) heap-size data-base + ; @@ -224,9 +259,11 @@ USERENV: undefined-quot 60 : emit-fixnum ( n -- ) tag-fixnum emit ; +: emit-header ( n -- ) tag-header emit ; + : emit-object ( class quot -- addr ) [ type-number ] dip over here-as - [ swap tag-fixnum emit call align-here ] dip ; + [ swap emit-header call align-here ] dip ; inline ! Write an object to the image. @@ -234,7 +271,7 @@ GENERIC: ' ( obj -- ptr ) ! Image header -: emit-header ( -- ) +: emit-image-header ( -- ) image-magic emit image-version emit data-base emit ! relocation base at end of header @@ -245,10 +282,10 @@ GENERIC: ' ( obj -- ptr ) 0 emit ! pointer to bignum 0 0 emit ! pointer to bignum 1 0 emit ! pointer to bignum -1 - userenv-size [ f ' emit ] times ; + special-objects-size [ f ' emit ] times ; -: emit-userenv ( symbol -- ) - [ get ' ] [ userenv-offset ] bi fixup ; +: emit-special-object ( symbol -- ) + [ get ' ] [ special-object-offset ] bi fixup ; ! Bignums @@ -501,16 +538,18 @@ M: quotation ' \ dip jit-dip-word set \ 2dip jit-2dip-word set \ 3dip jit-3dip-word set - \ (execute) jit-execute-word set - \ inline-cache-miss \ pic-miss-word set - \ inline-cache-miss-tail \ pic-miss-tail-word set - \ mega-cache-lookup \ mega-lookup-word set - \ mega-cache-miss \ mega-miss-word set + \ inline-cache-miss pic-miss-word set + \ inline-cache-miss-tail pic-miss-tail-word set + \ mega-cache-lookup mega-lookup-word set + \ mega-cache-miss mega-miss-word set \ declare jit-declare-word set + \ c-to-factor c-to-factor-word set + \ lazy-jit-compile lazy-jit-compile-word set + \ unwind-native-frames unwind-native-frames-word set [ undefined ] undefined-quot set ; -: emit-userenvs ( -- ) - userenvs get keys [ emit-userenv ] each ; +: emit-special-objects ( -- ) + special-objects get keys [ emit-special-object ] each ; : fixup-header ( -- ) heap-size data-heap-size-offset fixup ; @@ -518,7 +557,7 @@ M: quotation ' : build-image ( -- image ) 800000 image set 20000 objects set - emit-header t, 0, 1, -1, + emit-image-header t, 0, 1, -1, "Building generic words..." print flush remake-generics "Serializing words..." print flush @@ -527,8 +566,8 @@ M: quotation ' emit-jit-data "Serializing global namespace..." print flush emit-global - "Serializing user environment..." print flush - emit-userenvs + "Serializing special object table..." print flush + emit-special-objects "Performing word fixups..." print flush fixup-words "Performing header fixups..." print flush diff --git a/basis/bootstrap/image/syntax/syntax.factor b/basis/bootstrap/image/syntax/syntax.factor index 29dc09717a..7025cd61e1 100644 --- a/basis/bootstrap/image/syntax/syntax.factor +++ b/basis/bootstrap/image/syntax/syntax.factor @@ -1,14 +1,14 @@ -! Copyright (C) 2009 Slava Pestov. +! Copyright (C) 2009, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: parser kernel namespaces assocs words.symbol ; IN: bootstrap.image.syntax -SYMBOL: userenvs +SYMBOL: special-objects -SYNTAX: RESET H{ } clone userenvs set-global ; +SYNTAX: RESET H{ } clone special-objects set-global ; -SYNTAX: USERENV: +SYNTAX: SPECIAL-OBJECT: CREATE-WORD scan-word - [ swap userenvs get set-at ] + [ swap special-objects get set-at ] [ drop define-symbol ] 2bi ; \ No newline at end of file diff --git a/basis/bootstrap/stage2.factor b/basis/bootstrap/stage2.factor index 0b517c0e66..98b6a472ed 100644 --- a/basis/bootstrap/stage2.factor +++ b/basis/bootstrap/stage2.factor @@ -35,8 +35,8 @@ SYMBOL: bootstrap-time : count-words ( pred -- ) all-words swap count number>string write ; inline -: print-time ( ms -- ) - 1000 /i +: print-time ( us -- ) + 1,000,000,000 /i 60 /mod swap number>string write " minutes and " write number>string write " seconds." print ; @@ -56,9 +56,10 @@ SYMBOL: bootstrap-time error-continuation set-global error set-global ; inline + [ ! We time bootstrap - millis + nano-count default-image-name "output-image" set-global @@ -83,14 +84,14 @@ SYMBOL: bootstrap-time load-components - millis over - core-bootstrap-time set-global + nano-count over - core-bootstrap-time set-global run-bootstrap-init f error set-global f error-continuation set-global - millis swap - bootstrap-time set-global + nano-count swap - bootstrap-time set-global print-report "deploy-vocab" get [ diff --git a/basis/bootstrap/ui/ui.factor b/basis/bootstrap/ui/ui.factor old mode 100755 new mode 100644 diff --git a/basis/cairo/cairo.factor b/basis/cairo/cairo.factor old mode 100755 new mode 100644 index 074798a1b2..38398ae228 --- a/basis/cairo/cairo.factor +++ b/basis/cairo/cairo.factor @@ -16,7 +16,7 @@ ERROR: cairo-error message ; : check-surface ( surface -- ) cairo_surface_status (check-cairo) ; -: width>stride ( width -- stride ) "uint" heap-size * ; inline +: width>stride ( width -- stride ) uint heap-size * ; inline : ( data dim -- surface ) [ CAIRO_FORMAT_ARGB32 ] dip first2 over width>stride diff --git a/basis/calendar/calendar-docs.factor b/basis/calendar/calendar-docs.factor index 8cb1e751b2..616c4d2c2c 100644 --- a/basis/calendar/calendar-docs.factor +++ b/basis/calendar/calendar-docs.factor @@ -32,7 +32,7 @@ HELP: month-names { $warning "Do not use this array for looking up a month name directly. Use month-name instead." } ; HELP: month-name -{ $values { "n" integer } { "string" string } } +{ $values { "obj" { $or integer timestamp } } { "string" string } } { $description "Looks up the month name and returns it as a string. January has an index of 1 instead of zero." } ; HELP: month-abbreviations @@ -46,11 +46,11 @@ HELP: month-abbreviation HELP: day-names -{ $values { "array" array } } +{ $values { "value" array } } { $description "Returns an array with the English names of the days of the week." } ; HELP: day-name -{ $values { "n" integer } { "string" string } } +{ $values { "obj" { $or integer timestamp } } { "string" string } } { $description "Looks up the day name and returns it as a string." } ; HELP: day-abbreviations2 @@ -355,7 +355,7 @@ HELP: before HELP: { $values { "timestamp" timestamp } } -{ $description "Outputs a zero timestamp that consists of zeros for every slot. Used to see if timestamps are valid." } ; +{ $description "Returns a zero timestamp that consists of zeros for every slot. Used to see if timestamps are valid." } ; HELP: valid-timestamp? { $values { "timestamp" timestamp } { "?" "a boolean" } } @@ -363,7 +363,7 @@ HELP: valid-timestamp? HELP: unix-1970 { $values { "timestamp" timestamp } } -{ $description "Outputs the beginning of UNIX time, or midnight, January 1, 1970." } ; +{ $description "Returns the beginning of UNIX time, or midnight, January 1, 1970." } ; HELP: micros>timestamp { $values { "x" number } { "timestamp" timestamp } } @@ -377,13 +377,13 @@ HELP: micros>timestamp HELP: gmt { $values { "timestamp" timestamp } } -{ $description "Outputs the time right now, but in the GMT timezone." } ; +{ $description "Returns the time right now, but in the GMT timezone." } ; { gmt now } related-words HELP: now { $values { "timestamp" timestamp } } -{ $description "Outputs the time right now in your computer's timezone." } +{ $description "Returns the time right now in your computer's timezone." } { $examples { $unchecked-example "USING: calendar prettyprint ;" "now ." @@ -490,23 +490,23 @@ HELP: saturday HELP: midnight { $values { "timestamp" timestamp } { "new-timestamp" timestamp } } -{ $description "Returns a timestamp that represents today at midnight, or the beginning of the day." } ; +{ $description "Returns a new timestamp that represents today at midnight, or the beginning of the day." } ; HELP: noon { $values { "timestamp" timestamp } { "new-timestamp" timestamp } } -{ $description "Returns a timestamp that represents today at noon, or the middle of the day." } ; +{ $description "Returns a new timestamp that represents today at noon, or the middle of the day." } ; HELP: beginning-of-month { $values { "timestamp" timestamp } { "new-timestamp" timestamp } } -{ $description "Outputs a timestamp with the day set to one." } ; +{ $description "Returns a new timestamp with the day set to one." } ; HELP: beginning-of-week { $values { "timestamp" timestamp } { "new-timestamp" timestamp } } -{ $description "Outputs a timestamp where the day of the week is Sunday." } ; +{ $description "Returns a new timestamp where the day of the week is Sunday." } ; HELP: beginning-of-year -{ $values { "timestamp" timestamp } { "new-timestamp" timestamp } } -{ $description "Outputs a timestamp with the month and day set to one, or January 1 of the input timestamp." } ; +{ $values { "object" object } { "new-timestamp" timestamp } } +{ $description "Returns a new timestamp with the month and day set to one, or January 1 of the input timestamp, given a year or a timestamp." } ; HELP: time-since-midnight { $values { "timestamp" timestamp } { "duration" duration } } diff --git a/basis/calendar/calendar-tests.factor b/basis/calendar/calendar-tests.factor index 8d1071122d..2490b87c37 100644 --- a/basis/calendar/calendar-tests.factor +++ b/basis/calendar/calendar-tests.factor @@ -1,5 +1,6 @@ USING: arrays calendar kernel math sequences tools.test -continuations system math.order threads accessors ; +continuations system math.order threads accessors +random ; IN: calendar.tests [ f ] [ 2004 12 32 0 0 0 instant valid-timestamp? ] unit-test @@ -139,7 +140,7 @@ IN: calendar.tests [ +gt+ ] [ 2005 1 1 12 30 0 instant 2004 1 1 13 30 0 instant <=> ] unit-test -[ t ] [ now timestamp>micros micros - 1000000 < ] unit-test +[ t ] [ now timestamp>micros system-micros - 1000000 < ] unit-test [ t ] [ 0 micros>timestamp unix-1970 = ] unit-test [ t ] [ 123456789000000 [ micros>timestamp timestamp>micros ] keep = ] unit-test [ t ] [ 123456789123456000 [ micros>timestamp timestamp>micros ] keep = ] unit-test @@ -170,3 +171,8 @@ IN: calendar.tests [ f ] [ now dup midnight eq? ] unit-test [ f ] [ now dup easter eq? ] unit-test [ f ] [ now dup beginning-of-year eq? ] unit-test + +[ t ] [ 1325376000 unix-time>timestamp 2012 = ] unit-test +[ t ] [ 1356998399 unix-time>timestamp 2013 1 seconds time- = ] unit-test + +[ t ] [ 1500000000 random [ unix-time>timestamp timestamp>unix-time ] keep = ] unit-test diff --git a/basis/calendar/calendar.factor b/basis/calendar/calendar.factor index 0378e2701e..3940af4856 100644 --- a/basis/calendar/calendar.factor +++ b/basis/calendar/calendar.factor @@ -17,6 +17,8 @@ TUPLE: duration C: duration +: instant ( -- duration ) 0 0 0 0 0 0 ; + TUPLE: timestamp { year integer } { month integer } @@ -34,6 +36,15 @@ C: timestamp : ( year month day -- timestamp ) 0 0 0 gmt-offset-duration ; +: ( year month day -- timestamp ) + 0 0 0 instant ; + +: ( year -- timestamp ) + 1 1 ; + +: ( year -- timestamp ) + 1 1 ; + ERROR: not-a-month ; M: not-a-month summary drop "Months are indexed starting at 1" ; @@ -51,8 +62,16 @@ CONSTANT: month-names "July" "August" "September" "October" "November" "December" } -: month-name ( n -- string ) - check-month 1 - month-names nth ; + + +GENERIC: month-name ( obj -- string ) + +M: integer month-name check-month 1 - month-names nth ; +M: timestamp month-name month>> 1 - month-names nth ; CONSTANT: month-abbreviations { @@ -65,12 +84,8 @@ CONSTANT: month-abbreviations CONSTANT: day-counts { 0 31 28 31 30 31 30 31 31 30 31 30 31 } -: day-names ( -- array ) - { - "Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" - } ; - -: day-name ( n -- string ) day-names nth ; +CONSTANT: day-names + { "Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" } CONSTANT: day-abbreviations2 { "Su" "Mo" "Tu" "We" "Th" "Fr" "Sa" } @@ -128,8 +143,7 @@ GENERIC: easter ( obj -- obj' ) 32 2 e * + 2 i * + h - k - 7 mod :> l a 11 h * + 22 l * + 451 /i :> m - h l + 7 m * - 114 + 31 /mod 1 + :> ( month day ) - month day ; + h l + 7 m * - 114 + 31 /mod 1 + ; M: integer easter ( year -- timestamp ) dup easter-month-day ; @@ -145,7 +159,6 @@ M: timestamp easter ( timestamp -- timestamp ) : >time< ( timestamp -- hour minute second ) [ hour>> ] [ minute>> ] [ second>> ] tri ; -: instant ( -- duration ) 0 0 0 0 0 0 ; : years ( x -- duration ) instant clone swap >>year ; : months ( x -- duration ) instant clone swap >>month ; : days ( x -- duration ) instant clone swap >>day ; @@ -157,6 +170,18 @@ M: timestamp easter ( timestamp -- timestamp ) : microseconds ( x -- duration ) 1000000 / seconds ; : nanoseconds ( x -- duration ) 1000000000 / seconds ; +GENERIC: year ( obj -- n ) +M: integer year ; +M: timestamp year year>> ; + +GENERIC: month ( obj -- n ) +M: integer month ; +M: timestamp month month>> ; + +GENERIC: day ( obj -- n ) +M: integer day ; +M: timestamp day day>> ; + GENERIC: leap-year? ( obj -- ? ) M: integer leap-year? ( year -- ? ) @@ -305,6 +330,9 @@ GENERIC: time- ( time1 time2 -- time3 ) M: timestamp <=> ( ts1 ts2 -- n ) [ >gmt tuple-slots ] compare ; +: same-day? ( ts1 ts2 -- ? ) + [ >gmt >date< ] bi@ = ; + : (time-) ( timestamp timestamp -- n ) [ >gmt ] bi@ [ [ >date< julian-day-number ] bi@ - 86400 * ] 2keep @@ -357,7 +385,7 @@ M: duration time- : gmt ( -- timestamp ) #! GMT time, right now - unix-1970 micros microseconds time+ ; + unix-1970 system-micros microseconds time+ ; : now ( -- timestamp ) gmt >local-time ; : hence ( duration -- timestamp ) now swap time+ ; @@ -387,6 +415,10 @@ M: timestamp days-in-year ( timestamp -- n ) year>> days-in-year ; : day-of-week ( timestamp -- n ) >date< zeller-congruence ; +GENERIC: day-name ( obj -- string ) +M: integer day-name day-names nth ; +M: timestamp day-name day-of-week day-names nth ; + :: (day-of-year) ( year month day -- n ) day-counts month head-slice sum day + year leap-year? [ @@ -398,22 +430,6 @@ M: timestamp days-in-year ( timestamp -- n ) year>> days-in-year ; : day-of-year ( timestamp -- n ) >date< (day-of-year) ; - - -: sunday ( timestamp -- new-timestamp ) 0 day-this-week ; -: monday ( timestamp -- new-timestamp ) 1 day-this-week ; -: tuesday ( timestamp -- new-timestamp ) 2 day-this-week ; -: wednesday ( timestamp -- new-timestamp ) 3 day-this-week ; -: thursday ( timestamp -- new-timestamp ) 4 day-this-week ; -: friday ( timestamp -- new-timestamp ) 5 day-this-week ; -: saturday ( timestamp -- new-timestamp ) 6 day-this-week ; - : midnight ( timestamp -- new-timestamp ) clone 0 >>hour 0 >>minute 0 >>second ; inline @@ -423,11 +439,108 @@ PRIVATE> : beginning-of-month ( timestamp -- new-timestamp ) midnight 1 >>day ; +: end-of-month ( timestamp -- new-timestamp ) + [ midnight ] [ days-in-month ] bi >>day ; + +> ] bi@ = [ 1 weeks time+ ] unless + n 1 - [ weeks time+ ] unless-zero ; + +: last-day-this-month ( timestamp day -- new-timestamp ) + [ 1 months time+ 1 ] dip nth-day-this-month 1 weeks time- ; + +PRIVATE> + +GENERIC: january ( obj -- timestamp ) +GENERIC: february ( obj -- timestamp ) +GENERIC: march ( obj -- timestamp ) +GENERIC: april ( obj -- timestamp ) +GENERIC: may ( obj -- timestamp ) +GENERIC: june ( obj -- timestamp ) +GENERIC: july ( obj -- timestamp ) +GENERIC: august ( obj -- timestamp ) +GENERIC: september ( obj -- timestamp ) +GENERIC: october ( obj -- timestamp ) +GENERIC: november ( obj -- timestamp ) +GENERIC: december ( obj -- timestamp ) + +M: integer january 1 1 ; +M: integer february 2 1 ; +M: integer march 3 1 ; +M: integer april 4 1 ; +M: integer may 5 1 ; +M: integer june 6 1 ; +M: integer july 7 1 ; +M: integer august 8 1 ; +M: integer september 9 1 ; +M: integer october 10 1 ; +M: integer november 11 1 ; +M: integer december 12 1 ; + +M: timestamp january clone 1 >>month ; +M: timestamp february clone 2 >>month ; +M: timestamp march clone 3 >>month ; +M: timestamp april clone 4 >>month ; +M: timestamp may clone 5 >>month ; +M: timestamp june clone 6 >>month ; +M: timestamp july clone 7 >>month ; +M: timestamp august clone 8 >>month ; +M: timestamp september clone 9 >>month ; +M: timestamp october clone 10 >>month ; +M: timestamp november clone 11 >>month ; +M: timestamp december clone 12 >>month ; + +: sunday ( timestamp -- new-timestamp ) 0 day-this-week ; +: monday ( timestamp -- new-timestamp ) 1 day-this-week ; +: tuesday ( timestamp -- new-timestamp ) 2 day-this-week ; +: wednesday ( timestamp -- new-timestamp ) 3 day-this-week ; +: thursday ( timestamp -- new-timestamp ) 4 day-this-week ; +: friday ( timestamp -- new-timestamp ) 5 day-this-week ; +: saturday ( timestamp -- new-timestamp ) 6 day-this-week ; + +: sunday? ( timestamp -- ? ) day-of-week 0 = ; +: monday? ( timestamp -- ? ) day-of-week 1 = ; +: tuesday? ( timestamp -- ? ) day-of-week 2 = ; +: wednesday? ( timestamp -- ? ) day-of-week 3 = ; +: thursday? ( timestamp -- ? ) day-of-week 4 = ; +: friday? ( timestamp -- ? ) day-of-week 5 = ; +: saturday? ( timestamp -- ? ) day-of-week 6 = ; + +: sunday-of-month ( timestamp n -- new-timestamp ) 0 nth-day-this-month ; +: monday-of-month ( timestamp n -- new-timestamp ) 1 nth-day-this-month ; +: tuesday-of-month ( timestamp n -- new-timestamp ) 2 nth-day-this-month ; +: wednesday-of-month ( timestamp n -- new-timestamp ) 3 nth-day-this-month ; +: thursday-of-month ( timestamp n -- new-timestamp ) 4 nth-day-this-month ; +: friday-of-month ( timestamp n -- new-timestamp ) 5 nth-day-this-month ; +: saturday-of-month ( timestamp n -- new-timestamp ) 6 nth-day-this-month ; + +: last-sunday-of-month ( timestamp -- new-timestamp ) 0 last-day-this-month ; +: last-monday-of-month ( timestamp -- new-timestamp ) 1 last-day-this-month ; +: last-tuesday-of-month ( timestamp -- new-timestamp ) 2 last-day-this-month ; +: last-wednesday-of-month ( timestamp -- new-timestamp ) 3 last-day-this-month ; +: last-thursday-of-month ( timestamp -- new-timestamp ) 4 last-day-this-month ; +: last-friday-of-month ( timestamp -- new-timestamp ) 5 last-day-this-month ; +: last-saturday-of-month ( timestamp -- new-timestamp ) 6 last-day-this-month ; + : beginning-of-week ( timestamp -- new-timestamp ) midnight sunday ; -: beginning-of-year ( timestamp -- new-timestamp ) - beginning-of-month 1 >>month ; +GENERIC: beginning-of-year ( object -- new-timestamp ) +M: timestamp beginning-of-year beginning-of-month 1 >>month ; +M: integer beginning-of-year ; + +GENERIC: end-of-year ( object -- new-timestamp ) +M: timestamp end-of-year 12 >>month 31 >>day ; +M: integer end-of-year 12 31 ; : time-since-midnight ( timestamp -- duration ) dup midnight time- ; @@ -435,9 +548,14 @@ PRIVATE> : since-1970 ( duration -- timestamp ) unix-1970 time+ >local-time ; -M: timestamp sleep-until timestamp>micros sleep-until ; +: timestamp>unix-time ( timestamp -- seconds ) + unix-1970 time- second>> ; -M: duration sleep hence sleep-until ; +: unix-time>timestamp ( seconds -- timestamp ) + seconds unix-1970 time+ ; + +M: duration sleep + duration>nanoseconds >integer nano-count + sleep-until ; { { [ os unix? ] [ "calendar.unix" ] } diff --git a/basis/calendar/format/format.factor b/basis/calendar/format/format.factor index d07d74722a..96d76d0ce8 100644 --- a/basis/calendar/format/format.factor +++ b/basis/calendar/format/format.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov, Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: math math.order math.parser math.functions kernel sequences io accessors arrays io.streams.string splitting @@ -70,7 +70,7 @@ M: array month. ( pair -- ) [ [ 1 + day. ] keep 1 + + 7 mod zero? [ nl ] [ bl ] if - ] with each nl ; + ] with each-integer nl ; M: timestamp month. ( timestamp -- ) [ year>> ] [ month>> ] bi 2array month. ; @@ -78,7 +78,7 @@ M: timestamp month. ( timestamp -- ) GENERIC: year. ( obj -- ) M: integer year. ( n -- ) - 12 [ 1 + 2array month. nl ] with each ; + 12 [ 1 + 2array month. nl ] with each-integer ; M: timestamp year. ( timestamp -- ) year>> year. ; diff --git a/basis/calendar/model/model.factor b/basis/calendar/model/model.factor index 8665cc22ce..38ad986952 100644 --- a/basis/calendar/model/model.factor +++ b/basis/calendar/model/model.factor @@ -16,4 +16,4 @@ SYMBOL: time ] "Time model update" spawn drop ; f time set-global -[ time-thread ] "calendar.model" add-init-hook +[ time-thread ] "calendar.model" add-startup-hook diff --git a/basis/calendar/unix/unix.factor b/basis/calendar/unix/unix.factor index 28e54b89fb..ac72385d8c 100644 --- a/basis/calendar/unix/unix.factor +++ b/basis/calendar/unix/unix.factor @@ -14,6 +14,9 @@ IN: calendar.unix : timespec>seconds ( timespec -- seconds ) [ sec>> seconds ] [ nsec>> nanoseconds ] bi time+ ; +: timespec>nanoseconds ( timespec -- seconds ) + [ sec>> 1000000000 * ] [ nsec>> ] bi + ; + : timespec>unix-time ( timespec -- timestamp ) timespec>seconds since-1970 ; diff --git a/basis/channels/remote/remote.factor b/basis/channels/remote/remote.factor index 0a88875544..4eab29fd81 100644 --- a/basis/channels/remote/remote.factor +++ b/basis/channels/remote/remote.factor @@ -69,4 +69,4 @@ M: remote-channel from ( remote-channel -- value ) [ H{ } clone \ remote-channels set-global start-channel-node -] "channel-registry" add-init-hook +] "channel-registry" add-startup-hook diff --git a/basis/checksums/hmac/hmac-tests.factor b/basis/checksums/hmac/hmac-tests.factor old mode 100755 new mode 100644 diff --git a/basis/checksums/hmac/hmac.factor b/basis/checksums/hmac/hmac.factor old mode 100755 new mode 100644 diff --git a/basis/checksums/sha/sha.factor b/basis/checksums/sha/sha.factor index 35262bb0b0..ba85add03c 100644 --- a/basis/checksums/sha/sha.factor +++ b/basis/checksums/sha/sha.factor @@ -301,7 +301,7 @@ GENERIC: pad-initial-bytes ( string sha2 -- padded-string ) M cloned-H sha2 T1-256 cloned-H T2-256 cloned-H update-H - ] each + ] each-integer sha2 [ cloned-H [ w+ ] 2map ] change-H drop ; inline M: sha2-short checksum-block @@ -391,7 +391,7 @@ M: sha-256 checksum-stream ( stream checksum -- byte-array ) b H nth-unsafe 30 bitroll-32 c H set-nth-unsafe a H nth-unsafe b H set-nth-unsafe a H set-nth-unsafe - ] each + ] each-integer state [ H [ w+ ] 2map ] change-H drop ; inline M:: sha1-state checksum-block ( bytes state -- ) diff --git a/basis/circular/circular-docs.factor b/basis/circular/circular-docs.factor index 8abadfadd2..93d137d626 100644 --- a/basis/circular/circular-docs.factor +++ b/basis/circular/circular-docs.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: help.markup help.syntax io.streams.string sequences -math kernel ; +math kernel quotations ; IN: circular HELP: @@ -33,12 +33,12 @@ HELP: circular HELP: growing-circular { $description "A circular sequence that is growable." } ; -HELP: push-circular +HELP: circular-push { $values { "elt" object } { "circular" circular } } { $description "Pushes an element to a " { $link circular } " object." } ; -HELP: push-growing-circular +HELP: growing-circular-push { $values { "elt" object } { "circular" circular } } { $description "Pushes an element onto a " { $link growing-circular } " object." } ; @@ -48,6 +48,13 @@ HELP: rotate-circular { "circular" circular } } { $description "Advances the start index of a circular object by one." } ; +HELP: circular-while +{ $values + { "circular" circular } + { "quot" quotation } +} +{ $description "Calls " { $snippet "quot" } " on each element of the sequence until each call yields " { $link f } " in succession." } ; + ARTICLE: "circular" "Circular sequences" "The " { $vocab-link "circular" } " vocabulary implements the " { $link "sequence-protocol" } " to allow an arbitrary start index and wrap-around indexing." $nl "Creating a new circular object:" @@ -63,8 +70,10 @@ ARTICLE: "circular" "Circular sequences" } "Pushing new elements:" { $subsections - push-circular - push-growing-circular -} ; + circular-push + growing-circular-push +} +"Iterating over a circular until a stop condition:" +{ $subsections circular-while } ; ABOUT: "circular" diff --git a/basis/circular/circular-tests.factor b/basis/circular/circular-tests.factor index c3c4860f95..cda26df1d3 100644 --- a/basis/circular/circular-tests.factor +++ b/basis/circular/circular-tests.factor @@ -23,7 +23,7 @@ IN: circular.tests [ "boo" ] [ "foo" CHAR: b 3 pick set-nth-unsafe >string ] unit-test [ "ornact" ] [ "factor" 4 over change-circular-start CHAR: n 2 pick set-nth >string ] unit-test -[ "bcd" ] [ 3 "abcd" [ over push-circular ] each >string ] unit-test +[ "bcd" ] [ 3 "abcd" [ over circular-push ] each >string ] unit-test [ { 0 0 } ] [ { 0 0 } -1 over change-circular-start >array ] unit-test @@ -34,11 +34,11 @@ IN: circular.tests [ { } ] [ 3 >array ] unit-test [ { 1 2 } ] [ 3 - [ 1 swap push-growing-circular ] keep - [ 2 swap push-growing-circular ] keep >array + [ 1 swap growing-circular-push ] keep + [ 2 swap growing-circular-push ] keep >array ] unit-test [ { 3 4 5 } ] [ 3 dup { 1 2 3 4 5 } [ - swap push-growing-circular + swap growing-circular-push ] with each >array ] unit-test diff --git a/basis/circular/circular.factor b/basis/circular/circular.factor index b3be4651cd..ccb70c617f 100644 --- a/basis/circular/circular.factor +++ b/basis/circular/circular.factor @@ -1,57 +1,79 @@ ! Copyright (C) 2005, 2006 Alex Chapman, Daniel Ehrenberg ! See http;//factorcode.org/license.txt for BSD license USING: kernel sequences math sequences.private strings -accessors ; +accessors locals fry ; IN: circular -! a circular sequence wraps another sequence, but begins at an -! arbitrary element in the underlying sequence. -TUPLE: circular seq start ; +TUPLE: circular { seq read-only } { start integer } ; : ( seq -- circular ) - 0 circular boa ; + 0 circular boa ; inline > + ] keep [ seq>> length rem ] keep ; inline + PRIVATE> -M: circular length seq>> length ; +M: circular length seq>> length ; inline -M: circular virtual@ circular-wrap seq>> ; +M: circular virtual@ circular-wrap seq>> ; inline -M: circular virtual-seq seq>> ; +M: circular virtual-exemplar seq>> ; inline : change-circular-start ( n circular -- ) #! change start to (start + n) mod length - circular-wrap (>>start) ; + circular-wrap (>>start) ; inline : rotate-circular ( circular -- ) - [ 1 ] dip change-circular-start ; + [ 1 ] dip change-circular-start ; inline -: push-circular ( elt circular -- ) +: circular-push ( elt circular -- ) [ set-first ] [ rotate-circular ] bi ; : ( n -- circular ) - 0 ; + 0 ; inline INSTANCE: circular virtual-sequence -TUPLE: growing-circular < circular length ; +TUPLE: growing-circular < circular { length integer } ; -M: growing-circular length length>> ; +M: growing-circular length length>> ; inline > length ] bi = ; + [ length ] [ seq>> length ] bi = ; inline PRIVATE> -: push-growing-circular ( elt circular -- ) - dup full? [ push-circular ] +: growing-circular-push ( elt circular -- ) + dup full? [ circular-push ] [ [ 1 + ] change-length set-last ] if ; : ( capacity -- growing-circular ) - { } new-sequence 0 0 growing-circular boa ; + { } new-sequence 0 0 growing-circular boa ; inline + +TUPLE: circular-iterator + { circular read-only } { n integer } { last-start integer } ; + +: ( circular -- obj ) + 0 0 circular-iterator boa ; inline + +> ] [ circular>> ] bi nth ] dip call ] 2keep + rot [ [ dup n>> >>last-start ] dip ] when + over [ n>> ] [ [ last-start>> ] [ circular>> length ] bi + 1 - ] bi = [ + 2drop + ] [ + [ [ 1 + ] change-n ] dip (circular-while) + ] if ; inline recursive + +PRIVATE> + +: circular-while ( circular quot: ( obj -- ? ) -- ) + [ clone ] dip [ ] dip (circular-while) ; inline diff --git a/basis/classes/struct/bit-accessors/bit-accessors-tests.factor b/basis/classes/struct/bit-accessors/bit-accessors-tests.factor index e2ff6dbd9c..ecf7b68a2d 100644 --- a/basis/classes/struct/bit-accessors/bit-accessors-tests.factor +++ b/basis/classes/struct/bit-accessors/bit-accessors-tests.factor @@ -1,6 +1,7 @@ ! Copyright (C) 2009 Daniel Ehrenberg ! See http://factorcode.org/license.txt for BSD license. -USING: classes.struct.bit-accessors tools.test effects kernel random stack-checker ; +USING: classes.struct.bit-accessors tools.test effects kernel +sequences random stack-checker ; IN: classes.struct.bit-accessors.test [ t ] [ 20 random 20 random bit-reader infer (( alien -- n )) effect= ] unit-test diff --git a/basis/classes/struct/struct-tests.factor b/basis/classes/struct/struct-tests.factor old mode 100755 new mode 100644 index 58ab2df80b..2c0db93522 --- a/basis/classes/struct/struct-tests.factor +++ b/basis/classes/struct/struct-tests.factor @@ -365,3 +365,18 @@ STRUCT: bit-field-test [ -2 ] [ bit-field-test 2 >>b b>> ] unit-test [ 1 ] [ bit-field-test 257 >>c c>> ] unit-test [ 3 ] [ bit-field-test heap-size ] unit-test + +cpu ppc? [ + STRUCT: ppc-align-test-1 + { x longlong } + { y int } ; + + [ 16 ] [ ppc-align-test-1 heap-size ] unit-test + + STRUCT: ppc-align-test-2 + { y int } + { x longlong } ; + + [ 12 ] [ ppc-align-test-2 heap-size ] unit-test + [ 4 ] [ "x" ppc-align-test-2 offset-of ] unit-test +] when diff --git a/basis/classes/struct/struct.factor b/basis/classes/struct/struct.factor old mode 100755 new mode 100644 index d5e5fdc6c3..cdd47cae9a --- a/basis/classes/struct/struct.factor +++ b/basis/classes/struct/struct.factor @@ -189,9 +189,6 @@ M: struct-c-type c-struct? drop t ; \ cleave [ ] 2sequence \ output>array [ ] 2sequence ; -: define-inline-method ( class generic quot -- ) - [ create-method-in ] dip [ define ] [ drop make-inline ] 2bi ; - : (define-struct-slot-values-method) ( class -- ) [ \ struct-slot-values ] [ struct-slot-values-quot ] bi define-inline-method ; @@ -211,27 +208,32 @@ M: struct-c-type c-struct? drop t ; slots >>fields size >>size align >>align + align >>align-first class (unboxer-quot) >>unboxer-quot - class (boxer-quot) >>boxer-quot ; - -GENERIC: align-offset ( offset class -- offset' ) + class (boxer-quot) >>boxer-quot ; -M: struct-slot-spec align-offset - [ type>> c-type-align 8 * align ] keep +GENERIC: compute-slot-offset ( offset class -- offset' ) + +: c-type-align-at ( class offset -- n ) + 0 = [ c-type-align-first ] [ c-type-align ] if ; + +M: struct-slot-spec compute-slot-offset + [ type>> over c-type-align-at 8 * align ] keep [ [ 8 /i ] dip (>>offset) ] [ type>> heap-size 8 * + ] 2bi ; -M: struct-bit-slot-spec align-offset +M: struct-bit-slot-spec compute-slot-offset [ (>>offset) ] [ bits>> + ] 2bi ; -: struct-offsets ( slots -- size ) - 0 [ align-offset ] reduce 8 align 8 /i ; +: compute-struct-offsets ( slots -- size ) + 0 [ compute-slot-offset ] reduce 8 align 8 /i ; -: union-struct-offsets ( slots -- size ) +: compute-union-offsets ( slots -- size ) 1 [ 0 >>offset type>> heap-size max ] reduce ; -: struct-align ( slots -- align ) +: struct-alignment ( slots -- align ) [ struct-bit-slot-spec? not ] filter - 1 [ type>> c-type-align max ] reduce ; + 1 [ [ type>> ] [ offset>> ] bi c-type-align-at max ] reduce ; + PRIVATE> M: struct byte-length class "struct-size" word-prop ; foldable @@ -243,10 +245,8 @@ GENERIC: binary-zero? ( value -- ? ) M: object binary-zero? drop f ; M: f binary-zero? drop t ; -M: number binary-zero? zero? ; -M: struct binary-zero? - [ byte-length iota ] [ >c-ptr ] bi - [ *uchar zero? ] curry all? ; +M: number binary-zero? 0 = ; +M: struct binary-zero? >c-ptr [ 0 = ] all? ; : struct-needs-prototype? ( class -- ? ) struct-slots [ initial>> binary-zero? ] all? not ; @@ -278,8 +278,9 @@ M: struct binary-zero? slots empty? [ struct-must-have-slots ] when class redefine-struct-tuple-class slots make-slots dup check-struct-slots :> slot-specs - slot-specs struct-align :> alignment - slot-specs offsets-quot call alignment align :> size + slot-specs offsets-quot call :> unaligned-size + slot-specs struct-alignment :> alignment + unaligned-size alignment align :> size class slot-specs size alignment c-type-for-class :> c-type @@ -291,10 +292,10 @@ M: struct binary-zero? PRIVATE> : define-struct-class ( class slots -- ) - [ struct-offsets ] (define-struct-class) ; + [ compute-struct-offsets ] (define-struct-class) ; : define-union-struct-class ( class slots -- ) - [ union-struct-offsets ] (define-struct-class) ; + [ compute-union-offsets ] (define-struct-class) ; M: struct-class reset-class [ call-next-method ] [ name>> c-types get delete-at ] bi ; diff --git a/basis/cocoa/application/application.factor b/basis/cocoa/application/application.factor index cbf8636a75..df56ce5c4c 100644 --- a/basis/cocoa/application/application.factor +++ b/basis/cocoa/application/application.factor @@ -49,7 +49,7 @@ TUPLE: objc-error alien reason ; M: objc-error summary ( error -- ) drop "Objective C exception" ; -[ [ objc-error ] 19 setenv ] "cocoa.application" add-init-hook +[ [ objc-error ] 19 set-special-object ] "cocoa.application" add-startup-hook : running.app? ( -- ? ) #! Test if we're running a .app. diff --git a/basis/cocoa/cocoa.factor b/basis/cocoa/cocoa.factor index ec09f8f2ba..34bac0a505 100644 --- a/basis/cocoa/cocoa.factor +++ b/basis/cocoa/cocoa.factor @@ -27,7 +27,7 @@ SYMBOL: frameworks frameworks [ V{ } clone ] initialize -[ frameworks get [ load-framework ] each ] "cocoa" add-init-hook +[ frameworks get [ load-framework ] each ] "cocoa" add-startup-hook SYNTAX: FRAMEWORK: scan [ load-framework ] [ frameworks get push ] bi ; diff --git a/basis/cocoa/enumeration/enumeration.factor b/basis/cocoa/enumeration/enumeration.factor old mode 100755 new mode 100644 diff --git a/basis/cocoa/messages/messages.factor b/basis/cocoa/messages/messages.factor old mode 100755 new mode 100644 index fce7adc04a..02e6335c54 --- a/basis/cocoa/messages/messages.factor +++ b/basis/cocoa/messages/messages.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2006, 2009 Slava Pestov. +! Copyright (C) 2006, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors alien alien.c-types alien.strings arrays assocs classes.struct continuations combinators compiler compiler.alien @@ -76,13 +76,13 @@ MACRO: (send) ( selector super? -- quot ) : super-send ( receiver args... selector -- return... ) t (send) ; inline ! Runtime introspection -SYMBOL: class-init-hooks +SYMBOL: class-startup-hooks -class-init-hooks [ H{ } clone ] initialize +class-startup-hooks [ H{ } clone ] initialize : (objc-class) ( name word -- class ) 2dup execute dup [ 2nip ] [ - drop over class-init-hooks get at [ call( -- ) ] when* + drop over class-startup-hooks get at [ call( -- ) ] when* 2dup execute dup [ 2nip ] [ 2drop "No such class: " prepend throw ] if @@ -202,7 +202,7 @@ ERROR: no-objc-type name ; (free) ; : method-arg-types ( method -- args ) - dup method_getNumberOfArguments + dup method_getNumberOfArguments iota [ method-arg-type ] with map ; : method-return-type ( method -- ctype ) @@ -229,7 +229,7 @@ ERROR: no-objc-type name ; : class-exists? ( string -- class ) objc_getClass >boolean ; : define-objc-class-word ( quot name -- ) - [ class-init-hooks get set-at ] + [ class-startup-hooks get set-at ] [ [ "cocoa.classes" create ] [ '[ _ objc-class ] ] bi (( -- class )) define-declared diff --git a/basis/columns/columns-tests.factor b/basis/columns/columns-tests.factor index 434c233936..c0e0956709 100644 --- a/basis/columns/columns-tests.factor +++ b/basis/columns/columns-tests.factor @@ -7,3 +7,5 @@ IN: columns.tests [ { 1 4 7 } ] [ "seq" get 0 >array ] unit-test [ ] [ "seq" get 1 [ sq ] map! drop ] unit-test [ { 4 25 64 } ] [ "seq" get 1 >array ] unit-test + +[ { { 1 3 } { 2 4 } } ] [ { { 1 2 } { 3 4 } } [ >array ] map ] unit-test diff --git a/basis/columns/columns.factor b/basis/columns/columns.factor index 8f45dab872..c36505ab6d 100644 --- a/basis/columns/columns.factor +++ b/basis/columns/columns.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2005, 2008 Slava Pestov, Daniel Ehrenberg. +! Copyright (C) 2005, 2010 Slava Pestov, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. USING: sequences kernel accessors ; IN: columns @@ -8,11 +8,11 @@ TUPLE: column seq col ; C: column -M: column virtual-seq seq>> ; +M: column virtual-exemplar seq>> ; M: column virtual@ [ col>> swap ] [ seq>> ] bi nth bounds-check ; M: column length seq>> length ; INSTANCE: column virtual-sequence : ( seq -- seq' ) - dup empty? [ dup first length [ ] with map ] unless ; + dup empty? [ dup first length [ ] with { } map-integers ] unless ; diff --git a/basis/combinators/smart/smart-tests.factor b/basis/combinators/smart/smart-tests.factor index 399b4dc36f..bd224919f9 100644 --- a/basis/combinators/smart/smart-tests.factor +++ b/basis/combinators/smart/smart-tests.factor @@ -47,3 +47,9 @@ IN: combinators.smart.tests [ { { 1 2 } { 3 4 } } ] [ nested-smart-combo-test ] unit-test [ 14 ] [ [ 1 2 3 ] [ sq ] [ + ] map-reduce-outputs ] unit-test + +{ 2 3 } [ [ + ] preserving ] must-infer-as + +{ 2 0 } [ [ + ] nullary ] must-infer-as + +{ 2 2 } [ [ [ + ] nullary ] preserving ] must-infer-as diff --git a/basis/combinators/smart/smart.factor b/basis/combinators/smart/smart.factor index a00967742f..cb1b309c86 100644 --- a/basis/combinators/smart/smart.factor +++ b/basis/combinators/smart/smart.factor @@ -5,46 +5,49 @@ stack-checker math sequences ; IN: combinators.smart MACRO: drop-outputs ( quot -- quot' ) - dup infer out>> '[ @ _ ndrop ] ; + dup outputs '[ @ _ ndrop ] ; MACRO: keep-inputs ( quot -- quot' ) - dup infer in>> '[ _ _ nkeep ] ; + dup inputs '[ _ _ nkeep ] ; MACRO: output>sequence ( quot exemplar -- newquot ) - [ dup infer out>> ] dip + [ dup outputs ] dip '[ @ _ _ nsequence ] ; MACRO: output>array ( quot -- newquot ) '[ _ { } output>sequence ] ; MACRO: input> ] keep + [ inputs ] keep '[ _ firstn @ ] ; MACRO: input> ] keep + [ inputs ] keep '[ _ firstn-unsafe @ ] ; MACRO: reduce-outputs ( quot operation -- newquot ) - [ dup infer out>> 1 [-] ] dip n*quot compose ; + [ dup outputs 1 [-] ] dip n*quot compose ; MACRO: sum-outputs ( quot -- n ) '[ _ [ + ] reduce-outputs ] ; MACRO: map-reduce-outputs ( quot mapper reducer -- newquot ) - [ dup infer out>> ] 2dip + [ dup outputs ] 2dip [ swap '[ _ _ napply ] ] [ [ 1 [-] ] dip n*quot ] bi-curry* bi '[ @ @ @ ] ; MACRO: append-outputs-as ( quot exemplar -- newquot ) - [ dup infer out>> ] dip '[ @ _ _ nappend-as ] ; + [ dup outputs ] dip '[ @ _ _ nappend-as ] ; MACRO: append-outputs ( quot -- seq ) '[ _ { } append-outputs-as ] ; MACRO: preserving ( quot -- ) - [ infer in>> length ] keep '[ _ ndup @ ] ; + [ inputs ] keep '[ _ ndup @ ] ; + +MACRO: nullary ( quot -- quot' ) + dup outputs '[ @ _ ndrop ] ; MACRO: smart-if ( pred true false -- ) '[ _ preserving _ _ if ] ; inline diff --git a/basis/command-line/command-line.factor b/basis/command-line/command-line.factor index 19421359a3..939fb82f00 100644 --- a/basis/command-line/command-line.factor +++ b/basis/command-line/command-line.factor @@ -8,7 +8,8 @@ IN: command-line SYMBOL: script SYMBOL: command-line -: (command-line) ( -- args ) 10 getenv sift [ alien>native-string ] map ; +: (command-line) ( -- args ) + 10 special-object sift [ alien>native-string ] map ; : rc-path ( name -- path ) os windows? [ "." prepend ] unless @@ -69,4 +70,4 @@ SYMBOL: main-vocab-hook : ignore-cli-args? ( -- ? ) os macosx? "run" get "ui" = and ; -[ default-cli-args ] "command-line" add-init-hook +[ default-cli-args ] "command-line" add-startup-hook diff --git a/basis/compiler/cfg/build-stack-frame/build-stack-frame.factor b/basis/compiler/cfg/build-stack-frame/build-stack-frame.factor index 1f01bc438b..670e34e5f9 100644 --- a/basis/compiler/cfg/build-stack-frame/build-stack-frame.factor +++ b/basis/compiler/cfg/build-stack-frame/build-stack-frame.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: namespaces accessors math.order assocs kernel sequences combinators make classes words cpu.architecture layouts @@ -17,13 +17,13 @@ GENERIC: compute-stack-frame* ( insn -- ) UNION: stack-frame-insn ##alien-invoke ##alien-indirect + ##alien-assembly ##alien-callback ; M: stack-frame-insn compute-stack-frame* stack-frame>> request-stack-frame ; -M: ##call compute-stack-frame* - word>> sub-primitive>> [ frame-required? on ] unless ; +M: ##call compute-stack-frame* drop frame-required? on ; M: ##gc compute-stack-frame* frame-required? on diff --git a/basis/compiler/cfg/builder/builder.factor b/basis/compiler/cfg/builder/builder.factor old mode 100755 new mode 100644 index cf6215c5cd..529c3b5ae6 --- a/basis/compiler/cfg/builder/builder.factor +++ b/basis/compiler/cfg/builder/builder.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2004, 2009 Slava Pestov. +! Copyright (C) 2004, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators hashtables kernel math fry namespaces make sequences words byte-arrays @@ -45,6 +45,12 @@ SYMBOL: loops end-stack-analysis ] with-scope ; inline +: with-dummy-cfg-builder ( node quot -- ) + [ + [ V{ } clone procedures ] 2dip + '[ _ t t [ _ call( node -- ) ] with-cfg-builder ] with-variable + ] { } make drop ; + GENERIC: emit-node ( node -- ) : emit-nodes ( nodes -- ) @@ -230,13 +236,16 @@ M: #alien-invoke emit-node M: #alien-indirect emit-node [ ##alien-indirect ] emit-alien-node ; +M: #alien-assembly emit-node + [ ##alien-assembly ] emit-alien-node ; + M: #alien-callback emit-node dup params>> xt>> dup [ ##prologue - dup [ ##alien-callback ] emit-alien-node + [ ##alien-callback ] emit-alien-node ##epilogue - params>> ##callback-return + ##return ] with-cfg-builder ; ! No-op nodes diff --git a/basis/compiler/cfg/cfg.factor b/basis/compiler/cfg/cfg.factor index 369e6ebc32..5d815e3b0f 100644 --- a/basis/compiler/cfg/cfg.factor +++ b/basis/compiler/cfg/cfg.factor @@ -10,14 +10,14 @@ number { successors vector } { predecessors vector } ; -M: basic-block hashcode* nip id>> ; - : ( -- bb ) basic-block new + \ basic-block counter >>id V{ } clone >>instructions V{ } clone >>successors - V{ } clone >>predecessors - \ basic-block counter >>id ; + V{ } clone >>predecessors ; + +M: basic-block hashcode* nip id>> ; TUPLE: cfg { entry basic-block } word label spill-area-size reps diff --git a/basis/compiler/cfg/checker/checker.factor b/basis/compiler/cfg/checker/checker.factor index 051b0e3e1f..d6f2702ee7 100644 --- a/basis/compiler/cfg/checker/checker.factor +++ b/basis/compiler/cfg/checker/checker.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2009 Slava Pestov. +! Copyright (C) 2009, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel combinators.short-circuit accessors math sequences sets assocs compiler.cfg.instructions compiler.cfg.rpo @@ -14,7 +14,7 @@ ERROR: bad-kill-block bb ; dup instructions>> dup penultimate ##epilogue? [ { [ length 2 = ] - [ last { [ ##return? ] [ ##callback-return? ] [ ##jump? ] } 1|| ] + [ last { [ ##return? ] [ ##jump? ] } 1|| ] } 1&& ] [ last ##branch? ] if [ drop ] [ bad-kill-block ] if ; diff --git a/basis/compiler/cfg/instructions/instructions.factor b/basis/compiler/cfg/instructions/instructions.factor index 91ac923273..68a8b8ce59 100644 --- a/basis/compiler/cfg/instructions/instructions.factor +++ b/basis/compiler/cfg/instructions/instructions.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: assocs accessors arrays kernel sequences namespaces words math math.order layouts classes.algebra classes.union @@ -382,6 +382,16 @@ def: dst use: src1 src2 literal: rep ; +PURE-INSN: ##mul-high-vector +def: dst +use: src1 src2 +literal: rep ; + +PURE-INSN: ##mul-horizontal-add-vector +def: dst +use: src1 src2 +literal: rep ; + PURE-INSN: ##saturated-mul-vector def: dst use: src1 src2 @@ -402,19 +412,29 @@ def: dst use: src1 src2 literal: rep ; +PURE-INSN: ##avg-vector +def: dst +use: src1 src2 +literal: rep ; + PURE-INSN: ##dot-vector def: dst/scalar-rep use: src1 src2 literal: rep ; +PURE-INSN: ##sad-vector +def: dst +use: src1 src2 +literal: rep ; + PURE-INSN: ##horizontal-add-vector -def: dst/scalar-rep -use: src +def: dst +use: src1 src2 literal: rep ; PURE-INSN: ##horizontal-sub-vector -def: dst/scalar-rep -use: src +def: dst +use: src1 src2 literal: rep ; PURE-INSN: ##horizontal-shl-vector-imm @@ -651,11 +671,11 @@ literal: params stack-frame ; INSN: ##alien-indirect literal: params stack-frame ; -INSN: ##alien-callback +INSN: ##alien-assembly literal: params stack-frame ; -INSN: ##callback-return -literal: params ; +INSN: ##alien-callback +literal: params stack-frame ; ! Instructions used by CFG IR only. INSN: ##prologue ; @@ -728,8 +748,7 @@ temp: temp1/int-rep temp2/int-rep literal: size data-values tagged-values uninitialized-locs ; INSN: ##save-context -temp: temp1/int-rep temp2/int-rep -literal: callback-allowed? ; +temp: temp1/int-rep temp2/int-rep ; ! Instructions used by machine IR only. INSN: _prologue diff --git a/basis/compiler/cfg/instructions/syntax/syntax.factor b/basis/compiler/cfg/instructions/syntax/syntax.factor index bca5e1ee64..cd76652d06 100644 --- a/basis/compiler/cfg/instructions/syntax/syntax.factor +++ b/basis/compiler/cfg/instructions/syntax/syntax.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: classes.tuple classes.tuple.parser kernel words make fry sequences parser accessors effects namespaces @@ -61,14 +61,14 @@ TUPLE: insn-slot-spec type name rep ; "pure-insn" "compiler.cfg.instructions" lookup ; : insn-effect ( word -- effect ) - boa-effect in>> but-last f ; + boa-effect in>> but-last { } ; : define-insn-tuple ( class superclass specs -- ) [ name>> ] map "insn#" suffix define-tuple-class ; : define-insn-ctor ( class specs -- ) [ dup '[ _ ] [ f ] [ boa , ] surround ] dip - [ name>> ] map f define-declared ; + [ name>> ] map { } define-declared ; : define-insn ( class superclass specs -- ) parse-insn-slot-specs { diff --git a/basis/compiler/cfg/intrinsics/allot/allot.factor b/basis/compiler/cfg/intrinsics/allot/allot.factor index 9804244ecb..31a8a898bc 100644 --- a/basis/compiler/cfg/intrinsics/allot/allot.factor +++ b/basis/compiler/cfg/intrinsics/allot/allot.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel math math.order sequences accessors arrays byte-arrays layouts classes.tuple.private fry locals @@ -34,7 +34,7 @@ IN: compiler.cfg.intrinsics.allot [ [ ^^load-literal ] dip 1 ] dip type-number ##set-slot-imm ; :: store-initial-element ( len reg elt class -- ) - len [ [ elt reg ] dip 2 + class type-number ##set-slot-imm ] each ; + len [ [ elt reg ] dip 2 + class type-number ##set-slot-imm ] each-integer ; : expand-? ( obj -- ? ) dup integer? [ 0 8 between? ] [ drop f ] if ; diff --git a/basis/compiler/cfg/intrinsics/intrinsics.factor b/basis/compiler/cfg/intrinsics/intrinsics.factor index a03f04f182..d753a4c1b4 100644 --- a/basis/compiler/cfg/intrinsics/intrinsics.factor +++ b/basis/compiler/cfg/intrinsics/intrinsics.factor @@ -7,7 +7,6 @@ compiler.cfg.intrinsics.alien compiler.cfg.intrinsics.allot compiler.cfg.intrinsics.fixnum compiler.cfg.intrinsics.float -compiler.cfg.intrinsics.simd compiler.cfg.intrinsics.slots compiler.cfg.intrinsics.misc compiler.cfg.comparisons ; @@ -23,7 +22,6 @@ QUALIFIED: classes.tuple.private QUALIFIED: math.private QUALIFIED: math.integers.private QUALIFIED: math.floats.private -QUALIFIED: math.vectors.simd.intrinsics QUALIFIED: math.libm IN: compiler.cfg.intrinsics @@ -32,7 +30,8 @@ IN: compiler.cfg.intrinsics { { kernel.private:tag [ drop emit-tag ] } - { kernel.private:getenv [ emit-getenv ] } + { kernel.private:special-object [ emit-special-object ] } + { kernel.private:(identity-hashcode) [ drop emit-identity-hashcode ] } { math.private:both-fixnums? [ drop emit-both-fixnums? ] } { math.private:fixnum+ [ drop emit-fixnum+ ] } { math.private:fixnum- [ drop emit-fixnum- ] } @@ -151,64 +150,5 @@ IN: compiler.cfg.intrinsics { math.integers.private:fixnum-log2 [ drop emit-fixnum-log2 ] } } enable-intrinsics ; -: enable-simd ( -- ) - { - { math.vectors.simd.intrinsics:assert-positive [ drop ] } - { math.vectors.simd.intrinsics:(simd-v+) [ [ ^^add-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vs+) [ [ ^^saturated-add-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-v+-) [ [ ^^add-sub-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-v-) [ [ ^^sub-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vs-) [ [ ^^saturated-sub-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vneg) [ [ generate-neg-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-v*) [ [ ^^mul-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vs*) [ [ ^^saturated-mul-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-v/) [ [ ^^div-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vmin) [ [ generate-min-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vmax) [ [ generate-max-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-v.) [ [ ^^dot-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vabs) [ [ generate-abs-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vsqrt) [ [ ^^sqrt-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vbitand) [ [ ^^and-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vbitandn) [ [ ^^andn-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vbitor) [ [ ^^or-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vbitxor) [ [ ^^xor-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vbitnot) [ [ generate-not-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vand) [ [ ^^and-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vandn) [ [ ^^andn-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vor) [ [ ^^or-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vxor) [ [ ^^xor-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vnot) [ [ generate-not-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-v<=) [ [ cc<= generate-compare-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-v<) [ [ cc< generate-compare-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-v=) [ [ cc= generate-compare-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-v>) [ [ cc> generate-compare-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-v>=) [ [ cc>= generate-compare-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vunordered?) [ [ cc/<>= generate-compare-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vany?) [ [ vcc-any ^^test-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vall?) [ [ vcc-all ^^test-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vnone?) [ [ vcc-none ^^test-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vlshift) [ [ ^^shl-vector-imm ] [ ^^shl-vector ] emit-shift-vector-op ] } - { math.vectors.simd.intrinsics:(simd-vrshift) [ [ ^^shr-vector-imm ] [ ^^shr-vector ] emit-shift-vector-op ] } - { math.vectors.simd.intrinsics:(simd-hlshift) [ [ ^^horizontal-shl-vector-imm ] emit-shift-vector-imm-op ] } - { math.vectors.simd.intrinsics:(simd-hrshift) [ [ ^^horizontal-shr-vector-imm ] emit-shift-vector-imm-op ] } - { math.vectors.simd.intrinsics:(simd-with) [ [ ^^with-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-gather-2) [ emit-gather-vector-2 ] } - { math.vectors.simd.intrinsics:(simd-gather-4) [ emit-gather-vector-4 ] } - { math.vectors.simd.intrinsics:(simd-vshuffle-elements) [ emit-shuffle-vector ] } - { math.vectors.simd.intrinsics:(simd-vshuffle-bytes) [ emit-shuffle-vector-var ] } - { math.vectors.simd.intrinsics:(simd-(vmerge-head)) [ [ ^^merge-vector-head ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-(vmerge-tail)) [ [ ^^merge-vector-tail ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-(v>float)) [ [ ^^integer>float-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-(v>integer)) [ [ ^^float>integer-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-(vpack-signed)) [ [ ^^signed-pack-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-(vpack-unsigned)) [ [ ^^unsigned-pack-vector ] emit-binary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-(vunpack-head)) [ [ generate-unpack-vector-head ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-(vunpack-tail)) [ [ generate-unpack-vector-tail ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:(simd-select) [ emit-select-vector ] } - { math.vectors.simd.intrinsics:(simd-sum) [ [ ^^horizontal-add-vector ] emit-unary-vector-op ] } - { math.vectors.simd.intrinsics:alien-vector [ emit-alien-vector ] } - { math.vectors.simd.intrinsics:set-alien-vector [ emit-set-alien-vector ] } - } enable-intrinsics ; - : emit-intrinsic ( node word -- ) "intrinsic" word-prop call( node -- ) ; diff --git a/basis/compiler/cfg/intrinsics/misc/misc.factor b/basis/compiler/cfg/intrinsics/misc/misc.factor index ce005e8353..fed5492220 100644 --- a/basis/compiler/cfg/intrinsics/misc/misc.factor +++ b/basis/compiler/cfg/intrinsics/misc/misc.factor @@ -1,16 +1,22 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: namespaces layouts sequences kernel -accessors compiler.tree.propagation.info -compiler.cfg.stacks compiler.cfg.hats -compiler.cfg.instructions compiler.cfg.utilities ; +USING: namespaces layouts sequences kernel math accessors +compiler.tree.propagation.info compiler.cfg.stacks +compiler.cfg.hats compiler.cfg.instructions +compiler.cfg.utilities ; IN: compiler.cfg.intrinsics.misc : emit-tag ( -- ) ds-pop tag-mask get ^^and-imm ^^tag-fixnum ds-push ; -: emit-getenv ( node -- ) - "userenv" ^^vm-field-ptr +: emit-special-object ( node -- ) + "special-objects" ^^vm-field-ptr swap node-input-infos first literal>> [ ds-drop 0 ^^slot-imm ] [ ds-pop ^^offset>slot ^^slot ] if* ds-push ; + +: emit-identity-hashcode ( -- ) + ds-pop tag-mask get bitnot ^^load-immediate ^^and 0 0 ^^slot-imm + hashcode-shift ^^shr-imm + ^^tag-fixnum + ds-push ; diff --git a/basis/compiler/cfg/intrinsics/simd/backend/backend.factor b/basis/compiler/cfg/intrinsics/simd/backend/backend.factor new file mode 100644 index 0000000000..e8b9e3c5de --- /dev/null +++ b/basis/compiler/cfg/intrinsics/simd/backend/backend.factor @@ -0,0 +1,206 @@ +! (c)2009 Joe Groff bsd license +USING: accessors arrays assocs classes combinators +combinators.short-circuit compiler.cfg.builder.blocks +compiler.cfg.registers compiler.cfg.stacks +compiler.cfg.stacks.local compiler.tree.propagation.info +cpu.architecture effects fry generalizations +kernel locals macros math namespaces quotations sequences +splitting stack-checker words ; +IN: compiler.cfg.intrinsics.simd.backend + +! Selection of implementation based on available CPU instructions + +: can-has? ( quot -- ? ) + [ t \ can-has? ] dip '[ @ drop \ can-has? get ] with-variable ; inline + +: can-has-rep? ( rep reps -- ) + member? \ can-has? [ and ] change ; inline + +GENERIC: create-can-has ( word -- word' ) + +PREDICATE: hat-word < word + { + [ name>> { [ "^" head? ] [ "##" head? ] } 1|| ] + [ vocabulary>> { "compiler.cfg.intrinsics.simd" "compiler.cfg.hats" } member? ] + } 1&& ; + +PREDICATE: vector-op-word < hat-word + name>> "-vector" swap subseq? ; + +: reps-word ( word -- word' ) + name>> "^^" ?head drop "##" ?head drop + "%" "-reps" surround "cpu.architecture" lookup ; + +SYMBOL: blub + +:: can-has-^^-quot ( word def effect -- quot ) + effect in>> { "rep" } split1 [ length ] bi@ 1 + + word reps-word 1quotation + effect out>> length blub >quotation + '[ [ _ ndrop ] _ ndip @ can-has-rep? @ ] ; + +:: can-has-^-quot ( word def effect -- quot ) + def create-can-has first ; + +: map-concat-like ( seq quot -- seq' ) + '[ _ map ] [ concat-as ] bi ; inline + +M: object create-can-has 1quotation ; + +M: array create-can-has + [ create-can-has ] map-concat-like 1quotation ; +M: callable create-can-has + [ create-can-has ] map-concat-like 1quotation ; + +: (can-has-word) ( word -- word' ) + name>> "can-has-" prepend "compiler.cfg.intrinsics.simd.backend" lookup ; + +: (can-has-quot) ( word -- quot ) + [ ] [ def>> ] [ stack-effect ] tri { + { [ pick name>> "^^" head? ] [ can-has-^^-quot ] } + { [ pick name>> "##" head? ] [ can-has-^^-quot ] } + { [ pick name>> "^" head? ] [ can-has-^-quot ] } + } cond ; + +: (can-has-nop-quot) ( word -- quot ) + stack-effect in>> length '[ _ ndrop blub ] ; + +DEFER: can-has-words + +M: word create-can-has + can-has-words ?at drop 1quotation ; + +M: hat-word create-can-has + (can-has-nop-quot) ; + +M: vector-op-word create-can-has + dup (can-has-word) [ 1quotation ] [ (can-has-quot) ] ?if ; + +GENERIC# >can-has-cond 2 ( quot #pick #dup -- quotpair ) +M:: callable >can-has-cond ( quot #pick #dup -- quotpair ) + #dup quot create-can-has '[ _ ndup @ can-has? ] quot 2array ; + +M:: pair >can-has-cond ( pair #pick #dup -- quotpair ) + pair first2 :> ( class quot ) + #pick class #dup quot create-can-has + '[ _ npick _ instance? [ _ ndup @ can-has? ] dip and ] + quot 2array ; + +MACRO: v-vector-op ( trials -- ) + [ 1 2 >can-has-cond ] map '[ _ cond ] ; +MACRO: vl-vector-op ( trials -- ) + [ 1 3 >can-has-cond ] map '[ _ cond ] ; +MACRO: vv-vector-op ( trials -- ) + [ 1 3 >can-has-cond ] map '[ _ cond ] ; +MACRO: vv-cc-vector-op ( trials -- ) + [ 2 4 >can-has-cond ] map '[ _ cond ] ; +MACRO: vvvv-vector-op ( trials -- ) + [ 1 5 >can-has-cond ] map '[ _ cond ] ; + +! Special-case conditional instructions + +: can-has-^(compare-vector) ( src1 src2 rep cc -- dst ) + [ 2drop ] 2dip %compare-vector-reps member? + \ can-has? [ and ] change + blub ; + +: can-has-^^test-vector ( src rep vcc -- dst ) + [ drop ] 2dip drop %test-vector-reps member? + \ can-has? [ and ] change + blub ; + +MACRO: can-has-case ( cases -- ) + dup first second inputs 1 + + '[ _ ndrop f ] suffix '[ _ case ] ; + +GENERIC# >can-has-trial 1 ( obj #pick -- quot ) + +M: callable >can-has-trial + drop '[ _ can-has? ] ; +M: pair >can-has-trial + swap first2 dup inputs + '[ _ npick _ instance? [ _ can-has? ] [ _ ndrop blub ] if ] ; + +MACRO: can-has-vector-op ( trials #pick #dup -- ) + [ '[ _ >can-has-trial ] map ] dip '[ _ _ n|| \ can-has? [ and ] change blub ] ; + +: can-has-v-vector-op ( trials -- ? ) + 1 2 can-has-vector-op ; inline +: can-has-vv-vector-op ( trials -- ? ) + 1 3 can-has-vector-op ; inline +: can-has-vv-cc-vector-op ( trials -- ? ) + 2 4 can-has-vector-op ; inline +: can-has-vvvv-vector-op ( trials -- ? ) + 1 5 can-has-vector-op ; inline + +CONSTANT: can-has-words + H{ + { case can-has-case } + { v-vector-op can-has-v-vector-op } + { vl-vector-op can-has-vv-vector-op } + { vv-vector-op can-has-vv-vector-op } + { vv-cc-vector-op can-has-vv-cc-vector-op } + { vvvv-vector-op can-has-vvvv-vector-op } + } + +! Intrinsic code emission + +MACRO: check-elements ( quots -- ) + [ length '[ _ firstn ] ] + [ '[ _ spread ] ] + [ length 1 - \ and [ ] like ] + tri 3append ; + +ERROR: bad-simd-intrinsic node ; + +MACRO: if-literals-match ( quots -- ) + [ length ] [ ] [ length ] tri + ! n quots n + '[ + ! node quot + [ + dup node-input-infos + _ tail-slice* [ literal>> ] map + dup _ check-elements + ] dip + swap [ + ! node literals quot + [ _ firstn ] dip call + drop + ] [ 2drop bad-simd-intrinsic ] if + ] ; + +CONSTANT: [unary] [ ds-drop ds-pop ] +CONSTANT: [unary/param] [ [ -2 inc-d ds-pop ] dip ] +CONSTANT: [binary] [ ds-drop 2inputs ] +CONSTANT: [quaternary] + [ + ds-drop + D 3 peek-loc + D 2 peek-loc + D 1 peek-loc + D 0 peek-loc + -4 inc-d + ] + +:: [emit-vector-op] ( trials params-quot op-quot literal-preds -- quot ) + params-quot trials op-quot literal-preds + '[ [ _ dip _ @ ds-push ] _ if-literals-match ] ; + +MACRO: emit-v-vector-op ( trials -- ) + [unary] [ v-vector-op ] { [ representation? ] } [emit-vector-op] ; +MACRO: emit-vl-vector-op ( trials literal-pred -- ) + [ [unary/param] [ vl-vector-op ] { [ representation? ] } ] dip prefix [emit-vector-op] ; +MACRO: emit-vv-vector-op ( trials -- ) + [binary] [ vv-vector-op ] { [ representation? ] } [emit-vector-op] ; +MACRO: emit-vvvv-vector-op ( trials -- ) + [quaternary] [ vvvv-vector-op ] { [ representation? ] } [emit-vector-op] ; + +MACRO:: emit-vv-or-vl-vector-op ( var-trials imm-trials literal-pred -- ) + literal-pred imm-trials literal-pred var-trials + '[ + dup node-input-infos 2 tail-slice* first literal>> @ + [ _ _ emit-vl-vector-op ] + [ _ emit-vv-vector-op ] if + ] ; + diff --git a/basis/compiler/cfg/intrinsics/simd/simd-tests.factor b/basis/compiler/cfg/intrinsics/simd/simd-tests.factor new file mode 100644 index 0000000000..8bd936c4f6 --- /dev/null +++ b/basis/compiler/cfg/intrinsics/simd/simd-tests.factor @@ -0,0 +1,536 @@ +! (c)2009 Joe Groff bsd license +USING: arrays assocs biassocs byte-arrays byte-arrays.hex +classes compiler.cfg compiler.cfg.comparisons compiler.cfg.instructions +compiler.cfg.intrinsics.simd compiler.cfg.intrinsics.simd.backend +compiler.cfg.registers compiler.cfg.stacks.height +compiler.cfg.stacks.local compiler.tree compiler.tree.propagation.info +cpu.architecture fry hashtables kernel locals make namespaces sequences +system tools.test words ; +IN: compiler.cfg.intrinsics.simd.tests + +:: test-node ( rep -- node ) + T{ #call + { in-d { 1 2 3 4 } } + { out-d { 5 } } + { info H{ + { 1 T{ value-info { class byte-array } } } + { 2 T{ value-info { class byte-array } } } + { 3 T{ value-info { class byte-array } } } + { 4 T{ value-info { class word } { literal? t } { literal rep } } } + { 5 T{ value-info { class byte-array } } } + } } + } ; + +:: test-node-literal ( lit rep -- node ) + lit class :> lit-class + T{ #call + { in-d { 1 2 3 4 } } + { out-d { 5 } } + { info H{ + { 1 T{ value-info { class byte-array } } } + { 2 T{ value-info { class byte-array } } } + { 3 T{ value-info { class lit-class } { literal? t } { literal lit } } } + { 4 T{ value-info { class word } { literal? t } { literal rep } } } + { 5 T{ value-info { class byte-array } } } + } } + } ; + +: test-node-nonliteral-rep ( -- node ) + T{ #call + { in-d { 1 2 3 4 } } + { out-d { 5 } } + { info H{ + { 1 T{ value-info { class byte-array } } } + { 2 T{ value-info { class byte-array } } } + { 3 T{ value-info { class byte-array } } } + { 4 T{ value-info { class object } } } + { 5 T{ value-info { class byte-array } } } + } } + } ; + +: test-compiler-env ( -- x ) + H{ } clone + T{ basic-block { id 0 } } + [ \ basic-block pick set-at ] + [ 0 swap associate \ ds-heights pick set-at ] + [ 0 swap associate \ rs-heights pick set-at ] tri + T{ current-height { d 0 } { r 0 } { emit-d 0 } { emit-r 0 } } \ current-height pick set-at + H{ } clone \ local-peek-set pick set-at + H{ } clone \ replace-mapping pick set-at + H{ } \ locs>vregs pick set-at + H{ } clone \ peek-sets pick set-at + H{ } clone \ replace-sets pick set-at + H{ } clone \ kill-sets pick set-at ; + +: make-classes ( quot -- seq ) + { } make [ class ] map ; inline + +: test-emit ( cpu rep quot -- node ) + [ + [ new \ cpu ] 2dip '[ + test-compiler-env [ _ test-node @ ] bind + ] with-variable + ] make-classes ; inline + +: test-emit-literal ( cpu lit rep quot -- node ) + [ + [ new \ cpu ] 3dip '[ + test-compiler-env [ _ _ test-node-literal @ ] bind + ] with-variable + ] make-classes ; inline + +: test-emit-nonliteral-rep ( cpu quot -- node ) + [ + [ new \ cpu ] dip '[ + test-compiler-env [ test-node-nonliteral-rep @ ] bind + ] with-variable + ] make-classes ; inline + +CONSTANT: signed-reps + { char-16-rep short-8-rep int-4-rep longlong-2-rep float-4-rep double-2-rep } +CONSTANT: all-reps + { + char-16-rep short-8-rep int-4-rep longlong-2-rep float-4-rep double-2-rep + uchar-16-rep ushort-8-rep uint-4-rep ulonglong-2-rep + } + +TUPLE: scalar-cpu ; + +TUPLE: simple-ops-cpu ; +M: simple-ops-cpu %zero-vector-reps all-reps ; +M: simple-ops-cpu %fill-vector-reps all-reps ; +M: simple-ops-cpu %add-vector-reps all-reps ; +M: simple-ops-cpu %sub-vector-reps all-reps ; +M: simple-ops-cpu %mul-vector-reps all-reps ; +M: simple-ops-cpu %div-vector-reps all-reps ; +M: simple-ops-cpu %andn-vector-reps all-reps ; +M: simple-ops-cpu %and-vector-reps all-reps ; +M: simple-ops-cpu %or-vector-reps all-reps ; +M: simple-ops-cpu %xor-vector-reps all-reps ; +M: simple-ops-cpu %merge-vector-reps all-reps ; +M: simple-ops-cpu %sqrt-vector-reps all-reps ; +M: simple-ops-cpu %test-vector-reps all-reps ; +M: simple-ops-cpu %signed-pack-vector-reps all-reps ; +M: simple-ops-cpu %unsigned-pack-vector-reps all-reps ; +M: simple-ops-cpu %gather-vector-2-reps { longlong-2-rep ulonglong-2-rep double-2-rep } ; +M: simple-ops-cpu %gather-vector-4-reps { int-4-rep uint-4-rep float-4-rep } ; +M: simple-ops-cpu %alien-vector-reps all-reps ; + +! v+ +[ { ##add-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-v+ ] test-emit ] +unit-test + +! v- +[ { ##sub-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-v- ] test-emit ] +unit-test + +! vneg +[ { ##load-constant ##sub-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vneg ] test-emit ] +unit-test + +[ { ##zero-vector ##sub-vector } ] +[ simple-ops-cpu int-4-rep [ emit-simd-vneg ] test-emit ] +unit-test + +! v* +[ { ##mul-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-v* ] test-emit ] +unit-test + +! v/ +[ { ##div-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-v/ ] test-emit ] +unit-test + +TUPLE: addsub-cpu < simple-ops-cpu ; +M: addsub-cpu %add-sub-vector-reps { int-4-rep float-4-rep } ; + +! v+- +[ { ##add-sub-vector } ] +[ addsub-cpu float-4-rep [ emit-simd-v+- ] test-emit ] +unit-test + +[ { ##load-constant ##xor-vector ##add-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-v+- ] test-emit ] +unit-test + +[ { ##load-constant ##xor-vector ##sub-vector ##add-vector } ] +[ simple-ops-cpu int-4-rep [ emit-simd-v+- ] test-emit ] +unit-test + +TUPLE: saturating-cpu < simple-ops-cpu ; +M: saturating-cpu %saturated-add-vector-reps { int-4-rep } ; +M: saturating-cpu %saturated-sub-vector-reps { int-4-rep } ; +M: saturating-cpu %saturated-mul-vector-reps { int-4-rep } ; + +! vs+ +[ { ##add-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vs+ ] test-emit ] +unit-test + +[ { ##add-vector } ] +[ saturating-cpu float-4-rep [ emit-simd-vs+ ] test-emit ] +unit-test + +[ { ##saturated-add-vector } ] +[ saturating-cpu int-4-rep [ emit-simd-vs+ ] test-emit ] +unit-test + +! vs- +[ { ##sub-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vs- ] test-emit ] +unit-test + +[ { ##sub-vector } ] +[ saturating-cpu float-4-rep [ emit-simd-vs- ] test-emit ] +unit-test + +[ { ##saturated-sub-vector } ] +[ saturating-cpu int-4-rep [ emit-simd-vs- ] test-emit ] +unit-test + +! vs* +[ { ##mul-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vs* ] test-emit ] +unit-test + +[ { ##mul-vector } ] +[ saturating-cpu float-4-rep [ emit-simd-vs* ] test-emit ] +unit-test + +[ { ##saturated-mul-vector } ] +[ saturating-cpu int-4-rep [ emit-simd-vs* ] test-emit ] +unit-test + +TUPLE: minmax-cpu < simple-ops-cpu ; +M: minmax-cpu %min-vector-reps signed-reps ; +M: minmax-cpu %max-vector-reps signed-reps ; +M: minmax-cpu %compare-vector-reps { cc= cc/= } member? [ signed-reps ] [ { } ] if ; +M: minmax-cpu %compare-vector-ccs nip f 2array 1array f ; + +TUPLE: compare-cpu < simple-ops-cpu ; +M: compare-cpu %compare-vector-reps drop signed-reps ; +M: compare-cpu %compare-vector-ccs nip f 2array 1array f ; + +! vmin +[ { ##min-vector } ] +[ minmax-cpu float-4-rep [ emit-simd-vmin ] test-emit ] +unit-test + +[ { ##compare-vector ##and-vector ##andn-vector ##or-vector } ] +[ compare-cpu float-4-rep [ emit-simd-vmin ] test-emit ] +unit-test + +! vmax +[ { ##max-vector } ] +[ minmax-cpu float-4-rep [ emit-simd-vmax ] test-emit ] +unit-test + +[ { ##compare-vector ##and-vector ##andn-vector ##or-vector } ] +[ compare-cpu float-4-rep [ emit-simd-vmax ] test-emit ] +unit-test + +TUPLE: dot-cpu < simple-ops-cpu ; +M: dot-cpu %dot-vector-reps { float-4-rep } ; + +TUPLE: horizontal-cpu < simple-ops-cpu ; +M: horizontal-cpu %horizontal-add-vector-reps signed-reps ; +M: horizontal-cpu %unpack-vector-head-reps signed-reps ; +M: horizontal-cpu %unpack-vector-tail-reps signed-reps ; + +! v. +[ { ##dot-vector } ] +[ dot-cpu float-4-rep [ emit-simd-v. ] test-emit ] +unit-test + +[ { ##mul-vector ##horizontal-add-vector ##horizontal-add-vector ##vector>scalar } ] +[ horizontal-cpu float-4-rep [ emit-simd-v. ] test-emit ] +unit-test + +[ { + ##mul-vector + ##merge-vector-head ##merge-vector-tail ##add-vector + ##merge-vector-head ##merge-vector-tail ##add-vector + ##vector>scalar +} ] +[ simple-ops-cpu float-4-rep [ emit-simd-v. ] test-emit ] +unit-test + +! vsqrt +[ { ##sqrt-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vsqrt ] test-emit ] +unit-test + +! sum +[ { ##horizontal-add-vector ##vector>scalar } ] +[ horizontal-cpu double-2-rep [ emit-simd-sum ] test-emit ] +unit-test + +[ { ##horizontal-add-vector ##horizontal-add-vector ##vector>scalar } ] +[ horizontal-cpu float-4-rep [ emit-simd-sum ] test-emit ] +unit-test + +[ { + ##unpack-vector-head ##unpack-vector-tail ##add-vector + ##horizontal-add-vector ##horizontal-add-vector + ##vector>scalar +} ] +[ horizontal-cpu short-8-rep [ emit-simd-sum ] test-emit ] +unit-test + +[ { + ##unpack-vector-head ##unpack-vector-tail ##add-vector + ##horizontal-add-vector ##horizontal-add-vector ##horizontal-add-vector + ##vector>scalar +} ] +[ horizontal-cpu char-16-rep [ emit-simd-sum ] test-emit ] +unit-test + +TUPLE: abs-cpu < simple-ops-cpu ; +M: abs-cpu %abs-vector-reps signed-reps ; + +! vabs +[ { } ] +[ simple-ops-cpu uint-4-rep [ emit-simd-vabs ] test-emit ] +unit-test + +[ { ##abs-vector } ] +[ abs-cpu float-4-rep [ emit-simd-vabs ] test-emit ] +unit-test + +[ { ##load-constant ##andn-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vabs ] test-emit ] +unit-test + +[ { ##zero-vector ##sub-vector ##compare-vector ##and-vector ##andn-vector ##or-vector } ] +[ compare-cpu int-4-rep [ emit-simd-vabs ] test-emit ] +unit-test + +! vand +[ { ##and-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vand ] test-emit ] +unit-test + +! vandn +[ { ##andn-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vandn ] test-emit ] +unit-test + +! vor +[ { ##or-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vor ] test-emit ] +unit-test + +! vxor +[ { ##xor-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vxor ] test-emit ] +unit-test + +TUPLE: not-cpu < simple-ops-cpu ; +M: not-cpu %not-vector-reps signed-reps ; + +! vnot +[ { ##not-vector } ] +[ not-cpu float-4-rep [ emit-simd-vnot ] test-emit ] +unit-test + +[ { ##fill-vector ##xor-vector } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vnot ] test-emit ] +unit-test + +TUPLE: shift-cpu < simple-ops-cpu ; +M: shift-cpu %shl-vector-reps signed-reps ; +M: shift-cpu %shr-vector-reps signed-reps ; + +TUPLE: shift-imm-cpu < simple-ops-cpu ; +M: shift-imm-cpu %shl-vector-imm-reps signed-reps ; +M: shift-imm-cpu %shr-vector-imm-reps signed-reps ; + +TUPLE: horizontal-shift-cpu < simple-ops-cpu ; +M: horizontal-shift-cpu %horizontal-shl-vector-imm-reps signed-reps ; +M: horizontal-shift-cpu %horizontal-shr-vector-imm-reps signed-reps ; + +! vlshift +[ { ##shl-vector-imm } ] +[ shift-imm-cpu 2 int-4-rep [ emit-simd-vlshift ] test-emit-literal ] +unit-test + +[ { ##shl-vector } ] +[ shift-cpu int-4-rep [ emit-simd-vlshift ] test-emit ] +unit-test + +! vrshift +[ { ##shr-vector-imm } ] +[ shift-imm-cpu 2 int-4-rep [ emit-simd-vrshift ] test-emit-literal ] +unit-test + +[ { ##shr-vector } ] +[ shift-cpu int-4-rep [ emit-simd-vrshift ] test-emit ] +unit-test + +! hlshift +[ { ##horizontal-shl-vector-imm } ] +[ horizontal-shift-cpu 2 int-4-rep [ emit-simd-hlshift ] test-emit-literal ] +unit-test + +! hrshift +[ { ##horizontal-shr-vector-imm } ] +[ horizontal-shift-cpu 2 int-4-rep [ emit-simd-hrshift ] test-emit-literal ] +unit-test + +TUPLE: shuffle-imm-cpu < simple-ops-cpu ; +M: shuffle-imm-cpu %shuffle-vector-imm-reps signed-reps ; + +TUPLE: shuffle-cpu < simple-ops-cpu ; +M: shuffle-cpu %shuffle-vector-reps signed-reps ; + +! vshuffle-elements +[ { ##load-constant ##shuffle-vector } ] +[ shuffle-cpu { 0 1 2 3 } int-4-rep [ emit-simd-vshuffle-elements ] test-emit-literal ] +unit-test + +[ { ##shuffle-vector-imm } ] +[ shuffle-imm-cpu { 0 1 2 3 } int-4-rep [ emit-simd-vshuffle-elements ] test-emit-literal ] +unit-test + +! vshuffle-bytes +[ { ##shuffle-vector } ] +[ shuffle-cpu int-4-rep [ emit-simd-vshuffle-bytes ] test-emit ] +unit-test + +! vmerge-head +[ { ##merge-vector-head } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vmerge-head ] test-emit ] +unit-test + +! vmerge-tail +[ { ##merge-vector-tail } ] +[ simple-ops-cpu float-4-rep [ emit-simd-vmerge-tail ] test-emit ] +unit-test + +! v<= etc. +[ { ##compare-vector } ] +[ compare-cpu int-4-rep [ emit-simd-v<= ] test-emit ] +unit-test + +[ { ##min-vector ##compare-vector } ] +[ minmax-cpu int-4-rep [ emit-simd-v<= ] test-emit ] +unit-test + +[ { ##load-constant ##xor-vector ##xor-vector ##compare-vector } ] +[ compare-cpu uint-4-rep [ emit-simd-v<= ] test-emit ] +unit-test + +! vany? etc. +[ { ##test-vector } ] +[ simple-ops-cpu int-4-rep [ emit-simd-vany? ] test-emit ] +unit-test + +TUPLE: convert-cpu < simple-ops-cpu ; +M: convert-cpu %integer>float-vector-reps { int-4-rep } ; +M: convert-cpu %float>integer-vector-reps { float-4-rep } ; + +! v>float +[ { } ] +[ convert-cpu float-4-rep [ emit-simd-v>float ] test-emit ] +unit-test + +[ { ##integer>float-vector } ] +[ convert-cpu int-4-rep [ emit-simd-v>float ] test-emit ] +unit-test + +! v>integer +[ { } ] +[ convert-cpu int-4-rep [ emit-simd-v>integer ] test-emit ] +unit-test + +[ { ##float>integer-vector } ] +[ convert-cpu float-4-rep [ emit-simd-v>integer ] test-emit ] +unit-test + +! vpack-signed +[ { ##signed-pack-vector } ] +[ simple-ops-cpu int-4-rep [ emit-simd-vpack-signed ] test-emit ] +unit-test + +! vpack-unsigned +[ { ##unsigned-pack-vector } ] +[ simple-ops-cpu int-4-rep [ emit-simd-vpack-unsigned ] test-emit ] +unit-test + +TUPLE: unpack-head-cpu < simple-ops-cpu ; +M: unpack-head-cpu %unpack-vector-head-reps all-reps ; +TUPLE: unpack-cpu < unpack-head-cpu ; +M: unpack-cpu %unpack-vector-tail-reps all-reps ; + +! vunpack-head +[ { ##unpack-vector-head } ] +[ unpack-head-cpu int-4-rep [ emit-simd-vunpack-head ] test-emit ] +unit-test + +[ { ##zero-vector ##merge-vector-head } ] +[ simple-ops-cpu uint-4-rep [ emit-simd-vunpack-head ] test-emit ] +unit-test + +[ { ##merge-vector-head ##shr-vector-imm } ] +[ shift-imm-cpu int-4-rep [ emit-simd-vunpack-head ] test-emit ] +unit-test + +[ { ##zero-vector ##compare-vector ##merge-vector-head } ] +[ compare-cpu int-4-rep [ emit-simd-vunpack-head ] test-emit ] +unit-test + +! vunpack-tail +[ { ##unpack-vector-tail } ] +[ unpack-cpu int-4-rep [ emit-simd-vunpack-tail ] test-emit ] +unit-test + +[ { ##tail>head-vector ##unpack-vector-head } ] +[ unpack-head-cpu int-4-rep [ emit-simd-vunpack-tail ] test-emit ] +unit-test + +[ { ##zero-vector ##merge-vector-tail } ] +[ simple-ops-cpu uint-4-rep [ emit-simd-vunpack-tail ] test-emit ] +unit-test + +[ { ##merge-vector-tail ##shr-vector-imm } ] +[ shift-imm-cpu int-4-rep [ emit-simd-vunpack-tail ] test-emit ] +unit-test + +[ { ##zero-vector ##compare-vector ##merge-vector-tail } ] +[ compare-cpu int-4-rep [ emit-simd-vunpack-tail ] test-emit ] +unit-test + +! with +[ { ##scalar>vector ##shuffle-vector-imm } ] +[ shuffle-imm-cpu float-4-rep [ emit-simd-with ] test-emit ] +unit-test + +! gather-2 +[ { ##gather-vector-2 } ] +[ simple-ops-cpu double-2-rep [ emit-simd-gather-2 ] test-emit ] +unit-test + +! gather-4 +[ { ##gather-vector-4 } ] +[ simple-ops-cpu float-4-rep [ emit-simd-gather-4 ] test-emit ] +unit-test + +! select +[ { ##shuffle-vector-imm ##vector>scalar } ] +[ shuffle-imm-cpu 1 float-4-rep [ emit-simd-select ] test-emit-literal ] +unit-test + +! test with nonliteral/invalid reps +[ simple-ops-cpu [ emit-simd-v+ ] test-emit-nonliteral-rep ] +[ bad-simd-intrinsic? ] must-fail-with + +[ simple-ops-cpu f [ emit-simd-v+ ] test-emit ] +[ bad-simd-intrinsic? ] must-fail-with + +[ simple-ops-cpu 3 [ emit-simd-v+ ] test-emit ] +[ bad-simd-intrinsic? ] must-fail-with + diff --git a/basis/compiler/cfg/intrinsics/simd/simd.factor b/basis/compiler/cfg/intrinsics/simd/simd.factor index a8dfaab2dd..c75e890c27 100644 --- a/basis/compiler/cfg/intrinsics/simd/simd.factor +++ b/basis/compiler/cfg/intrinsics/simd/simd.factor @@ -1,189 +1,26 @@ -! Copyright (C) 2009 Slava Pestov. +! Copyright (C) 2009 Slava Pestov, Joe Groff. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors alien byte-arrays fry classes.algebra -cpu.architecture kernel math sequences math.vectors -math.vectors.simd.intrinsics macros generalizations combinators -combinators.short-circuit arrays locals -compiler.tree.propagation.info compiler.cfg.builder.blocks +USING: accessors alien alien.c-types byte-arrays fry +classes.algebra cpu.architecture kernel layouts math sequences +math.vectors math.vectors.simd.intrinsics +macros generalizations combinators combinators.short-circuit +arrays locals compiler.tree.propagation.info +compiler.cfg.builder.blocks compiler.cfg.comparisons compiler.cfg.stacks compiler.cfg.stacks.local compiler.cfg.hats compiler.cfg.instructions compiler.cfg.registers +compiler.cfg.intrinsics compiler.cfg.intrinsics.alien +compiler.cfg.intrinsics.simd.backend specialized-arrays ; -FROM: alien.c-types => heap-size uchar ushort uint ulonglong float double ; -SPECIALIZED-ARRAYS: uchar ushort uint ulonglong float double ; +FROM: alien.c-types => heap-size char short int longlong float double ; +SPECIALIZED-ARRAYS: char uchar short ushort int uint longlong ulonglong float double ; IN: compiler.cfg.intrinsics.simd -MACRO: check-elements ( quots -- ) - [ length '[ _ firstn ] ] - [ '[ _ spread ] ] - [ length 1 - \ and [ ] like ] - tri 3append ; - -MACRO: if-literals-match ( quots -- ) - [ length ] [ ] [ length ] tri - ! n quots n - '[ - ! node quot - [ - dup node-input-infos - _ tail-slice* [ literal>> ] map - dup _ check-elements - ] dip - swap [ - ! node literals quot - [ _ firstn ] dip call - drop - ] [ 2drop emit-primitive ] if - ] ; - -: emit-vector-op ( node quot: ( rep -- ) -- ) - { [ representation? ] } if-literals-match ; inline - -: [binary] ( quot -- quot' ) - '[ [ ds-drop 2inputs ] dip @ ds-push ] ; inline - -: emit-binary-vector-op ( node quot -- ) - [binary] emit-vector-op ; inline - -: [unary] ( quot -- quot' ) - '[ [ ds-drop ds-pop ] dip @ ds-push ] ; inline - -: emit-unary-vector-op ( node quot -- ) - [unary] emit-vector-op ; inline - -: [unary/param] ( quot -- quot' ) - '[ [ -2 inc-d ds-pop ] 2dip @ ds-push ] ; inline - -: emit-shift-vector-imm-op ( node quot -- ) - [unary/param] - { [ integer? ] [ representation? ] } if-literals-match ; inline - -:: emit-shift-vector-op ( node imm-quot var-quot -- ) - node node-input-infos 2 tail-slice* first literal>> integer? - [ node imm-quot emit-shift-vector-imm-op ] - [ node var-quot emit-binary-vector-op ] if ; inline - -: emit-gather-vector-2 ( node -- ) - [ ^^gather-vector-2 ] emit-binary-vector-op ; - -: emit-gather-vector-4 ( node -- ) - [ - ds-drop - [ - D 3 peek-loc - D 2 peek-loc - D 1 peek-loc - D 0 peek-loc - -4 inc-d - ] dip - ^^gather-vector-4 - ds-push - ] emit-vector-op ; - -: shuffle? ( obj -- ? ) { [ array? ] [ [ integer? ] all? ] } 1&& ; - -: >variable-shuffle ( shuffle rep -- shuffle' ) - rep-component-type heap-size - [ dup >byte-array ] - [ iota >byte-array ] bi - '[ _ n*v _ v+ ] map concat ; - -: generate-shuffle-vector-imm ( src shuffle rep -- dst ) - dup %shuffle-vector-imm-reps member? - [ ^^shuffle-vector-imm ] - [ - [ >variable-shuffle ^^load-constant ] keep - ^^shuffle-vector - ] if ; - -: emit-shuffle-vector-imm ( node -- ) - ! Pad the permutation with zeroes if it's too short, since we - ! can't throw an error at this point. - [ [ rep-components 0 pad-tail ] keep generate-shuffle-vector-imm ] [unary/param] - { [ shuffle? ] [ representation? ] } if-literals-match ; - -: emit-shuffle-vector-var ( node -- ) - [ ^^shuffle-vector ] [binary] - { [ %shuffle-vector-reps member? ] } if-literals-match ; - -: emit-shuffle-vector ( node -- ) - dup node-input-infos { - [ length 3 = ] - [ first class>> byte-array class<= ] - [ second class>> byte-array class<= ] - [ third literal>> representation? ] - } 1&& [ emit-shuffle-vector-var ] [ emit-shuffle-vector-imm ] if ; - -: ^^broadcast-vector ( src n rep -- dst ) - [ rep-components swap ] keep - generate-shuffle-vector-imm ; - -: emit-broadcast-vector ( node -- ) - [ ^^broadcast-vector ] [unary/param] - { [ integer? ] [ representation? ] } if-literals-match ; - -: ^^with-vector ( src rep -- dst ) - [ ^^scalar>vector ] keep [ 0 ] dip ^^broadcast-vector ; - -: ^^select-vector ( src n rep -- dst ) - [ ^^broadcast-vector ] keep ^^vector>scalar ; - -: emit-select-vector ( node -- ) - [ ^^select-vector ] [unary/param] - { [ integer? ] [ representation? ] } if-literals-match ; inline - -: emit-alien-vector-op ( node quot: ( rep -- ) -- ) - { [ %alien-vector-reps member? ] } if-literals-match ; inline - -: emit-alien-vector ( node -- ) - dup [ - '[ - ds-drop prepare-alien-getter - _ ^^alien-vector ds-push - ] - [ inline-alien-getter? ] inline-alien - ] with emit-alien-vector-op ; - -: emit-set-alien-vector ( node -- ) - dup [ - '[ - ds-drop prepare-alien-setter ds-pop - _ ##set-alien-vector - ] - [ byte-array inline-alien-setter? ] - inline-alien - ] with emit-alien-vector-op ; - -: generate-not-vector ( src rep -- dst ) - dup %not-vector-reps member? - [ ^^not-vector ] - [ [ ^^fill-vector ] [ ^^xor-vector ] bi ] if ; - -:: ((generate-compare-vector)) ( src1 src2 rep {cc,swap} -- dst ) - {cc,swap} first2 :> ( cc swap? ) - swap? - [ src2 src1 rep cc ^^compare-vector ] - [ src1 src2 rep cc ^^compare-vector ] if ; - -:: (generate-compare-vector) ( src1 src2 rep orig-cc -- dst ) - rep orig-cc %compare-vector-ccs :> ( ccs not? ) - - ccs empty? - [ rep not? [ ^^fill-vector ] [ ^^zero-vector ] if ] - [ - ccs unclip :> ( rest-ccs first-cc ) - src1 src2 rep first-cc ((generate-compare-vector)) :> first-dst - - rest-ccs first-dst - [ [ src1 src2 rep ] dip ((generate-compare-vector)) rep ^^or-vector ] - reduce - - not? [ rep generate-not-vector ] when - ] if ; +! compound vector ops : sign-bit-mask ( rep -- byte-array ) - unsign-rep { + signed-rep { { char-16-rep [ uchar-array{ HEX: 80 HEX: 80 HEX: 80 HEX: 80 HEX: 80 HEX: 80 HEX: 80 HEX: 80 @@ -204,150 +41,628 @@ MACRO: if-literals-match ( quots -- ) } underlying>> ] } } case ; -:: (generate-minmax-compare-vector) ( src1 src2 rep orig-cc -- dst ) - orig-cc order-cc { - { cc< [ src1 src2 rep ^^max-vector src1 rep cc/= (generate-compare-vector) ] } - { cc<= [ src1 src2 rep ^^min-vector src1 rep cc= (generate-compare-vector) ] } - { cc> [ src1 src2 rep ^^min-vector src1 rep cc/= (generate-compare-vector) ] } - { cc>= [ src1 src2 rep ^^max-vector src1 rep cc= (generate-compare-vector) ] } - } case ; - -:: generate-compare-vector ( src1 src2 rep orig-cc -- dst ) +: ^load-neg-zero-vector ( rep -- dst ) { - { - [ rep orig-cc %compare-vector-reps member? ] - [ src1 src2 rep orig-cc (generate-compare-vector) ] - } - { - [ rep %min-vector-reps member? ] - [ src1 src2 rep orig-cc (generate-minmax-compare-vector) ] - } - { - [ rep unsign-rep orig-cc %compare-vector-reps member? ] - [ - rep sign-bit-mask ^^load-constant :> sign-bits - src1 sign-bits rep ^^xor-vector - src2 sign-bits rep ^^xor-vector - rep unsign-rep orig-cc (generate-compare-vector) - ] - } - } cond ; - -:: generate-unpack-vector-head ( src rep -- dst ) - { - { - [ rep %unpack-vector-head-reps member? ] - [ src rep ^^unpack-vector-head ] - } - { - [ rep unsigned-int-vector-rep? ] - [ - rep ^^zero-vector :> zero - src zero rep ^^merge-vector-head - ] - } - { - [ rep widen-vector-rep %shr-vector-imm-reps member? ] - [ - src src rep ^^merge-vector-head - rep rep-component-type - heap-size 8 * rep widen-vector-rep ^^shr-vector-imm - ] - } - [ - rep ^^zero-vector :> zero - zero src rep cc> ^^compare-vector :> sign - src sign rep ^^merge-vector-head - ] - } cond ; - -:: generate-unpack-vector-tail ( src rep -- dst ) - { - { - [ rep %unpack-vector-tail-reps member? ] - [ src rep ^^unpack-vector-tail ] - } - { - [ rep %unpack-vector-head-reps member? ] - [ - src rep ^^tail>head-vector :> tail - tail rep ^^unpack-vector-head - ] - } - { - [ rep unsigned-int-vector-rep? ] - [ - rep ^^zero-vector :> zero - src zero rep ^^merge-vector-tail - ] - } - { - [ rep widen-vector-rep %shr-vector-imm-reps member? ] - [ - src src rep ^^merge-vector-tail - rep rep-component-type - heap-size 8 * rep widen-vector-rep ^^shr-vector-imm - ] - } - [ - rep ^^zero-vector :> zero - zero src rep cc> ^^compare-vector :> sign - src sign rep ^^merge-vector-tail - ] - } cond ; - -:: generate-load-neg-zero-vector ( rep -- dst ) - rep { { float-4-rep [ float-array{ -0.0 -0.0 -0.0 -0.0 } underlying>> ^^load-constant ] } { double-2-rep [ double-array{ -0.0 -0.0 } underlying>> ^^load-constant ] } - [ drop rep ^^zero-vector ] } case ; -:: generate-neg-vector ( src rep -- dst ) - rep generate-load-neg-zero-vector - src rep ^^sub-vector ; +: ^load-add-sub-vector ( rep -- dst ) + signed-rep { + { float-4-rep [ float-array{ -0.0 0.0 -0.0 0.0 } underlying>> ^^load-constant ] } + { double-2-rep [ double-array{ -0.0 0.0 } underlying>> ^^load-constant ] } + { char-16-rep [ char-array{ -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 } underlying>> ^^load-constant ] } + { short-8-rep [ short-array{ -1 0 -1 0 -1 0 -1 0 } underlying>> ^^load-constant ] } + { int-4-rep [ int-array{ -1 0 -1 0 } underlying>> ^^load-constant ] } + { longlong-2-rep [ longlong-array{ -1 0 } underlying>> ^^load-constant ] } + } case ; -:: generate-blend-vector ( mask true false rep -- dst ) - mask true rep ^^and-vector +: ^load-half-vector ( rep -- dst ) + { + { float-4-rep [ float-array{ 0.5 0.5 0.5 0.5 } underlying>> ^^load-constant ] } + { double-2-rep [ double-array{ 0.5 0.5 } underlying>> ^^load-constant ] } + } case ; + +: >variable-shuffle ( shuffle rep -- shuffle' ) + rep-component-type heap-size + [ dup >byte-array ] + [ iota >byte-array ] bi + '[ _ n*v _ v+ ] map concat ; + +: ^load-immediate-shuffle ( shuffle rep -- dst ) + >variable-shuffle ^^load-constant ; + +:: ^blend-vector ( mask true false rep -- dst ) + true mask rep ^^and-vector mask false rep ^^andn-vector rep ^^or-vector ; -:: generate-abs-vector ( src rep -- dst ) +: ^not-vector ( src rep -- dst ) { - { - [ rep unsigned-int-vector-rep? ] - [ src ] - } - { - [ rep %abs-vector-reps member? ] - [ src rep ^^abs-vector ] - } - { - [ rep float-vector-rep? ] - [ - rep generate-load-neg-zero-vector - src rep ^^andn-vector - ] - } - [ + [ ^^not-vector ] + [ [ ^^fill-vector ] [ ^^xor-vector ] bi ] + } v-vector-op ; + +:: ^((compare-vector)) ( src1 src2 rep {cc,swap} -- dst ) + {cc,swap} first2 :> ( cc swap? ) + swap? + [ src2 src1 rep cc ^^compare-vector ] + [ src1 src2 rep cc ^^compare-vector ] if ; + +:: ^(compare-vector) ( src1 src2 rep orig-cc -- dst ) + rep orig-cc %compare-vector-ccs :> ( ccs not? ) + + ccs empty? + [ rep not? [ ^^fill-vector ] [ ^^zero-vector ] if ] + [ + ccs unclip :> ( rest-ccs first-cc ) + src1 src2 rep first-cc ^((compare-vector)) :> first-dst + + rest-ccs first-dst + [ [ src1 src2 rep ] dip ^((compare-vector)) rep ^^or-vector ] + reduce + + not? [ rep ^not-vector ] when + ] if ; + +:: ^minmax-compare-vector ( src1 src2 rep cc -- dst ) + cc order-cc { + { cc< [ src1 src2 rep ^^max-vector src1 rep cc/= ^(compare-vector) ] } + { cc<= [ src1 src2 rep ^^min-vector src1 rep cc= ^(compare-vector) ] } + { cc> [ src1 src2 rep ^^min-vector src1 rep cc/= ^(compare-vector) ] } + { cc>= [ src1 src2 rep ^^max-vector src1 rep cc= ^(compare-vector) ] } + } case ; + +: ^compare-vector ( src1 src2 rep cc -- dst ) + { + [ ^(compare-vector) ] + [ ^minmax-compare-vector ] + { unsigned-int-vector-rep [| src1 src2 rep cc | + rep sign-bit-mask ^^load-constant :> sign-bits + src1 sign-bits rep ^^xor-vector + src2 sign-bits rep ^^xor-vector + rep signed-rep cc ^(compare-vector) + ] } + } vv-cc-vector-op ; + +: ^unpack-vector-head ( src rep -- dst ) + { + [ ^^unpack-vector-head ] + { unsigned-int-vector-rep [ [ ^^zero-vector ] [ ^^merge-vector-head ] bi ] } + { signed-int-vector-rep [| src rep | + src src rep ^^merge-vector-head :> merged + rep rep-component-type heap-size 8 * :> bits + merged bits rep widen-vector-rep ^^shr-vector-imm + ] } + { signed-int-vector-rep [| src rep | + rep ^^zero-vector :> zero + zero src rep cc> ^compare-vector :> sign + src sign rep ^^merge-vector-head + ] } + } v-vector-op ; + +: ^unpack-vector-tail ( src rep -- dst ) + { + [ ^^unpack-vector-tail ] + [ [ ^^tail>head-vector ] [ ^^unpack-vector-head ] bi ] + { unsigned-int-vector-rep [ [ ^^zero-vector ] [ ^^merge-vector-tail ] bi ] } + { signed-int-vector-rep [| src rep | + src src rep ^^merge-vector-tail :> merged + rep rep-component-type heap-size 8 * :> bits + merged bits rep widen-vector-rep ^^shr-vector-imm + ] } + { signed-int-vector-rep [| src rep | + rep ^^zero-vector :> zero + zero src rep cc> ^compare-vector :> sign + src sign rep ^^merge-vector-tail + ] } + } v-vector-op ; + +PREDICATE: fixnum-vector-rep < int-vector-rep + rep-component-type heap-size cell < ; + +: ^(sum-vector-2) ( src rep -- dst ) + { + [ dupd ^^horizontal-add-vector ] + [| src rep | + src src rep ^^merge-vector-head :> head + src src rep ^^merge-vector-tail :> tail + head tail rep ^^add-vector + ] + } v-vector-op ; + +: ^(sum-vector-4) ( src rep -- dst ) + { + [ + [ dupd ^^horizontal-add-vector ] + [ dupd ^^horizontal-add-vector ] bi + ] + [| src rep | + src src rep ^^merge-vector-head :> head + src src rep ^^merge-vector-tail :> tail + head tail rep ^^add-vector :> src' + + rep widen-vector-rep :> rep' + src' src' rep' ^^merge-vector-head :> head' + src' src' rep' ^^merge-vector-tail :> tail' + head' tail' rep ^^add-vector + ] + } v-vector-op ; + +: ^(sum-vector-8) ( src rep -- dst ) + { + [ + [ dupd ^^horizontal-add-vector ] + [ dupd ^^horizontal-add-vector ] + [ dupd ^^horizontal-add-vector ] tri + ] + [| src rep | + src src rep ^^merge-vector-head :> head + src src rep ^^merge-vector-tail :> tail + head tail rep ^^add-vector :> src' + + rep widen-vector-rep :> rep' + src' src' rep' ^^merge-vector-head :> head' + src' src' rep' ^^merge-vector-tail :> tail' + head' tail' rep ^^add-vector :> src'' + + rep' widen-vector-rep :> rep'' + src'' src'' rep'' ^^merge-vector-head :> head'' + src'' src'' rep'' ^^merge-vector-tail :> tail'' + head'' tail'' rep ^^add-vector + ] + } v-vector-op ; + +: ^(sum-vector-16) ( src rep -- dst ) + { + [ + { + [ dupd ^^horizontal-add-vector ] + [ dupd ^^horizontal-add-vector ] + [ dupd ^^horizontal-add-vector ] + [ dupd ^^horizontal-add-vector ] + } cleave + ] + [| src rep | + src src rep ^^merge-vector-head :> head + src src rep ^^merge-vector-tail :> tail + head tail rep ^^add-vector :> src' + + rep widen-vector-rep :> rep' + src' src' rep' ^^merge-vector-head :> head' + src' src' rep' ^^merge-vector-tail :> tail' + head' tail' rep ^^add-vector :> src'' + + rep' widen-vector-rep :> rep'' + src'' src'' rep'' ^^merge-vector-head :> head'' + src'' src'' rep'' ^^merge-vector-tail :> tail'' + head'' tail'' rep ^^add-vector :> src''' + + rep'' widen-vector-rep :> rep''' + src''' src''' rep''' ^^merge-vector-head :> head''' + src''' src''' rep''' ^^merge-vector-tail :> tail''' + head''' tail''' rep ^^add-vector + ] + } v-vector-op ; + +: ^(sum-vector) ( src rep -- dst ) + [ + dup rep-length { + { 2 [ ^(sum-vector-2) ] } + { 4 [ ^(sum-vector-4) ] } + { 8 [ ^(sum-vector-8) ] } + { 16 [ ^(sum-vector-16) ] } + } case + ] [ ^^vector>scalar ] bi ; + +: ^sum-vector ( src rep -- dst ) + { + { float-vector-rep [ ^(sum-vector) ] } + { fixnum-vector-rep [| src rep | + src rep ^unpack-vector-head :> head + src rep ^unpack-vector-tail :> tail + rep widen-vector-rep :> wide-rep + head tail wide-rep ^^add-vector wide-rep + ^(sum-vector) + ] } + } v-vector-op ; + +: shuffle? ( obj -- ? ) { [ array? ] [ [ integer? ] all? ] } 1&& ; + +: ^shuffle-vector-imm ( src1 shuffle rep -- dst ) + [ rep-length 0 pad-tail ] keep { + [ ^^shuffle-vector-imm ] + [ [ ^load-immediate-shuffle ] [ ^^shuffle-vector ] bi ] + } vl-vector-op ; + +: ^broadcast-vector ( src n rep -- dst ) + [ rep-length swap ] keep + ^shuffle-vector-imm ; + +: ^with-vector ( src rep -- dst ) + [ ^^scalar>vector ] keep [ 0 ] dip ^broadcast-vector ; + +: ^select-vector ( src n rep -- dst ) + [ ^broadcast-vector ] keep ^^vector>scalar ; + +! intrinsic emitters + +: emit-simd-v+ ( node -- ) + { + [ ^^add-vector ] + } emit-vv-vector-op ; + +: emit-simd-v- ( node -- ) + { + [ ^^sub-vector ] + } emit-vv-vector-op ; + +: emit-simd-vneg ( node -- ) + { + { float-vector-rep [ [ ^load-neg-zero-vector swap ] [ ^^sub-vector ] bi ] } + { int-vector-rep [ [ ^^zero-vector swap ] [ ^^sub-vector ] bi ] } + } emit-v-vector-op ; + +: emit-simd-v+- ( node -- ) + { + [ ^^add-sub-vector ] + { float-vector-rep [| src1 src2 rep | + rep ^load-add-sub-vector :> signs + src2 signs rep ^^xor-vector :> src2' + src1 src2' rep ^^add-vector + ] } + { int-vector-rep [| src1 src2 rep | + rep ^load-add-sub-vector :> signs + src2 signs rep ^^xor-vector :> src2' + src2' signs rep ^^sub-vector :> src2'' + src1 src2'' rep ^^add-vector + ] } + } emit-vv-vector-op ; + +: emit-simd-vs+ ( node -- ) + { + { float-vector-rep [ ^^add-vector ] } + { int-vector-rep [ ^^saturated-add-vector ] } + } emit-vv-vector-op ; + +: emit-simd-vs- ( node -- ) + { + { float-vector-rep [ ^^sub-vector ] } + { int-vector-rep [ ^^saturated-sub-vector ] } + } emit-vv-vector-op ; + +: emit-simd-vs* ( node -- ) + { + { float-vector-rep [ ^^mul-vector ] } + { int-vector-rep [ ^^saturated-mul-vector ] } + } emit-vv-vector-op ; + +: emit-simd-v* ( node -- ) + { + [ ^^mul-vector ] + } emit-vv-vector-op ; + +: emit-simd-v*high ( node -- ) + { + [ ^^mul-high-vector ] + } emit-vv-vector-op ; + +: emit-simd-v*hs+ ( node -- ) + { + [ ^^mul-horizontal-add-vector ] + } emit-vv-vector-op ; + +: emit-simd-v/ ( node -- ) + { + [ ^^div-vector ] + } emit-vv-vector-op ; + +: emit-simd-vmin ( node -- ) + { + [ ^^min-vector ] + [ + [ cc< ^compare-vector ] + [ ^blend-vector ] 3bi + ] + } emit-vv-vector-op ; + +: emit-simd-vmax ( node -- ) + { + [ ^^max-vector ] + [ + [ cc> ^compare-vector ] + [ ^blend-vector ] 3bi + ] + } emit-vv-vector-op ; + +: emit-simd-vavg ( node -- ) + { + [ ^^avg-vector ] + { float-vector-rep [| src1 src2 rep | + src1 src2 rep ^^add-vector + rep ^load-half-vector rep ^^mul-vector + ] } + } emit-vv-vector-op ; + +: emit-simd-v. ( node -- ) + { + [ ^^dot-vector ] + { float-vector-rep [ [ ^^mul-vector ] [ ^sum-vector ] bi ] } + } emit-vv-vector-op ; + +: emit-simd-vsad ( node -- ) + { + [ + [ ^^sad-vector dup { 2 3 0 1 } int-4-rep ^^shuffle-vector-imm int-4-rep ^^add-vector ] + [ widen-vector-rep ^^vector>scalar ] bi + ] + } emit-vv-vector-op ; + +: emit-simd-vsqrt ( node -- ) + { + [ ^^sqrt-vector ] + } emit-v-vector-op ; + +: emit-simd-sum ( node -- ) + { + [ ^sum-vector ] + } emit-v-vector-op ; + +: emit-simd-vabs ( node -- ) + { + { unsigned-int-vector-rep [ drop ] } + [ ^^abs-vector ] + { float-vector-rep [ [ ^load-neg-zero-vector ] [ swapd ^^andn-vector ] bi ] } + { int-vector-rep [| src rep | rep ^^zero-vector :> zero zero src rep ^^sub-vector :> -src - zero src rep cc> ^^compare-vector :> sign - sign -src src rep generate-blend-vector + zero src rep cc> ^compare-vector :> sign + sign -src src rep ^blend-vector + ] } + } emit-v-vector-op ; + +: emit-simd-vand ( node -- ) + { + [ ^^and-vector ] + } emit-vv-vector-op ; + +: emit-simd-vandn ( node -- ) + { + [ ^^andn-vector ] + } emit-vv-vector-op ; + +: emit-simd-vor ( node -- ) + { + [ ^^or-vector ] + } emit-vv-vector-op ; + +: emit-simd-vxor ( node -- ) + { + [ ^^xor-vector ] + } emit-vv-vector-op ; + +: emit-simd-vnot ( node -- ) + { + [ ^not-vector ] + } emit-v-vector-op ; + +: emit-simd-vlshift ( node -- ) + { + [ ^^shl-vector ] + } { + [ ^^shl-vector-imm ] + } [ integer? ] emit-vv-or-vl-vector-op ; + +: emit-simd-vrshift ( node -- ) + { + [ ^^shr-vector ] + } { + [ ^^shr-vector-imm ] + } [ integer? ] emit-vv-or-vl-vector-op ; + +: emit-simd-hlshift ( node -- ) + { + [ ^^horizontal-shl-vector-imm ] + } [ integer? ] emit-vl-vector-op ; + +: emit-simd-hrshift ( node -- ) + { + [ ^^horizontal-shr-vector-imm ] + } [ integer? ] emit-vl-vector-op ; + +: emit-simd-vshuffle-elements ( node -- ) + { + [ ^shuffle-vector-imm ] + } [ shuffle? ] emit-vl-vector-op ; + +: emit-simd-vshuffle-bytes ( node -- ) + { + [ ^^shuffle-vector ] + } emit-vv-vector-op ; + +: emit-simd-vmerge-head ( node -- ) + { + [ ^^merge-vector-head ] + } emit-vv-vector-op ; + +: emit-simd-vmerge-tail ( node -- ) + { + [ ^^merge-vector-tail ] + } emit-vv-vector-op ; + +: emit-simd-v<= ( node -- ) + { + [ cc<= ^compare-vector ] + } emit-vv-vector-op ; +: emit-simd-v< ( node -- ) + { + [ cc< ^compare-vector ] + } emit-vv-vector-op ; +: emit-simd-v= ( node -- ) + { + [ cc= ^compare-vector ] + } emit-vv-vector-op ; +: emit-simd-v> ( node -- ) + { + [ cc> ^compare-vector ] + } emit-vv-vector-op ; +: emit-simd-v>= ( node -- ) + { + [ cc>= ^compare-vector ] + } emit-vv-vector-op ; +: emit-simd-vunordered? ( node -- ) + { + [ cc/<>= ^compare-vector ] + } emit-vv-vector-op ; + +: emit-simd-vany? ( node -- ) + { + [ vcc-any ^^test-vector ] + } emit-v-vector-op ; +: emit-simd-vall? ( node -- ) + { + [ vcc-all ^^test-vector ] + } emit-v-vector-op ; +: emit-simd-vnone? ( node -- ) + { + [ vcc-none ^^test-vector ] + } emit-v-vector-op ; + +: emit-simd-v>float ( node -- ) + { + { float-vector-rep [ drop ] } + { int-vector-rep [ ^^integer>float-vector ] } + } emit-v-vector-op ; + +: emit-simd-v>integer ( node -- ) + { + { float-vector-rep [ ^^float>integer-vector ] } + { int-vector-rep [ drop ] } + } emit-v-vector-op ; + +: emit-simd-vpack-signed ( node -- ) + { + [ ^^signed-pack-vector ] + } emit-vv-vector-op ; + +: emit-simd-vpack-unsigned ( node -- ) + { + [ ^^unsigned-pack-vector ] + } emit-vv-vector-op ; + +: emit-simd-vunpack-head ( node -- ) + { + [ ^unpack-vector-head ] + } emit-v-vector-op ; + +: emit-simd-vunpack-tail ( node -- ) + { + [ ^unpack-vector-tail ] + } emit-v-vector-op ; + +: emit-simd-with ( node -- ) + { + { fixnum-vector-rep [ ^with-vector ] } + { float-vector-rep [ ^with-vector ] } + } emit-v-vector-op ; + +: emit-simd-gather-2 ( node -- ) + { + { fixnum-vector-rep [ ^^gather-vector-2 ] } + { float-vector-rep [ ^^gather-vector-2 ] } + } emit-vv-vector-op ; + +: emit-simd-gather-4 ( node -- ) + { + { fixnum-vector-rep [ ^^gather-vector-4 ] } + { float-vector-rep [ ^^gather-vector-4 ] } + } emit-vvvv-vector-op ; + +: emit-simd-select ( node -- ) + { + { fixnum-vector-rep [ ^select-vector ] } + { float-vector-rep [ ^select-vector ] } + } [ integer? ] emit-vl-vector-op ; + +: emit-alien-vector ( node -- ) + dup [ + '[ + ds-drop prepare-alien-getter + _ ^^alien-vector ds-push ] - } cond ; + [ inline-alien-getter? ] inline-alien + ] with { [ %alien-vector-reps member? ] } if-literals-match ; -: generate-min-vector ( src1 src2 rep -- dst ) - dup %min-vector-reps member? - [ ^^min-vector ] [ - [ cc< generate-compare-vector ] - [ generate-blend-vector ] 3bi - ] if ; +: emit-set-alien-vector ( node -- ) + dup [ + '[ + ds-drop prepare-alien-setter ds-pop + _ ##set-alien-vector + ] + [ byte-array inline-alien-setter? ] + inline-alien + ] with { [ %alien-vector-reps member? ] } if-literals-match ; -: generate-max-vector ( src1 src2 rep -- dst ) - dup %max-vector-reps member? - [ ^^max-vector ] [ - [ cc> generate-compare-vector ] - [ generate-blend-vector ] 3bi - ] if ; +: enable-simd ( -- ) + { + { (simd-v+) [ emit-simd-v+ ] } + { (simd-v-) [ emit-simd-v- ] } + { (simd-vneg) [ emit-simd-vneg ] } + { (simd-v+-) [ emit-simd-v+- ] } + { (simd-vs+) [ emit-simd-vs+ ] } + { (simd-vs-) [ emit-simd-vs- ] } + { (simd-vs*) [ emit-simd-vs* ] } + { (simd-v*) [ emit-simd-v* ] } + { (simd-v*high) [ emit-simd-v*high ] } + { (simd-v*hs+) [ emit-simd-v*hs+ ] } + { (simd-v/) [ emit-simd-v/ ] } + { (simd-vmin) [ emit-simd-vmin ] } + { (simd-vmax) [ emit-simd-vmax ] } + { (simd-vavg) [ emit-simd-vavg ] } + { (simd-v.) [ emit-simd-v. ] } + { (simd-vsad) [ emit-simd-vsad ] } + { (simd-vsqrt) [ emit-simd-vsqrt ] } + { (simd-sum) [ emit-simd-sum ] } + { (simd-vabs) [ emit-simd-vabs ] } + { (simd-vbitand) [ emit-simd-vand ] } + { (simd-vbitandn) [ emit-simd-vandn ] } + { (simd-vbitor) [ emit-simd-vor ] } + { (simd-vbitxor) [ emit-simd-vxor ] } + { (simd-vbitnot) [ emit-simd-vnot ] } + { (simd-vand) [ emit-simd-vand ] } + { (simd-vandn) [ emit-simd-vandn ] } + { (simd-vor) [ emit-simd-vor ] } + { (simd-vxor) [ emit-simd-vxor ] } + { (simd-vnot) [ emit-simd-vnot ] } + { (simd-vlshift) [ emit-simd-vlshift ] } + { (simd-vrshift) [ emit-simd-vrshift ] } + { (simd-hlshift) [ emit-simd-hlshift ] } + { (simd-hrshift) [ emit-simd-hrshift ] } + { (simd-vshuffle-elements) [ emit-simd-vshuffle-elements ] } + { (simd-vshuffle-bytes) [ emit-simd-vshuffle-bytes ] } + { (simd-vmerge-head) [ emit-simd-vmerge-head ] } + { (simd-vmerge-tail) [ emit-simd-vmerge-tail ] } + { (simd-v<=) [ emit-simd-v<= ] } + { (simd-v<) [ emit-simd-v< ] } + { (simd-v=) [ emit-simd-v= ] } + { (simd-v>) [ emit-simd-v> ] } + { (simd-v>=) [ emit-simd-v>= ] } + { (simd-vunordered?) [ emit-simd-vunordered? ] } + { (simd-vany?) [ emit-simd-vany? ] } + { (simd-vall?) [ emit-simd-vall? ] } + { (simd-vnone?) [ emit-simd-vnone? ] } + { (simd-v>float) [ emit-simd-v>float ] } + { (simd-v>integer) [ emit-simd-v>integer ] } + { (simd-vpack-signed) [ emit-simd-vpack-signed ] } + { (simd-vpack-unsigned) [ emit-simd-vpack-unsigned ] } + { (simd-vunpack-head) [ emit-simd-vunpack-head ] } + { (simd-vunpack-tail) [ emit-simd-vunpack-tail ] } + { (simd-with) [ emit-simd-with ] } + { (simd-gather-2) [ emit-simd-gather-2 ] } + { (simd-gather-4) [ emit-simd-gather-4 ] } + { (simd-select) [ emit-simd-select ] } + { alien-vector [ emit-alien-vector ] } + { set-alien-vector [ emit-set-alien-vector ] } + } enable-intrinsics ; +enable-simd diff --git a/basis/compiler/cfg/intrinsics/slots/slots.factor b/basis/compiler/cfg/intrinsics/slots/slots.factor index 1424aba354..1ceac4990a 100644 --- a/basis/compiler/cfg/intrinsics/slots/slots.factor +++ b/basis/compiler/cfg/intrinsics/slots/slots.factor @@ -1,14 +1,17 @@ ! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: layouts namespaces kernel accessors sequences math -classes.algebra locals combinators cpu.architecture -compiler.tree.propagation.info compiler.cfg.stacks -compiler.cfg.hats compiler.cfg.registers +classes.algebra classes.builtin locals combinators +cpu.architecture compiler.tree.propagation.info +compiler.cfg.stacks compiler.cfg.hats compiler.cfg.registers compiler.cfg.instructions compiler.cfg.utilities compiler.cfg.builder.blocks compiler.constants ; IN: compiler.cfg.intrinsics.slots -: value-tag ( info -- n ) class>> class-type ; inline +: class-tag ( class -- tag/f ) + builtins get [ class<= ] with find drop ; + +: value-tag ( info -- n ) class>> class-tag ; : ^^tag-offset>slot ( slot tag -- vreg' ) [ ^^offset>slot ] dip ^^sub-imm ; diff --git a/basis/compiler/cfg/linearization/linearization.factor b/basis/compiler/cfg/linearization/linearization.factor old mode 100755 new mode 100644 diff --git a/basis/compiler/cfg/save-contexts/save-contexts-tests.factor b/basis/compiler/cfg/save-contexts/save-contexts-tests.factor index 23646cfcd7..020d000b6a 100644 --- a/basis/compiler/cfg/save-contexts/save-contexts-tests.factor +++ b/basis/compiler/cfg/save-contexts/save-contexts-tests.factor @@ -15,7 +15,7 @@ V{ [ V{ - T{ ##save-context f 1 2 f } + T{ ##save-context f 1 2 } T{ ##unary-float-function f 2 3 "sqrt" } T{ ##branch } } diff --git a/basis/compiler/cfg/save-contexts/save-contexts.factor b/basis/compiler/cfg/save-contexts/save-contexts.factor index fd92ace150..c7b6db0671 100644 --- a/basis/compiler/cfg/save-contexts/save-contexts.factor +++ b/basis/compiler/cfg/save-contexts/save-contexts.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2009 Slava Pestov. +! Copyright (C) 2009, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators.short-circuit compiler.cfg.instructions compiler.cfg.registers @@ -14,14 +14,7 @@ IN: compiler.cfg.save-contexts [ ##binary-float-function? ] [ ##alien-invoke? ] [ ##alien-indirect? ] - } 1|| - ] any? ; - -: needs-callback-context? ( insns -- ? ) - [ - { - [ ##alien-invoke? ] - [ ##alien-indirect? ] + [ ##alien-assembly? ] } 1|| ] any? ; @@ -29,7 +22,6 @@ IN: compiler.cfg.save-contexts dup instructions>> dup needs-save-context? [ int-rep next-vreg-rep int-rep next-vreg-rep - pick needs-callback-context? \ ##save-context new-insn prefix >>instructions drop ] [ 2drop ] if ; diff --git a/basis/compiler/cfg/stacks/stacks.factor b/basis/compiler/cfg/stacks/stacks.factor old mode 100755 new mode 100644 index ce673ba5bb..6cf362c230 --- a/basis/compiler/cfg/stacks/stacks.factor +++ b/basis/compiler/cfg/stacks/stacks.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: math sequences kernel namespaces accessors biassocs compiler.cfg compiler.cfg.instructions compiler.cfg.registers compiler.cfg.hats @@ -33,7 +33,7 @@ IN: compiler.cfg.stacks : ds-load ( n -- vregs ) dup 0 = [ drop f ] - [ [ [ peek-loc ] map ] [ neg inc-d ] bi ] if ; + [ [ iota [ peek-loc ] map ] [ neg inc-d ] bi ] if ; : ds-store ( vregs -- ) [ diff --git a/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor b/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor index 0bed759e52..e5fbfa6c40 100644 --- a/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor +++ b/basis/compiler/cfg/stacks/uninitialized/uninitialized.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2009 Slava Pestov. +! Copyright (C) 2009, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel sequences byte-arrays namespaces accessors classes math math.order fry arrays combinators compiler.cfg.registers @@ -55,7 +55,7 @@ M: insn visit-insn drop ; 2dup [ length ] bi@ max '[ _ 1 pad-tail ] bi@ [ bitand ] 2map ; : (uninitialized-locs) ( seq quot -- seq' ) - [ dup length [ drop 0 = ] pusher [ 2each ] dip ] dip map ; inline + [ [ drop 0 = ] pusher [ each-index ] dip ] dip map ; inline PRIVATE> diff --git a/basis/compiler/cfg/value-numbering/expressions/expressions.factor b/basis/compiler/cfg/value-numbering/expressions/expressions.factor index 6534aa74ab..d2e7c2ac86 100644 --- a/basis/compiler/cfg/value-numbering/expressions/expressions.factor +++ b/basis/compiler/cfg/value-numbering/expressions/expressions.factor @@ -27,6 +27,9 @@ C: reference-expr M: reference-expr equal? over reference-expr? [ [ value>> ] bi@ eq? ] [ 2drop f ] if ; +M: reference-expr hashcode* + nip value>> identity-hashcode ; + : constant>vn ( constant -- vn ) expr>vn ; inline GENERIC: >expr ( insn -- expr ) diff --git a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor old mode 100755 new mode 100644 index 4864a8bfb7..0fa0314c3e --- a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor +++ b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators combinators.short-circuit arrays fry kernel layouts math namespaces sequences cpu.architecture -math.bitwise math.order math.vectors.simd.intrinsics classes +math.bitwise math.order classes vectors locals make alien.c-types io.binary grouping compiler.cfg compiler.cfg.registers @@ -42,6 +42,14 @@ M: insn rewrite drop f ; ] [ drop f ] if ; inline : general-compare-expr? ( insn -- ? ) + { + [ compare-expr? ] + [ compare-imm-expr? ] + [ compare-float-unordered-expr? ] + [ compare-float-ordered-expr? ] + } 1|| ; + +: general-or-vector-compare-expr? ( insn -- ? ) { [ compare-expr? ] [ compare-imm-expr? ] @@ -52,7 +60,7 @@ M: insn rewrite drop f ; : rewrite-boolean-comparison? ( insn -- ? ) dup ##branch-t? [ - src1>> vreg>expr general-compare-expr? + src1>> vreg>expr general-or-vector-compare-expr? ] [ drop f ] if ; inline : >compare-expr< ( expr -- in1 in2 cc ) @@ -463,100 +471,9 @@ M: ##alien-signed-2 rewrite rewrite-alien-addressing ; M: ##alien-signed-4 rewrite rewrite-alien-addressing ; M: ##alien-float rewrite rewrite-alien-addressing ; M: ##alien-double rewrite rewrite-alien-addressing ; -M: ##alien-vector rewrite rewrite-alien-addressing ; M: ##set-alien-integer-1 rewrite rewrite-alien-addressing ; M: ##set-alien-integer-2 rewrite rewrite-alien-addressing ; M: ##set-alien-integer-4 rewrite rewrite-alien-addressing ; M: ##set-alien-float rewrite rewrite-alien-addressing ; M: ##set-alien-double rewrite rewrite-alien-addressing ; -M: ##set-alien-vector rewrite rewrite-alien-addressing ; -! Some lame constant folding for SIMD intrinsics. Eventually this -! should be redone completely. - -: rewrite-shuffle-vector-imm ( insn expr -- insn' ) - 2dup [ rep>> ] bi@ eq? [ - [ [ dst>> ] [ src>> vn>vreg ] bi* ] - [ [ shuffle>> ] bi@ nths ] - [ drop rep>> ] - 2tri \ ##shuffle-vector-imm new-insn - ] [ 2drop f ] if ; - -: (fold-shuffle-vector-imm) ( shuffle bytes -- bytes' ) - 2dup length swap length /i group nths concat ; - -: fold-shuffle-vector-imm ( insn expr -- insn' ) - [ [ dst>> ] [ shuffle>> ] bi ] dip value>> - (fold-shuffle-vector-imm) \ ##load-constant new-insn ; - -M: ##shuffle-vector-imm rewrite - dup src>> vreg>expr { - { [ dup shuffle-vector-imm-expr? ] [ rewrite-shuffle-vector-imm ] } - { [ dup reference-expr? ] [ fold-shuffle-vector-imm ] } - { [ dup constant-expr? ] [ fold-shuffle-vector-imm ] } - [ 2drop f ] - } cond ; - -: (fold-scalar>vector) ( insn bytes -- insn' ) - [ [ dst>> ] [ rep>> rep-components ] bi ] dip concat - \ ##load-constant new-insn ; - -: fold-scalar>vector ( insn expr -- insn' ) - value>> over rep>> { - { float-4-rep [ float>bits 4 >le (fold-scalar>vector) ] } - { double-2-rep [ double>bits 8 >le (fold-scalar>vector) ] } - [ [ untag-fixnum ] dip rep-component-type heap-size >le (fold-scalar>vector) ] - } case ; - -M: ##scalar>vector rewrite - dup src>> vreg>expr dup constant-expr? - [ fold-scalar>vector ] [ 2drop f ] if ; - -M: ##xor-vector rewrite - dup [ src1>> vreg>vn ] [ src2>> vreg>vn ] bi eq? - [ [ dst>> ] [ rep>> ] bi \ ##zero-vector new-insn ] [ drop f ] if ; - -: vector-not? ( expr -- ? ) - { - [ not-vector-expr? ] - [ { - [ xor-vector-expr? ] - [ [ src1>> ] [ src2>> ] bi [ vn>expr fill-vector-expr? ] either? ] - } 1&& ] - } 1|| ; - -GENERIC: vector-not-src ( expr -- vreg ) -M: not-vector-expr vector-not-src src>> vn>vreg ; -M: xor-vector-expr vector-not-src - dup src1>> vn>expr fill-vector-expr? [ src2>> ] [ src1>> ] if vn>vreg ; - -M: ##and-vector rewrite - { - { [ dup src1>> vreg>expr vector-not? ] [ - { - [ dst>> ] - [ src1>> vreg>expr vector-not-src ] - [ src2>> ] - [ rep>> ] - } cleave \ ##andn-vector new-insn - ] } - { [ dup src2>> vreg>expr vector-not? ] [ - { - [ dst>> ] - [ src2>> vreg>expr vector-not-src ] - [ src1>> ] - [ rep>> ] - } cleave \ ##andn-vector new-insn - ] } - [ drop f ] - } cond ; - -M: ##andn-vector rewrite - dup src1>> vreg>expr vector-not? [ - { - [ dst>> ] - [ src1>> vreg>expr vector-not-src ] - [ src2>> ] - [ rep>> ] - } cleave \ ##and-vector new-insn - ] [ drop f ] if ; diff --git a/basis/compiler/cfg/value-numbering/simd/simd.factor b/basis/compiler/cfg/value-numbering/simd/simd.factor new file mode 100644 index 0000000000..16d38bc5bb --- /dev/null +++ b/basis/compiler/cfg/value-numbering/simd/simd.factor @@ -0,0 +1,120 @@ +! Copyright (C) 2008, 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors combinators combinators.short-circuit arrays +fry kernel layouts math namespaces sequences cpu.architecture +math.bitwise math.order classes +vectors locals make alien.c-types io.binary grouping +math.vectors.simd.intrinsics +compiler.cfg +compiler.cfg.registers +compiler.cfg.comparisons +compiler.cfg.instructions +compiler.cfg.value-numbering.expressions +compiler.cfg.value-numbering.graph +compiler.cfg.value-numbering.rewrite +compiler.cfg.value-numbering.simplify ; +IN: compiler.cfg.value-numbering.simd + +M: ##alien-vector rewrite rewrite-alien-addressing ; +M: ##set-alien-vector rewrite rewrite-alien-addressing ; + +! Some lame constant folding for SIMD intrinsics. Eventually this +! should be redone completely. + +: rewrite-shuffle-vector-imm ( insn expr -- insn' ) + 2dup [ rep>> ] bi@ eq? [ + [ [ dst>> ] [ src>> vn>vreg ] bi* ] + [ [ shuffle>> ] bi@ nths ] + [ drop rep>> ] + 2tri \ ##shuffle-vector-imm new-insn + ] [ 2drop f ] if ; + +: (fold-shuffle-vector-imm) ( shuffle bytes -- bytes' ) + 2dup length swap length /i group nths concat ; + +: fold-shuffle-vector-imm ( insn expr -- insn' ) + [ [ dst>> ] [ shuffle>> ] bi ] dip value>> + (fold-shuffle-vector-imm) \ ##load-constant new-insn ; + +M: ##shuffle-vector-imm rewrite + dup src>> vreg>expr { + { [ dup shuffle-vector-imm-expr? ] [ rewrite-shuffle-vector-imm ] } + { [ dup reference-expr? ] [ fold-shuffle-vector-imm ] } + { [ dup constant-expr? ] [ fold-shuffle-vector-imm ] } + [ 2drop f ] + } cond ; + +: (fold-scalar>vector) ( insn bytes -- insn' ) + [ [ dst>> ] [ rep>> rep-length ] bi ] dip concat + \ ##load-constant new-insn ; + +: fold-scalar>vector ( insn expr -- insn' ) + value>> over rep>> { + { float-4-rep [ float>bits 4 >le (fold-scalar>vector) ] } + { double-2-rep [ double>bits 8 >le (fold-scalar>vector) ] } + [ [ untag-fixnum ] dip rep-component-type heap-size >le (fold-scalar>vector) ] + } case ; + +M: ##scalar>vector rewrite + dup src>> vreg>expr dup constant-expr? + [ fold-scalar>vector ] [ 2drop f ] if ; + +M: ##xor-vector rewrite + dup [ src1>> vreg>vn ] [ src2>> vreg>vn ] bi eq? + [ [ dst>> ] [ rep>> ] bi \ ##zero-vector new-insn ] [ drop f ] if ; + +: vector-not? ( expr -- ? ) + { + [ not-vector-expr? ] + [ { + [ xor-vector-expr? ] + [ [ src1>> ] [ src2>> ] bi [ vn>expr fill-vector-expr? ] either? ] + } 1&& ] + } 1|| ; + +GENERIC: vector-not-src ( expr -- vreg ) +M: not-vector-expr vector-not-src src>> vn>vreg ; +M: xor-vector-expr vector-not-src + dup src1>> vn>expr fill-vector-expr? [ src2>> ] [ src1>> ] if vn>vreg ; + +M: ##and-vector rewrite + { + { [ dup src1>> vreg>expr vector-not? ] [ + { + [ dst>> ] + [ src1>> vreg>expr vector-not-src ] + [ src2>> ] + [ rep>> ] + } cleave \ ##andn-vector new-insn + ] } + { [ dup src2>> vreg>expr vector-not? ] [ + { + [ dst>> ] + [ src2>> vreg>expr vector-not-src ] + [ src1>> ] + [ rep>> ] + } cleave \ ##andn-vector new-insn + ] } + [ drop f ] + } cond ; + +M: ##andn-vector rewrite + dup src1>> vreg>expr vector-not? [ + { + [ dst>> ] + [ src1>> vreg>expr vector-not-src ] + [ src2>> ] + [ rep>> ] + } cleave \ ##and-vector new-insn + ] [ drop f ] if ; + +M: scalar>vector-expr simplify* + src>> vn>expr { + { [ dup vector>scalar-expr? ] [ src>> ] } + [ drop f ] + } cond ; + +M: shuffle-vector-imm-expr simplify* + [ src>> ] [ shuffle>> ] [ rep>> rep-length iota ] tri + sequence= [ drop f ] unless ; + diff --git a/basis/compiler/cfg/value-numbering/simplify/simplify.factor b/basis/compiler/cfg/value-numbering/simplify/simplify.factor index df3dc6aab9..7a95711b01 100644 --- a/basis/compiler/cfg/value-numbering/simplify/simplify.factor +++ b/basis/compiler/cfg/value-numbering/simplify/simplify.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel accessors combinators classes math layouts -sequences math.vectors.simd.intrinsics +sequences compiler.cfg.instructions compiler.cfg.value-numbering.graph compiler.cfg.value-numbering.expressions ; @@ -130,16 +130,6 @@ M: box-displaced-alien-expr simplify* [ 2drop f ] } cond ; -M: scalar>vector-expr simplify* - src>> vn>expr { - { [ dup vector>scalar-expr? ] [ src>> ] } - [ drop f ] - } cond ; - -M: shuffle-vector-imm-expr simplify* - [ src>> ] [ shuffle>> ] [ rep>> rep-components iota ] tri - sequence= [ drop f ] unless ; - M: expr simplify* drop f ; : simplify ( expr -- vn ) diff --git a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor index b404c4d4a4..ac992ff98d 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor @@ -4,7 +4,7 @@ cpu.architecture tools.test kernel math combinators.short-circuit accessors sequences compiler.cfg.predecessors locals compiler.cfg.dce compiler.cfg.ssa.destruction compiler.cfg.loop-detection compiler.cfg.representations compiler.cfg assocs vectors arrays -layouts literals namespaces alien ; +layouts literals namespaces alien compiler.cfg.value-numbering.simd ; IN: compiler.cfg.value-numbering.tests : trim-temps ( insns -- insns ) diff --git a/basis/compiler/codegen/codegen.factor b/basis/compiler/codegen/codegen.factor old mode 100755 new mode 100644 index 15c4e14ac1..ef6794e9fa --- a/basis/compiler/codegen/codegen.factor +++ b/basis/compiler/codegen/codegen.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: namespaces make math math.order math.parser sequences accessors kernel kernel.private layouts assocs words summary arrays @@ -40,7 +40,7 @@ SYMBOL: labels V{ } clone calls set ; : generate-insns ( asm -- code ) - dup word>> [ + dup label>> [ init-generator instructions>> [ [ class insn-counts get inc-at ] @@ -61,9 +61,7 @@ SYMBOL: labels ! Special cases M: ##no-tco generate-insn drop ; -M: ##call generate-insn - word>> dup sub-primitive>> - [ second first % ] [ [ add-call ] [ %call ] bi ] ?if ; +M: ##call generate-insn word>> [ add-call ] [ %call ] bi ; M: ##jump generate-insn word>> [ add-call ] [ %jump ] bi ; @@ -173,11 +171,15 @@ CODEGEN: ##add-sub-vector %add-sub-vector CODEGEN: ##sub-vector %sub-vector CODEGEN: ##saturated-sub-vector %saturated-sub-vector CODEGEN: ##mul-vector %mul-vector +CODEGEN: ##mul-high-vector %mul-high-vector +CODEGEN: ##mul-horizontal-add-vector %mul-horizontal-add-vector CODEGEN: ##saturated-mul-vector %saturated-mul-vector CODEGEN: ##div-vector %div-vector CODEGEN: ##min-vector %min-vector CODEGEN: ##max-vector %max-vector +CODEGEN: ##avg-vector %avg-vector CODEGEN: ##dot-vector %dot-vector +CODEGEN: ##sad-vector %sad-vector CODEGEN: ##sqrt-vector %sqrt-vector CODEGEN: ##horizontal-add-vector %horizontal-add-vector CODEGEN: ##horizontal-sub-vector %horizontal-sub-vector @@ -281,7 +283,7 @@ M: ##gc generate-insn [ [ uninitialized-locs>> ] [ temp1>> ] bi wipe-locs ] [ data-values>> save-data-regs ] [ [ tagged-values>> ] [ temp1>> ] bi save-gc-roots ] - [ [ temp1>> ] [ temp2>> ] bi t %save-context ] + [ [ temp1>> ] [ temp2>> ] bi %save-context ] [ [ tagged-values>> length ] [ temp1>> ] bi %call-gc ] [ [ tagged-values>> ] [ temp1>> ] bi load-gc-roots ] [ data-values>> load-data-regs ] @@ -378,11 +380,11 @@ M: c-type-name flatten-value-type c-type flatten-value-type ; [ [ parameter-offsets nip ] keep ] dip 2reverse-each ; inline : prepare-unbox-parameters ( parameters -- offsets types indices ) - [ parameter-offsets nip ] [ ] [ length iota reverse ] tri ; + [ parameter-offsets nip ] [ ] [ length iota ] tri ; : unbox-parameters ( offset node -- ) parameters>> swap - '[ prepare-unbox-parameters [ %prepare-unbox [ _ + ] dip unbox-parameter ] 3each ] + '[ prepare-unbox-parameters [ %pop-stack [ _ + ] dip unbox-parameter ] 3each ] [ length neg %inc-d ] bi ; @@ -405,7 +407,7 @@ M: c-type-name flatten-value-type c-type flatten-value-type ; ] with-param-regs ; : box-return* ( node -- ) - return>> [ ] [ box-return ] if-void ; + return>> [ ] [ box-return %push-stack ] if-void ; : check-dlsym ( symbols dll -- ) dup dll-valid? [ @@ -434,6 +436,16 @@ M: ##alien-invoke generate-insn dup %cleanup box-return* ; +M: ##alien-assembly generate-insn + params>> + ! Unbox parameters + dup objects>registers + %prepare-var-args + ! Generate assembly + dup quot>> call( -- ) + ! Box return value + box-return* ; + ! ##alien-indirect M: ##alien-indirect generate-insn params>> @@ -450,7 +462,7 @@ M: ##alien-indirect generate-insn ! ##alien-callback : box-parameters ( params -- ) - alien-parameters [ box-parameter ] each-parameter ; + alien-parameters [ box-parameter %push-context-stack ] each-parameter ; : registers>objects ( node -- ) ! Generate code for boxing input parameters in a callback. @@ -462,7 +474,7 @@ M: ##alien-indirect generate-insn TUPLE: callback-context ; -: current-callback ( -- id ) 2 getenv ; +: current-callback ( -- id ) 2 special-object ; : wait-to-return ( token -- ) dup current-callback eq? [ @@ -473,7 +485,7 @@ TUPLE: callback-context ; : do-callback ( quot token -- ) init-catchstack - [ 2 setenv call ] keep + [ 2 set-special-object call ] keep wait-to-return ; inline : callback-return-quot ( ctype -- quot ) @@ -494,11 +506,6 @@ TUPLE: callback-context ; [ callback-context new do-callback ] % ] [ ] make ; -M: ##callback-return generate-insn - #! All the extra book-keeping for %unwind is only for x86. - #! On other platforms its an alias for %return. - params>> %callback-return ; - M: ##alien-callback generate-insn params>> [ registers>objects ] diff --git a/basis/compiler/codegen/fixup/fixup.factor b/basis/compiler/codegen/fixup/fixup.factor old mode 100755 new mode 100644 index 21a8db807b..eef517a2bb --- a/basis/compiler/codegen/fixup/fixup.factor +++ b/basis/compiler/codegen/fixup/fixup.factor @@ -1,15 +1,20 @@ -! Copyright (C) 2007, 2009 Slava Pestov. +! Copyright (C) 2007, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: 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 -accessors growable fry generalizations compiler.constants ; +system combinators math.bitwise math.order generalizations +accessors growable fry compiler.constants memoize ; IN: compiler.codegen.fixup ! Owner SYMBOL: compiling-word +! Parameter table +SYMBOL: parameter-table + +: add-parameter ( obj -- ) parameter-table get push ; + ! Literal table SYMBOL: literal-table @@ -29,13 +34,10 @@ TUPLE: label offset ; dup label? [ get ] unless compiled-offset >>offset drop ; -: offset-for-class ( class -- n ) - rc-absolute-cell = cell 4 ? compiled-offset swap - ; - TUPLE: label-fixup { label label } { class integer } { offset integer } ; : label-fixup ( label class -- ) - dup offset-for-class \ label-fixup boa label-table get push ; + compiled-offset \ label-fixup boa label-table get push ; ! Relocation table SYMBOL: relocation-table @@ -48,28 +50,28 @@ SYMBOL: relocation-table { 0 24 28 } bitfield relocation-table get push-4 ; : rel-fixup ( class type -- ) - swap dup offset-for-class add-relocation-entry ; + swap compiled-offset add-relocation-entry ; -: add-dlsym-literals ( symbol dll -- ) - [ string>symbol add-literal ] [ add-literal ] bi* ; +! Caching common symbol names reduces image size a bit +MEMO: cached-string>symbol ( symbol -- obj ) string>symbol ; + +: add-dlsym-parameters ( symbol dll -- ) + [ cached-string>symbol add-parameter ] [ add-parameter ] bi* ; : rel-dlsym ( name dll class -- ) - [ add-dlsym-literals ] dip rt-dlsym rel-fixup ; + [ add-dlsym-parameters ] dip rt-dlsym rel-fixup ; : rel-word ( word class -- ) - [ add-literal ] dip rt-xt rel-fixup ; + [ add-literal ] dip rt-entry-point rel-fixup ; : rel-word-pic ( word class -- ) - [ add-literal ] dip rt-xt-pic rel-fixup ; + [ add-literal ] dip rt-entry-point-pic rel-fixup ; : rel-word-pic-tail ( word class -- ) - [ add-literal ] dip rt-xt-pic-tail rel-fixup ; - -: rel-primitive ( word class -- ) - [ def>> first add-literal ] dip rt-primitive rel-fixup ; + [ add-literal ] dip rt-entry-point-pic-tail rel-fixup ; : rel-immediate ( literal class -- ) - [ add-literal ] dip rt-immediate rel-fixup ; + [ add-literal ] dip rt-literal rel-fixup ; : rel-this ( class -- ) rt-this rel-fixup ; @@ -78,7 +80,7 @@ SYMBOL: relocation-table [ add-literal ] dip rt-here rel-fixup ; : rel-vm ( offset class -- ) - [ add-literal ] dip rt-vm rel-fixup ; + [ add-parameter ] dip rt-vm rel-fixup ; : rel-cards-offset ( class -- ) rt-cards-offset rel-fixup ; @@ -105,6 +107,7 @@ SYMBOL: relocation-table : init-fixup ( word -- ) compiling-word set + V{ } clone parameter-table set V{ } clone literal-table set V{ } clone label-table set BV{ } clone relocation-table set ; @@ -114,7 +117,7 @@ SYMBOL: relocation-table init-fixup @ label-table [ resolve-labels ] change - compiling-word get + parameter-table get >array literal-table get >array relocation-table get >byte-array label-table get diff --git a/basis/compiler/compiler.factor b/basis/compiler/compiler.factor old mode 100755 new mode 100644 index e58cf0c834..2375d8575d --- a/basis/compiler/compiler.factor +++ b/basis/compiler/compiler.factor @@ -5,13 +5,16 @@ continuations vocabs assocs dlists definitions math graphs generic generic.single combinators deques search-deques macros source-files.errors combinators.short-circuit -stack-checker stack-checker.state stack-checker.inlining stack-checker.errors +stack-checker stack-checker.dependencies stack-checker.inlining +stack-checker.errors compiler.errors compiler.units compiler.utilities compiler.tree.builder compiler.tree.optimizer +compiler.crossref + compiler.cfg compiler.cfg.builder compiler.cfg.optimizer @@ -29,7 +32,6 @@ SYMBOL: compiled [ "forgotten" word-prop ] [ compiled get key? ] [ inlined-block? ] - [ primitive? ] } 1|| not ; : queue-compile ( word -- ) @@ -60,17 +62,23 @@ M: method-body no-compile? "method-generic" word-prop no-compile? ; M: predicate-engine-word no-compile? "owner-generic" word-prop no-compile? ; M: word no-compile? - { - [ macro? ] - [ inline? ] - [ "special" word-prop ] - [ "no-compile" word-prop ] - } 1|| ; + { [ macro? ] [ "special" word-prop ] [ "no-compile" word-prop ] } 1|| ; + +GENERIC: combinator? ( word -- ? ) + +M: method-body combinator? "method-generic" word-prop combinator? ; + +M: predicate-engine-word combinator? "owner-generic" word-prop combinator? ; + +M: word combinator? inline? ; : ignore-error? ( word error -- ? ) #! Ignore some errors on inline combinators, macros, and special #! words such as 'call'. - [ no-compile? ] [ { [ do-not-compile? ] [ literal-expected? ] } 1|| ] bi* and ; + { + [ drop no-compile? ] + [ [ combinator? ] [ unknown-macro-input? ] bi* and ] + } 2|| ; : finish ( word -- ) #! Recompile callers if the word's stack effect changed, then @@ -117,7 +125,10 @@ M: word no-compile? } cond ; : optimize? ( word -- ? ) - single-generic? not ; + { + [ single-generic? ] + [ primitive? ] + } 1|| not ; : contains-breakpoints? ( -- ? ) dependencies get keys [ "break?" word-prop ] any? ; @@ -193,6 +204,14 @@ M: optimizing-compiler recompile ( words -- alist ) ] with-scope "--- compile done" compiler-message ; +M: optimizing-compiler to-recompile ( -- words ) + changed-definitions get compiled-usages + changed-generics get compiled-generic-usages + append assoc-combine keys ; + +M: optimizing-compiler process-forgotten-words + [ delete-compiled-xref ] each ; + : with-optimizer ( quot -- ) [ optimizing-compiler compiler-impl ] dip with-variable ; inline diff --git a/basis/compiler/constants/constants.factor b/basis/compiler/constants/constants.factor index 19cdb6eebd..73e77cca4d 100644 --- a/basis/compiler/constants/constants.factor +++ b/basis/compiler/constants/constants.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: math kernel layouts system strings words quotations byte-arrays alien arrays literals sequences ; @@ -20,11 +20,18 @@ CONSTANT: deck-bits 18 : alien-offset ( -- n ) 4 alien type-number slot-offset ; inline : underlying-alien-offset ( -- n ) 1 alien type-number slot-offset ; inline : tuple-class-offset ( -- n ) 1 tuple type-number slot-offset ; inline -: word-xt-offset ( -- n ) 10 \ word type-number slot-offset ; inline -: quot-xt-offset ( -- n ) 4 quotation type-number slot-offset ; inline +: word-entry-point-offset ( -- n ) 10 \ word type-number slot-offset ; inline +: quot-entry-point-offset ( -- n ) 4 quotation type-number slot-offset ; inline : word-code-offset ( -- n ) 11 \ word type-number slot-offset ; inline : array-start-offset ( -- n ) 2 array type-number slot-offset ; inline : compiled-header-size ( -- n ) 4 bootstrap-cells ; inline +: callstack-length-offset ( -- n ) 1 \ callstack type-number slot-offset ; inline +: callstack-top-offset ( -- n ) 2 \ callstack type-number slot-offset ; inline +: vm-context-offset ( -- n ) 0 bootstrap-cells ; inline +: context-callstack-top-offset ( -- n ) 0 bootstrap-cells ; inline +: context-callstack-bottom-offset ( -- n ) 1 bootstrap-cells ; inline +: context-datastack-offset ( -- n ) 2 bootstrap-cells ; inline +: context-retainstack-offset ( -- n ) 3 bootstrap-cells ; inline ! Relocation classes CONSTANT: rc-absolute-cell 0 @@ -37,23 +44,21 @@ CONSTANT: rc-relative-ppc-3 6 CONSTANT: rc-relative-arm-3 7 CONSTANT: rc-indirect-arm 8 CONSTANT: rc-indirect-arm-pc 9 +CONSTANT: rc-absolute-2 10 ! Relocation types -CONSTANT: rt-primitive 0 -CONSTANT: rt-dlsym 1 -CONSTANT: rt-dispatch 2 -CONSTANT: rt-xt 3 -CONSTANT: rt-xt-pic 4 -CONSTANT: rt-xt-pic-tail 5 -CONSTANT: rt-here 6 -CONSTANT: rt-this 7 -CONSTANT: rt-immediate 8 -CONSTANT: rt-stack-chain 9 -CONSTANT: rt-untagged 10 -CONSTANT: rt-megamorphic-cache-hits 11 -CONSTANT: rt-vm 12 -CONSTANT: rt-cards-offset 13 -CONSTANT: rt-decks-offset 14 +CONSTANT: rt-dlsym 0 +CONSTANT: rt-entry-point 1 +CONSTANT: rt-entry-point-pic 2 +CONSTANT: rt-entry-point-pic-tail 3 +CONSTANT: rt-here 4 +CONSTANT: rt-this 5 +CONSTANT: rt-literal 6 +CONSTANT: rt-untagged 7 +CONSTANT: rt-megamorphic-cache-hits 8 +CONSTANT: rt-vm 9 +CONSTANT: rt-cards-offset 10 +CONSTANT: rt-decks-offset 11 : rc-absolute? ( n -- ? ) ${ rc-absolute-ppc-2/2 rc-absolute-cell rc-absolute } member? ; diff --git a/basis/cords/authors.txt b/basis/compiler/crossref/authors.txt similarity index 100% rename from basis/cords/authors.txt rename to basis/compiler/crossref/authors.txt diff --git a/basis/compiler/crossref/crossref.factor b/basis/compiler/crossref/crossref.factor new file mode 100644 index 0000000000..e6ef5cf17c --- /dev/null +++ b/basis/compiler/crossref/crossref.factor @@ -0,0 +1,68 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: assocs classes.algebra compiler.units definitions graphs +grouping kernel namespaces sequences words +stack-checker.dependencies ; +IN: compiler.crossref + +SYMBOL: compiled-crossref + +compiled-crossref [ H{ } clone ] initialize + +SYMBOL: compiled-generic-crossref + +compiled-generic-crossref [ H{ } clone ] initialize + +: compiled-usage ( word -- assoc ) + compiled-crossref get at ; + +: (compiled-usages) ( word -- assoc ) + #! If the word is not flushable anymore, we have to recompile + #! all words which flushable away a call (presumably when the + #! word was still flushable). If the word is flushable, we + #! don't have to recompile words that folded this away. + [ compiled-usage ] + [ "flushable" word-prop inlined-dependency flushed-dependency ? ] bi + [ dependency>= nip ] curry assoc-filter ; + +: compiled-usages ( seq -- assocs ) + [ drop word? ] assoc-filter + [ [ drop (compiled-usages) ] { } assoc>map ] keep suffix ; + +: compiled-generic-usage ( word -- assoc ) + compiled-generic-crossref get at ; + +: (compiled-generic-usages) ( generic class -- assoc ) + [ compiled-generic-usage ] dip + [ + 2dup [ valid-class? ] both? + [ classes-intersect? ] [ 2drop f ] if nip + ] curry assoc-filter ; + +: compiled-generic-usages ( assoc -- assocs ) + [ (compiled-generic-usages) ] { } assoc>map ; + +: (compiled-xref) ( word dependencies word-prop variable -- ) + [ [ concat ] dip set-word-prop ] [ get add-vertex* ] bi-curry* 2bi ; + +: compiled-xref ( word dependencies generic-dependencies -- ) + [ [ drop crossref? ] { } assoc-filter-as ] bi@ + [ "compiled-uses" compiled-crossref (compiled-xref) ] + [ "compiled-generic-uses" compiled-generic-crossref (compiled-xref) ] + bi-curry* bi ; + +: (compiled-unxref) ( word word-prop variable -- ) + [ [ [ dupd word-prop 2 ] dip get remove-vertex* ] 2curry ] + [ drop [ remove-word-prop ] curry ] + 2bi bi ; + +: compiled-unxref ( word -- ) + [ "compiled-uses" compiled-crossref (compiled-unxref) ] + [ "compiled-generic-uses" compiled-generic-crossref (compiled-unxref) ] + bi ; + +: delete-compiled-xref ( word -- ) + [ compiled-unxref ] + [ compiled-crossref get delete-at ] + [ compiled-generic-crossref get delete-at ] + tri ; diff --git a/basis/compiler/tests/alien.factor b/basis/compiler/tests/alien.factor old mode 100755 new mode 100644 index 04ee02a5d7..4cfbe8f6fa --- a/basis/compiler/tests/alien.factor +++ b/basis/compiler/tests/alien.factor @@ -94,6 +94,8 @@ FUNCTION: TINY ffi_test_17 int x ; { 1 1 } [ indirect-test-1 ] must-infer-as +[ B{ } indirect-test-1 ] [ { "kernel-error" 3 6 B{ } } = ] must-fail-with + [ 3 ] [ &: ffi_test_1 indirect-test-1 ] unit-test : indirect-test-1' ( ptr -- ) @@ -162,7 +164,7 @@ FUNCTION: void ffi_test_20 double x1, double x2, double x3, { int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int } alien-invoke gc 3 ; -[ 861 3 ] [ 42 [ ] each ffi_test_31 ] unit-test +[ 861 3 ] [ 42 [ ] each-integer ffi_test_31 ] unit-test : ffi_test_31_point_5 ( a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a -- result ) float @@ -170,7 +172,7 @@ FUNCTION: void ffi_test_20 double x1, double x2, double x3, { float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float } alien-invoke ; -[ 861.0 ] [ 42 [ >float ] each ffi_test_31_point_5 ] unit-test +[ 861.0 ] [ 42 [ >float ] each-integer ffi_test_31_point_5 ] unit-test FUNCTION: longlong ffi_test_21 long x long y ; @@ -314,7 +316,7 @@ FUNCTION: ulonglong ffi_test_38 ( ulonglong x, ulonglong y ) ; : callback-1 ( -- callback ) void { } "cdecl" [ ] alien-callback ; -[ 0 1 ] [ [ callback-1 ] infer [ in>> ] [ out>> ] bi ] unit-test +[ 0 1 ] [ [ callback-1 ] infer [ in>> length ] [ out>> length ] bi ] unit-test [ t ] [ callback-1 alien? ] unit-test @@ -375,9 +377,7 @@ FUNCTION: ulonglong ffi_test_38 ( ulonglong x, ulonglong y ) ; [ f ] [ namespace global eq? ] unit-test : callback-8 ( -- callback ) - void { } "cdecl" [ - [ continue ] callcc0 - ] alien-callback ; + void { } "cdecl" [ [ ] in-thread yield ] alien-callback ; [ ] [ callback-8 callback_test_1 ] unit-test @@ -588,5 +588,9 @@ FUNCTION: short ffi_test_48 ( bool-field-test x ) ; ! Regression: calling an undefined function would raise a protection fault FUNCTION: void this_does_not_exist ( ) ; -[ this_does_not_exist ] [ { "kernel-error" 10 f f } = ] must-fail-with +[ this_does_not_exist ] [ { "kernel-error" 9 f f } = ] must-fail-with +! More alien-assembly tests are in cpu.* vocabs +: assembly-test-1 ( -- ) void { } "cdecl" [ ] alien-assembly ; + +[ ] [ assembly-test-1 ] unit-test diff --git a/basis/compiler/tests/codegen.factor b/basis/compiler/tests/codegen.factor index eba6580574..cff685eaf6 100644 --- a/basis/compiler/tests/codegen.factor +++ b/basis/compiler/tests/codegen.factor @@ -116,7 +116,7 @@ unit-test 1 1.0 2.5 try-breaking-dispatch "bye" = [ 3.5 = ] dip and ; [ t ] [ - 10000000 [ drop try-breaking-dispatch-2 ] all? + 10000000 [ drop try-breaking-dispatch-2 ] all-integers? ] unit-test ! Regression @@ -314,7 +314,7 @@ cell 4 = [ ! Bug with ##return node construction : return-recursive-bug ( nodes -- ? ) - { fixnum } declare [ + { fixnum } declare iota [ dup 3 bitand 1 = [ drop t ] [ dup 3 bitand 2 = [ return-recursive-bug diff --git a/basis/compiler/tests/float.factor b/basis/compiler/tests/float.factor index 14b347008c..632a560c0d 100644 --- a/basis/compiler/tests/float.factor +++ b/basis/compiler/tests/float.factor @@ -1,5 +1,5 @@ USING: compiler.units compiler kernel kernel.private memory math -math.private tools.test math.floats.private ; +math.private tools.test math.floats.private math.order fry ; IN: compiler.tests.float [ 5.0 ] [ [ 5.0 ] compile-call gc gc gc ] unit-test @@ -84,11 +84,6 @@ IN: compiler.tests.float [ 315 315.0 ] [ 313 [ 2 fixnum+fast dup fixnum>float ] compile-call ] unit-test -[ 17.5 ] [ -11.3 17.5 [ float-max ] compile-call ] unit-test -[ 17.5 ] [ 17.5 -11.3 [ float-max ] compile-call ] unit-test -[ -11.3 ] [ -11.3 17.5 [ float-min ] compile-call ] unit-test -[ -11.3 ] [ 17.5 -11.3 [ float-min ] compile-call ] unit-test - [ t ] [ 0/0. 0/0. [ float-unordered? ] compile-call ] unit-test [ t ] [ 0/0. 1.0 [ float-unordered? ] compile-call ] unit-test [ t ] [ 1.0 0/0. [ float-unordered? ] compile-call ] unit-test @@ -100,3 +95,23 @@ IN: compiler.tests.float [ 1 ] [ 1.0 0/0. [ float-unordered? [ 1 ] [ 2 ] if ] compile-call ] unit-test [ 2 ] [ 3.0 1.0 [ float-unordered? [ 1 ] [ 2 ] if ] compile-call ] unit-test [ 2 ] [ 1.0 3.0 [ float-unordered? [ 1 ] [ 2 ] if ] compile-call ] unit-test + +! Ensure that float-min and min, and float-max and max, have +! consistent behavior with respect to NaNs + +: two-floats ( a b -- a b ) { float float } declare ; inline + +[ -11.3 ] [ -11.3 17.5 [ two-floats min ] compile-call ] unit-test +[ -11.3 ] [ 17.5 -11.3 [ two-floats min ] compile-call ] unit-test +[ 17.5 ] [ -11.3 17.5 [ two-floats max ] compile-call ] unit-test +[ 17.5 ] [ 17.5 -11.3 [ two-floats max ] compile-call ] unit-test + +: check-compiled-binary-op ( a b word -- ) + [ '[ [ [ two-floats _ execute ] compile-call ] call( a b -- c ) ] ] + [ '[ _ execute ] ] + bi 2bi fp-bitwise= ; inline + +[ t ] [ 0/0. 3.0 \ min check-compiled-binary-op ] unit-test +[ t ] [ 3.0 0/0. \ min check-compiled-binary-op ] unit-test +[ t ] [ 0/0. 3.0 \ max check-compiled-binary-op ] unit-test +[ t ] [ 3.0 0/0. \ max check-compiled-binary-op ] unit-test diff --git a/basis/compiler/tests/intrinsics.factor b/basis/compiler/tests/intrinsics.factor old mode 100755 new mode 100644 index a26ba5a27a..1c066f26a3 --- a/basis/compiler/tests/intrinsics.factor +++ b/basis/compiler/tests/intrinsics.factor @@ -21,7 +21,6 @@ IN: compiler.tests.intrinsics [ 2 1 3 ] [ 1 2 3 [ swapd ] compile-call ] unit-test [ 2 ] [ 1 2 [ nip ] compile-call ] unit-test [ 3 ] [ 1 2 3 [ 2nip ] compile-call ] unit-test -[ 2 1 2 ] [ 1 2 [ tuck ] compile-call ] unit-test [ 1 2 1 ] [ 1 2 [ over ] compile-call ] unit-test [ 1 2 3 1 ] [ 1 2 3 [ pick ] compile-call ] unit-test [ 2 1 ] [ 1 2 [ swap ] compile-call ] unit-test @@ -55,8 +54,8 @@ IN: compiler.tests.intrinsics [ HEX: 123456 ] [ 1 [ "a\u123456c" string-nth ] compile-call ] unit-test [ HEX: 123456 ] [ [ 1 "a\u123456c" string-nth ] compile-call ] unit-test -[ ] [ [ 0 getenv ] compile-call drop ] unit-test -[ ] [ 1 getenv [ 1 setenv ] compile-call ] unit-test +[ ] [ [ 0 special-object ] compile-call drop ] unit-test +[ ] [ 1 special-object [ 1 set-special-object ] compile-call ] unit-test [ ] [ 1 [ drop ] compile-call ] unit-test [ ] [ [ 1 drop ] compile-call ] unit-test @@ -338,7 +337,7 @@ ERROR: bug-in-fixnum* x y a b ; [ ] [ 10000 [ - 5 random [ drop 32 random-bits ] map product >bignum + 5 random iota [ drop 32 random-bits ] map product >bignum dup [ bignum>fixnum ] keep compiled-bignum>fixnum = [ drop ] [ "Oops" throw ] if ] times @@ -586,16 +585,16 @@ TUPLE: alien-accessor-regression { b byte-array } { i fixnum } ; swap [ { tuple } declare 1 slot ] [ - 0 slot + 1 slot ] if ; -[ t ] [ f B{ } mutable-value-bug-1 byte-array type-number = ] unit-test +[ 0 ] [ f { } mutable-value-bug-1 ] unit-test : mutable-value-bug-2 ( a b -- c ) swap [ - 0 slot + 1 slot ] [ { tuple } declare 1 slot ] if ; -[ t ] [ t B{ } mutable-value-bug-2 byte-array type-number = ] unit-test +[ 0 ] [ t { } mutable-value-bug-2 ] unit-test diff --git a/basis/compiler/tests/optimizer.factor b/basis/compiler/tests/optimizer.factor index 0831d6e8dd..865cd639a3 100644 --- a/basis/compiler/tests/optimizer.factor +++ b/basis/compiler/tests/optimizer.factor @@ -4,7 +4,7 @@ sbufs strings tools.test vectors words sequences.private quotations classes classes.algebra classes.tuple.private continuations growable namespaces hints alien.accessors compiler.tree.builder compiler.tree.optimizer sequences.deep -compiler definitions generic.single shuffle ; +compiler definitions generic.single shuffle math.order ; IN: compiler.tests.optimizer GENERIC: xyz ( obj -- obj ) @@ -90,7 +90,7 @@ TUPLE: pred-test ; : double-label-2 ( a -- b ) dup array? [ ] [ ] if 0 t double-label-1 ; -[ 0 ] [ 10 double-label-2 ] unit-test +[ 0 ] [ 10 iota double-label-2 ] unit-test ! regression GENERIC: void-generic ( obj -- * ) @@ -208,7 +208,7 @@ USE: binary-search.private ] if ; inline recursive [ 10 ] [ - 10 20 >vector + 10 20 iota [ [ - ] swap old-binsearch ] compile-call 2nip ] unit-test @@ -349,7 +349,7 @@ TUPLE: some-tuple x ; [ 5 ] [ { 1 2 { 3 { 4 5 } } } deep-find-test ] unit-test [ f ] [ { 1 2 { 3 { 4 } } } deep-find-test ] unit-test -[ B{ 0 1 2 3 4 5 6 7 } ] [ [ 8 [ ] B{ } map-as ] compile-call ] unit-test +[ B{ 0 1 2 3 4 5 6 7 } ] [ [ 8 iota [ ] B{ } map-as ] compile-call ] unit-test [ 0 ] [ 1234 [ { fixnum } declare -64 shift ] compile-call ] unit-test @@ -445,5 +445,17 @@ M: object bad-dispatch-position-test* ; [ 1024 bignum ] [ 10 [ 1 >bignum swap >fixnum shift ] compile-call dup class ] unit-test -! Not sure if I want to fix this... -! [ t [ [ f ] [ 3 ] if >fixnum ] compile-call ] [ no-method? ] must-fail-with +TUPLE: grid-mesh-tuple { length read-only } { step read-only } ; + +: grid-mesh-test-case ( -- vertices ) + 1.0 1.0 { 2 } first /f [ /i 1 + ] keep grid-mesh-tuple boa + 1 f + [ + [ drop length>> >fixnum 2 min ] 2keep + [ + [ step>> 1 * ] dip + 0 swap set-nth-unsafe + ] 2curry times + ] keep ; + +[ { 0.5 } ] [ grid-mesh-test-case ] unit-test diff --git a/basis/compiler/tests/redefine3.factor b/basis/compiler/tests/redefine3.factor index 67added49d..913111b8ea 100644 --- a/basis/compiler/tests/redefine3.factor +++ b/basis/compiler/tests/redefine3.factor @@ -1,6 +1,6 @@ USING: accessors compiler compiler.units tools.test math parser kernel sequences sequences.private classes.mixin generic -definitions arrays words assocs eval ; +definitions arrays words assocs eval grouping ; IN: compiler.tests.redefine3 GENERIC: sheeple ( obj -- x ) @@ -13,20 +13,23 @@ M: empty-mixin sheeple drop "wake up" ; inline : sheeple-test ( -- string ) { } sheeple ; +: compiled-use? ( key word -- ? ) + "compiled-uses" word-prop 2 key? ; + [ "sheeple" ] [ sheeple-test ] unit-test [ t ] [ \ sheeple-test optimized? ] unit-test -[ t ] [ object \ sheeple method \ sheeple-test "compiled-uses" word-prop key? ] unit-test -[ f ] [ empty-mixin \ sheeple method \ sheeple-test "compiled-uses" word-prop key? ] unit-test +[ t ] [ object \ sheeple method \ sheeple-test compiled-use? ] unit-test +[ f ] [ empty-mixin \ sheeple method \ sheeple-test compiled-use? ] unit-test [ ] [ "IN: compiler.tests.redefine3 USE: arrays INSTANCE: array empty-mixin" eval( -- ) ] unit-test [ "wake up" ] [ sheeple-test ] unit-test -[ f ] [ object \ sheeple method \ sheeple-test "compiled-uses" word-prop key? ] unit-test -[ t ] [ empty-mixin \ sheeple method \ sheeple-test "compiled-uses" word-prop key? ] unit-test +[ f ] [ object \ sheeple method \ sheeple-test compiled-use? ] unit-test +[ t ] [ empty-mixin \ sheeple method \ sheeple-test compiled-use? ] unit-test [ ] [ [ array empty-mixin remove-mixin-instance ] with-compilation-unit ] unit-test [ "sheeple" ] [ sheeple-test ] unit-test [ t ] [ \ sheeple-test optimized? ] unit-test -[ t ] [ object \ sheeple method \ sheeple-test "compiled-uses" word-prop key? ] unit-test -[ f ] [ empty-mixin \ sheeple method \ sheeple-test "compiled-uses" word-prop key? ] unit-test +[ t ] [ object \ sheeple method \ sheeple-test compiled-use? ] unit-test +[ f ] [ empty-mixin \ sheeple method \ sheeple-test compiled-use? ] unit-test diff --git a/basis/compiler/tests/stack-trace.factor b/basis/compiler/tests/stack-trace.factor old mode 100755 new mode 100644 diff --git a/basis/compiler/tree/builder/builder-tests.factor b/basis/compiler/tree/builder/builder-tests.factor old mode 100755 new mode 100644 diff --git a/basis/compiler/tree/builder/builder.factor b/basis/compiler/tree/builder/builder.factor index e4523deb9f..8eb66fde1f 100644 --- a/basis/compiler/tree/builder/builder.factor +++ b/basis/compiler/tree/builder/builder.factor @@ -39,7 +39,7 @@ M: word (build-tree) [ recursive-state set V{ } clone stack-visitor set - [ [ >vector \ meta-d set ] [ length d-in set ] bi ] + [ [ >vector \ meta-d set ] [ length input-count set ] bi ] [ (build-tree) ] bi* ] with-infer nip ; diff --git a/basis/compiler/tree/checker/checker.factor b/basis/compiler/tree/checker/checker.factor old mode 100755 new mode 100644 index 0b3b46fe33..b3f01c8c01 --- a/basis/compiler/tree/checker/checker.factor +++ b/basis/compiler/tree/checker/checker.factor @@ -185,9 +185,7 @@ M: #recursive check-stack-flow* M: #copy check-stack-flow* [ check-in-d ] [ check-out-d ] bi ; -M: #alien-invoke check-stack-flow* [ check-in-d ] [ check-out-d ] bi ; - -M: #alien-indirect check-stack-flow* [ check-in-d ] [ check-out-d ] bi ; +M: #alien-node check-stack-flow* [ check-in-d ] [ check-out-d ] bi ; M: #alien-callback check-stack-flow* drop ; diff --git a/basis/compiler/tree/cleanup/cleanup-tests.factor b/basis/compiler/tree/cleanup/cleanup-tests.factor old mode 100755 new mode 100644 index db96086371..05f9092ee1 --- a/basis/compiler/tree/cleanup/cleanup-tests.factor +++ b/basis/compiler/tree/cleanup/cleanup-tests.factor @@ -339,28 +339,23 @@ cell-bits 32 = [ ] unit-test [ t ] [ - [ { fixnum } declare length [ drop ] each-integer ] + [ { fixnum } declare iota [ drop ] each ] { < <-integer-fixnum +-integer-fixnum + } inlined? ] unit-test [ t ] [ - [ { fixnum } declare [ drop ] each ] - { < <-integer-fixnum +-integer-fixnum + } inlined? -] unit-test - -[ t ] [ - [ { fixnum } declare 0 [ + ] reduce ] + [ { fixnum } declare iota 0 [ + ] reduce ] { < <-integer-fixnum nth-unsafe } inlined? ] unit-test [ f ] [ - [ { fixnum } declare 0 [ + ] reduce ] + [ { fixnum } declare iota 0 [ + ] reduce ] \ +-integer-fixnum inlined? ] unit-test [ f ] [ [ - { integer } declare [ ] map + { integer } declare iota [ ] map ] \ >fixnum inlined? ] unit-test @@ -403,7 +398,7 @@ cell-bits 32 = [ [ t ] [ [ - { integer } declare [ 0 >= ] map + { integer } declare iota [ 0 >= ] map ] { >= fixnum>= } inlined? ] unit-test diff --git a/basis/compiler/tree/cleanup/cleanup.factor b/basis/compiler/tree/cleanup/cleanup.factor index 8ed83188e5..ec819d0eac 100644 --- a/basis/compiler/tree/cleanup/cleanup.factor +++ b/basis/compiler/tree/cleanup/cleanup.factor @@ -3,7 +3,7 @@ USING: kernel accessors sequences combinators fry classes.algebra namespaces assocs words math math.private math.partial-dispatch math.intervals classes classes.tuple -classes.tuple.private layouts definitions stack-checker.state +classes.tuple.private layouts definitions stack-checker.dependencies stack-checker.branches compiler.utilities compiler.tree diff --git a/basis/compiler/tree/combinators/combinators.factor b/basis/compiler/tree/combinators/combinators.factor old mode 100755 new mode 100644 diff --git a/basis/compiler/tree/dead-code/branches/branches.factor b/basis/compiler/tree/dead-code/branches/branches.factor index 6cef45a9c9..d1fdf6359a 100644 --- a/basis/compiler/tree/dead-code/branches/branches.factor +++ b/basis/compiler/tree/dead-code/branches/branches.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: sequences namespaces kernel accessors assocs sets fry arrays combinators columns stack-checker.backend @@ -36,7 +36,7 @@ M: #branch remove-dead-code* : drop-indexed-values ( values indices -- node ) [ drop filter-live ] [ swap nths ] 2bi - [ make-values ] keep + [ length make-values ] keep [ drop ] [ zip ] 2bi #data-shuffle ; diff --git a/basis/compiler/tree/dead-code/recursive/recursive.factor b/basis/compiler/tree/dead-code/recursive/recursive.factor index 482d370947..0c9464374a 100644 --- a/basis/compiler/tree/dead-code/recursive/recursive.factor +++ b/basis/compiler/tree/dead-code/recursive/recursive.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: accessors arrays assocs sequences kernel locals fry combinators stack-checker.backend @@ -24,7 +24,7 @@ M: #call-recursive compute-live-values* :: drop-dead-inputs ( inputs outputs -- #shuffle ) inputs filter-live - outputs inputs filter-corresponding make-values + outputs inputs filter-corresponding length make-values outputs inputs drop-values ; @@ -39,7 +39,7 @@ M: #enter-recursive remove-dead-code* 2bi ; :: (drop-call-recursive-outputs) ( inputs outputs -- #shuffle ) - inputs outputs filter-corresponding make-values :> new-live-outputs + inputs outputs filter-corresponding length make-values :> new-live-outputs outputs filter-live :> live-outputs new-live-outputs live-outputs diff --git a/basis/compiler/tree/dead-code/simple/simple.factor b/basis/compiler/tree/dead-code/simple/simple.factor old mode 100755 new mode 100644 index f6165a44ab..77523568d7 --- a/basis/compiler/tree/dead-code/simple/simple.factor +++ b/basis/compiler/tree/dead-code/simple/simple.factor @@ -1,8 +1,8 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel accessors words assocs sequences arrays namespaces fry locals definitions classes classes.algebra generic -stack-checker.state +stack-checker.dependencies stack-checker.backend compiler.tree compiler.tree.propagation.info @@ -28,9 +28,7 @@ M: method-body flushable? "method-generic" word-prop flushable? ; M: #call mark-live-values* dup flushable-call? [ drop ] [ look-at-inputs ] if ; -M: #alien-invoke mark-live-values* look-at-inputs ; - -M: #alien-indirect mark-live-values* look-at-inputs ; +M: #alien-node mark-live-values* look-at-inputs ; M: #return mark-live-values* look-at-inputs ; @@ -47,9 +45,7 @@ M: #call compute-live-values* nip look-at-inputs ; M: #shuffle compute-live-values* mapping>> at look-at-value ; -M: #alien-invoke compute-live-values* nip look-at-inputs ; - -M: #alien-indirect compute-live-values* nip look-at-inputs ; +M: #alien-node compute-live-values* nip look-at-inputs ; : filter-mapping ( assoc -- assoc' ) live-values get '[ drop _ key? ] assoc-filter ; @@ -71,7 +67,7 @@ M: #alien-indirect compute-live-values* nip look-at-inputs ; filter-corresponding zip #data-shuffle ; inline :: drop-dead-values ( outputs -- #shuffle ) - outputs make-values :> new-outputs + outputs length make-values :> new-outputs outputs filter-live :> live-outputs new-outputs live-outputs @@ -127,8 +123,5 @@ M: #terminate remove-dead-code* [ filter-live ] change-in-d [ filter-live ] change-in-r ; -M: #alien-invoke remove-dead-code* - maybe-drop-dead-outputs ; - -M: #alien-indirect remove-dead-code* +M: #alien-node remove-dead-code* maybe-drop-dead-outputs ; diff --git a/basis/compiler/tree/debugger/debugger.factor b/basis/compiler/tree/debugger/debugger.factor index 4bf4cf88f0..47ec13e809 100644 --- a/basis/compiler/tree/debugger/debugger.factor +++ b/basis/compiler/tree/debugger/debugger.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2006, 2009 Slava Pestov. +! Copyright (C) 2006, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel assocs match fry accessors namespaces make effects sequences sequences.private quotations generic macros arrays @@ -51,7 +51,6 @@ MATCH-VARS: ?a ?b ?c ; { { { ?b ?a } { ?a ?b } } [ swap ] } { { { ?b ?a ?c } { ?a ?b ?c } } [ swapd ] } { { { ?a ?b } { ?a ?a ?b } } [ dupd ] } - { { { ?a ?b } { ?b ?a ?b } } [ tuck ] } { { { ?a ?b ?c } { ?a ?b ?c ?a } } [ pick ] } { { { ?a ?b ?c } { ?c ?a ?b } } [ -rot ] } { { { ?a ?b ?c } { ?b ?c ?a } } [ rot ] } @@ -65,7 +64,7 @@ TUPLE: shuffle-node { effect effect } ; M: shuffle-node pprint* effect>> effect>string text ; : (shuffle-effect) ( in out #shuffle -- effect ) - mapping>> '[ _ at ] map ; + mapping>> '[ _ at ] map [ >array ] bi@ ; : shuffle-effect ( #shuffle -- effect ) [ in-d>> ] [ out-d>> ] [ ] tri (shuffle-effect) ; @@ -127,6 +126,8 @@ M: #alien-invoke node>quot params>> , \ #alien-invoke , ; M: #alien-indirect node>quot params>> , \ #alien-indirect , ; +M: #alien-assembly node>quot params>> , \ #alien-assembly , ; + M: #alien-callback node>quot params>> , \ #alien-callback , ; M: node node>quot drop ; diff --git a/basis/compiler/tree/escape-analysis/escape-analysis-tests.factor b/basis/compiler/tree/escape-analysis/escape-analysis-tests.factor index debb66b8d4..6c50347c3a 100644 --- a/basis/compiler/tree/escape-analysis/escape-analysis-tests.factor +++ b/basis/compiler/tree/escape-analysis/escape-analysis-tests.factor @@ -7,7 +7,7 @@ math.private kernel tools.test accessors slots.private quotations.private prettyprint classes.tuple.private classes classes.tuple namespaces compiler.tree.propagation.info stack-checker.errors -compiler.tree.checker +compiler.tree.checker compiler.tree.def-use compiler.tree.dead-code kernel.private vectors ; IN: compiler.tree.escape-analysis.tests @@ -37,6 +37,8 @@ M: node count-unboxed-allocations* drop ; cleanup escape-analysis dup check-nodes + compute-def-use + remove-dead-code 0 swap [ count-unboxed-allocations* ] each-node ; [ 0 ] [ [ [ + ] curry ] count-unboxed-allocations ] unit-test @@ -173,12 +175,6 @@ TUPLE: cons { car read-only } { cdr read-only } ; [ 10 [ drop ] each-integer ] count-unboxed-allocations ] unit-test -[ 2 ] [ - [ - 1 2 cons boa 10 [ 2drop 1 2 cons boa ] each-integer car>> - ] count-unboxed-allocations -] unit-test - [ 0 ] [ [ 1 2 cons boa 10 [ drop 2 cons boa ] each-integer car>> @@ -304,14 +300,6 @@ C: ro-box [ 0 ] [ [ 1 cons boa "x" get slot ] count-unboxed-allocations ] unit-test -: impeach-node ( quot: ( node -- ) -- ) - [ call ] keep impeach-node ; inline recursive - -: bleach-node ( quot: ( node -- ) -- ) - [ bleach-node ] curry [ ] compose impeach-node ; inline recursive - -[ 3 ] [ [ [ ] bleach-node ] count-unboxed-allocations ] unit-test - [ 0 ] [ [ dup -1 over >= [ 0 >= [ "A" throw ] unless ] [ drop ] if ] count-unboxed-allocations @@ -322,10 +310,6 @@ C: ro-box count-unboxed-allocations ] unit-test -[ 0 ] [ - [ { null } declare [ 1 ] [ 2 ] if ] count-unboxed-allocations -] unit-test - ! Doug found a regression TUPLE: empty-tuple ; diff --git a/basis/compiler/tree/escape-analysis/recursive/recursive-tests.factor b/basis/compiler/tree/escape-analysis/recursive/recursive-tests.factor index c26f3ddefc..bb32e6e23b 100644 --- a/basis/compiler/tree/escape-analysis/recursive/recursive-tests.factor +++ b/basis/compiler/tree/escape-analysis/recursive/recursive-tests.factor @@ -1,4 +1,4 @@ -USING: kernel tools.test namespaces sequences +USING: kernel tools.test namespaces sequences math compiler.tree.escape-analysis.recursive compiler.tree.escape-analysis.allocations ; IN: compiler.tree.escape-analysis.recursive.tests @@ -6,7 +6,7 @@ IN: compiler.tree.escape-analysis.recursive.tests H{ } clone allocations set escaping-values set -[ ] [ 8 [ introduce-value ] each ] unit-test +[ ] [ 8 [ introduce-value ] each-integer ] unit-test [ ] [ { 1 2 } 3 record-allocation ] unit-test diff --git a/basis/compiler/tree/escape-analysis/simple/simple.factor b/basis/compiler/tree/escape-analysis/simple/simple.factor index c053b15f29..50fa7ef0a8 100644 --- a/basis/compiler/tree/escape-analysis/simple/simple.factor +++ b/basis/compiler/tree/escape-analysis/simple/simple.factor @@ -86,12 +86,7 @@ M: #call escape-analysis* M: #return escape-analysis* in-d>> add-escaping-values ; -M: #alien-invoke escape-analysis* - [ in-d>> add-escaping-values ] - [ out-d>> unknown-allocations ] - bi ; - -M: #alien-indirect escape-analysis* +M: #alien-node escape-analysis* [ in-d>> add-escaping-values ] [ out-d>> unknown-allocations ] bi ; diff --git a/basis/compiler/tree/finalization/finalization.factor b/basis/compiler/tree/finalization/finalization.factor old mode 100755 new mode 100644 diff --git a/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor b/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor index 42e7f421bf..7366a83ee1 100644 --- a/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor +++ b/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor @@ -73,7 +73,7 @@ TUPLE: declared-fixnum { x fixnum } ; [ t ] [ [ - { fixnum } declare 0 swap + { fixnum } declare iota 0 swap [ drop 615949 * 797807 + 20 2^ rem dup 19 2^ - ] map @@ -94,7 +94,7 @@ TUPLE: declared-fixnum { x fixnum } ; [ t ] [ [ - { integer } declare [ 256 mod ] map + { integer } declare iota [ 256 mod ] map ] { mod fixnum-mod } inlined? ] unit-test diff --git a/basis/compiler/tree/normalization/normalization.factor b/basis/compiler/tree/normalization/normalization.factor index fcfa42c70b..7912fce1f6 100644 --- a/basis/compiler/tree/normalization/normalization.factor +++ b/basis/compiler/tree/normalization/normalization.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: fry namespaces sequences math math.order accessors kernel arrays combinators assocs @@ -75,10 +75,9 @@ M: #phi normalize* ] with-variable ; M: #recursive normalize* - dup label>> introductions>> - [ drop [ child>> first ] [ in-d>> ] bi >>in-d drop ] - [ make-values '[ _ (normalize) ] change-child ] - 2bi ; + [ [ child>> first ] [ in-d>> ] bi >>in-d drop ] + [ dup label>> introductions>> make-values '[ _ (normalize) ] change-child ] + bi ; M: #enter-recursive normalize* [ introduction-stack get prepend ] change-out-d diff --git a/basis/compiler/tree/propagation/branches/branches.factor b/basis/compiler/tree/propagation/branches/branches.factor old mode 100755 new mode 100644 index 0d837d82ae..28f34cb425 --- a/basis/compiler/tree/propagation/branches/branches.factor +++ b/basis/compiler/tree/propagation/branches/branches.factor @@ -97,7 +97,7 @@ M: #phi propagate-before ( #phi -- ) constraints get last update-constraints ; : branch-phi-constraints ( output values booleans -- ) - { + { { { { t } { f } } [ @@ -130,6 +130,22 @@ M: #phi propagate-before ( #phi -- ) swap t--> ] } + { + { { t f } { t } } + [ + first =f + condition-value get =t /\ + swap f--> + ] + } + { + { { t } { t f } } + [ + second =f + condition-value get =f /\ + swap f--> + ] + } { { { t f } { } } [ diff --git a/basis/compiler/tree/propagation/call-effect/call-effect-tests.factor b/basis/compiler/tree/propagation/call-effect/call-effect-tests.factor index 79a9f69de5..4a543fb87a 100644 --- a/basis/compiler/tree/propagation/call-effect/call-effect-tests.factor +++ b/basis/compiler/tree/propagation/call-effect/call-effect-tests.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2009 Slava Pestov, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. USING: compiler.tree.propagation.call-effect tools.test fry math effects kernel -compiler.tree.builder compiler.tree.optimizer compiler.tree.debugger sequences ; +compiler.tree.builder compiler.tree.optimizer compiler.tree.debugger sequences +eval combinators ; IN: compiler.tree.propagation.call-effect.tests [ t ] [ \ + (( a b -- c )) execute-effect-unsafe? ] unit-test @@ -58,4 +59,23 @@ IN: compiler.tree.propagation.call-effect.tests ! [ boa ] by itself doesn't infer TUPLE: a-tuple x ; -[ V{ a-tuple } ] [ [ a-tuple '[ _ boa ] call( x -- tuple ) ] final-classes ] unit-test \ No newline at end of file +[ V{ a-tuple } ] [ [ a-tuple '[ _ boa ] call( x -- tuple ) ] final-classes ] unit-test + +! See if redefinitions are handled correctly +: call(-redefine-test ( a -- b ) 1 + ; + +: test-quotatation ( -- quot ) [ call(-redefine-test ] ; + +[ t ] [ test-quotatation cached-effect (( a -- b )) effect<= ] unit-test + +[ ] [ "IN: compiler.tree.propagation.call-effect.tests USE: math : call(-redefine-test ( a b -- c ) + ;" eval( -- ) ] unit-test + +[ t ] [ test-quotatation cached-effect (( a b -- c )) effect<= ] unit-test + +: inline-cache-invalidation-test ( a b c -- c ) call( a b -- c ) ; + +[ 4 ] [ 1 3 test-quotatation inline-cache-invalidation-test ] unit-test + +[ ] [ "IN: compiler.tree.propagation.call-effect.tests USE: math : call(-redefine-test ( a -- c ) 1 + ;" eval( -- ) ] unit-test + +[ 1 3 test-quotatation inline-cache-invalidation-test ] [ T{ wrong-values f (( a b -- c )) } = ] must-fail-with diff --git a/basis/compiler/tree/propagation/call-effect/call-effect.factor b/basis/compiler/tree/propagation/call-effect/call-effect.factor index 614ceeb597..04320ee792 100644 --- a/basis/compiler/tree/propagation/call-effect/call-effect.factor +++ b/basis/compiler/tree/propagation/call-effect/call-effect.factor @@ -1,10 +1,10 @@ -! Copyright (C) 2009 Slava Pestov, Daniel Ehrenberg. +! Copyright (C) 2009, 2010 Slava Pestov, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors combinators combinators.private effects fry -kernel kernel.private make sequences continuations quotations -words math stack-checker stack-checker.transforms -compiler.tree.propagation.info -compiler.tree.propagation.inlining ; +USING: accessors arrays combinators combinators.private effects +fry kernel kernel.private make sequences continuations +quotations words math stack-checker combinators.short-circuit +stack-checker.transforms compiler.tree.propagation.info +compiler.tree.propagation.inlining compiler.units ; IN: compiler.tree.propagation.call-effect ! call( and execute( have complex expansions. @@ -15,13 +15,20 @@ IN: compiler.tree.propagation.call-effect ! and compare it with declaration. If matches, call it unsafely. ! - Fallback. If the above doesn't work, call it and compare the datastack before ! and after to make sure it didn't mess anything up. +! - Inline caches and cached effects are invalidated whenever a macro is redefined, or +! a word's effect changes, by comparing a global counter against the counter value +! last observed. The counter is incremented by compiler.units. ! execute( uses a similar strategy. -TUPLE: inline-cache value ; +TUPLE: inline-cache value counter ; -: cache-hit? ( word/quot ic -- ? ) - [ value>> eq? ] [ value>> ] bi and ; inline +: inline-cache-hit? ( word/quot ic -- ? ) + { [ value>> eq? ] [ nip counter>> effect-counter eq? ] } 2&& ; inline + +: update-inline-cache ( word/quot ic -- ) + [ effect-counter ] dip + [ (>>value) ] [ (>>counter) ] bi-curry bi* ; inline SINGLETON: +unknown+ @@ -36,7 +43,7 @@ M: +unknown+ curry-effect ; M: effect curry-effect [ in>> length ] [ out>> length ] [ terminated?>> ] tri pick 0 = [ [ 1 + ] dip ] [ [ 1 - ] 2dip ] if - effect boa ; + [ [ "x" ] bi@ ] dip effect boa ; M: curry cached-effect quot>> cached-effect curry-effect ; @@ -53,14 +60,21 @@ M: compose cached-effect : safe-infer ( quot -- effect ) [ infer ] [ 2drop +unknown+ ] recover ; +: cached-effect-valid? ( quot -- ? ) + cache-counter>> effect-counter eq? ; inline + +: save-effect ( effect quot -- ) + [ effect-counter ] dip + [ (>>cached-effect) ] [ (>>cache-counter) ] bi-curry bi* ; + M: quotation cached-effect - dup cached-effect>> - [ ] [ [ safe-infer dup ] keep (>>cached-effect) ] ?if ; + dup cached-effect-valid? + [ cached-effect>> ] [ [ safe-infer dup ] keep save-effect ] if ; : call-effect-unsafe? ( quot effect -- ? ) [ cached-effect ] dip over +unknown+ eq? - [ 2drop f ] [ effect<= ] if ; inline + [ 2drop f ] [ [ { effect } declare ] dip effect<= ] if ; inline : (call-effect-slow>quot) ( in out effect -- quot ) [ @@ -82,12 +96,12 @@ M: quotation cached-effect : call-effect-fast ( quot effect inline-cache -- ) 2over call-effect-unsafe? - [ [ nip (>>value) ] [ drop call-effect-unsafe ] 3bi ] + [ [ nip update-inline-cache ] [ drop call-effect-unsafe ] 3bi ] [ drop call-effect-slow ] if ; inline : call-effect-ic ( quot effect inline-cache -- ) - 3dup nip cache-hit? + 3dup nip inline-cache-hit? [ drop call-effect-unsafe ] [ call-effect-fast ] if ; inline @@ -103,12 +117,12 @@ M: quotation cached-effect : execute-effect-fast ( word effect inline-cache -- ) 2over execute-effect-unsafe? - [ [ nip (>>value) ] [ drop execute-effect-unsafe ] 3bi ] + [ [ nip update-inline-cache ] [ drop execute-effect-unsafe ] 3bi ] [ drop execute-effect-slow ] if ; inline : execute-effect-ic ( word effect inline-cache -- ) - 3dup nip cache-hit? + 3dup nip inline-cache-hit? [ drop execute-effect-unsafe ] [ execute-effect-fast ] if ; inline diff --git a/basis/compiler/tree/propagation/constraints/constraints.factor b/basis/compiler/tree/propagation/constraints/constraints.factor index 59c9912e47..617352d699 100644 --- a/basis/compiler/tree/propagation/constraints/constraints.factor +++ b/basis/compiler/tree/propagation/constraints/constraints.factor @@ -39,8 +39,8 @@ M: true-constraint assume* bi ; M: true-constraint satisfied? - value>> value-info class>> - { [ true-class? ] [ null-class? not ] } 1&& ; + value>> value-info* + [ class>> true-class? ] [ drop f ] if ; TUPLE: false-constraint value ; @@ -52,8 +52,8 @@ M: false-constraint assume* bi ; M: false-constraint satisfied? - value>> value-info class>> - { [ false-class? ] [ null-class? not ] } 1&& ; + value>> value-info* + [ class>> false-class? ] [ drop f ] if ; ! Class constraints TUPLE: class-constraint value class ; diff --git a/basis/compiler/tree/propagation/info/info-tests.factor b/basis/compiler/tree/propagation/info/info-tests.factor index 826131ab61..446aad89e5 100644 --- a/basis/compiler/tree/propagation/info/info-tests.factor +++ b/basis/compiler/tree/propagation/info/info-tests.factor @@ -4,13 +4,6 @@ IN: compiler.tree.propagation.info.tests [ f ] [ 0.0 -0.0 eql? ] unit-test -[ t ] [ - number - sequence - value-info-intersect - class>> integer class= -] unit-test - [ t t ] [ 0 10 [a,b] 5 20 [a,b] diff --git a/basis/compiler/tree/propagation/info/info.factor b/basis/compiler/tree/propagation/info/info.factor index 9030914e34..28ffb96f8f 100644 --- a/basis/compiler/tree/propagation/info/info.factor +++ b/basis/compiler/tree/propagation/info/info.factor @@ -294,8 +294,11 @@ DEFER: (value-info-union) ! Assoc stack of current value --> info mapping SYMBOL: value-infos +: value-info* ( value -- info ? ) + resolve-copy value-infos get assoc-stack [ null-info or ] [ >boolean ] bi ; inline + : value-info ( value -- info ) - resolve-copy value-infos get assoc-stack null-info or ; + value-info* drop ; : set-value-info ( info value -- ) resolve-copy value-infos get last set-at ; @@ -309,16 +312,12 @@ SYMBOL: value-infos value-info >literal< ; : possible-boolean-values ( info -- values ) - dup literal?>> [ - literal>> 1array - ] [ - class>> { - { [ dup null-class? ] [ { } ] } - { [ dup true-class? ] [ { t } ] } - { [ dup false-class? ] [ { f } ] } - [ { t f } ] - } cond nip - ] if ; + class>> { + { [ dup null-class? ] [ { } ] } + { [ dup true-class? ] [ { t } ] } + { [ dup false-class? ] [ { f } ] } + [ { t f } ] + } cond nip ; : node-value-info ( node value -- info ) swap info>> at* [ drop null-info ] unless ; diff --git a/basis/compiler/tree/propagation/inlining/inlining.factor b/basis/compiler/tree/propagation/inlining/inlining.factor old mode 100755 new mode 100644 diff --git a/basis/compiler/tree/propagation/known-words/known-words.factor b/basis/compiler/tree/propagation/known-words/known-words.factor index 8afbaf0099..6aacbc57da 100644 --- a/basis/compiler/tree/propagation/known-words/known-words.factor +++ b/basis/compiler/tree/propagation/known-words/known-words.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel effects accessors math math.private math.integers.private math.floats.private math.partial-dispatch @@ -8,7 +8,7 @@ classes.algebra combinators generic.math splitting fry locals classes.tuple alien.accessors classes.tuple.private slots.private definitions strings.private vectors hashtables generic quotations alien -stack-checker.state +stack-checker.dependencies compiler.tree.comparisons compiler.tree.propagation.info compiler.tree.propagation.nodes @@ -16,19 +16,17 @@ compiler.tree.propagation.slots compiler.tree.propagation.simple compiler.tree.propagation.constraints compiler.tree.propagation.call-effect -compiler.tree.propagation.transforms -compiler.tree.propagation.simd ; +compiler.tree.propagation.transforms ; FROM: alien.c-types => (signed-interval) (unsigned-interval) ; IN: compiler.tree.propagation.known-words { + - * / } [ { number number } "input-classes" set-word-prop ] each -{ /f < > <= >= u< u> u<= u>= } +{ /f /i mod < > <= >= u< u> u<= u>= } [ { real real } "input-classes" set-word-prop ] each -{ /i mod /mod } -[ { rational rational } "input-classes" set-word-prop ] each +\ /mod { rational rational } "input-classes" set-word-prop { bitand bitor bitxor bitnot shift } [ { integer integer } "input-classes" set-word-prop ] each diff --git a/basis/compiler/tree/propagation/propagation-tests.factor b/basis/compiler/tree/propagation/propagation-tests.factor index 3627757acd..ad17ccc1c9 100644 --- a/basis/compiler/tree/propagation/propagation-tests.factor +++ b/basis/compiler/tree/propagation/propagation-tests.factor @@ -1,14 +1,13 @@ USING: kernel compiler.tree.builder compiler.tree compiler.tree.propagation compiler.tree.recursive -compiler.tree.normalization tools.test math math.order -accessors sequences arrays kernel.private vectors -alien.accessors alien.c-types sequences.private -byte-arrays classes.algebra classes.tuple.private -math.functions math.private strings layouts -compiler.tree.propagation.info compiler.tree.def-use -compiler.tree.debugger compiler.tree.checker -slots.private words hashtables classes assocs locals -specialized-arrays system sorting math.libm +compiler.tree.normalization tools.test math math.order accessors +sequences arrays kernel.private vectors alien.accessors +alien.c-types sequences.private byte-arrays classes.algebra +classes.tuple.private math.functions math.private strings +layouts compiler.tree.propagation.info compiler.tree.def-use +compiler.tree.debugger compiler.tree.checker slots.private words +hashtables classes assocs locals specialized-arrays system +sorting math.libm math.floats.private math.integers.private math.intervals quotations effects alien alien.data ; FROM: math => float ; SPECIALIZED-ARRAY: double @@ -91,6 +90,8 @@ IN: compiler.tree.propagation.tests [ float ] [ [ { float float } declare mod ] final-math-class ] unit-test +[ V{ integer float } ] [ [ { float float } declare [ /i ] keep ] final-classes ] unit-test + [ V{ fixnum } ] [ [ 255 bitand ] final-classes ] unit-test [ V{ fixnum } ] [ @@ -224,6 +225,14 @@ IN: compiler.tree.propagation.tests [ t ] [ [ over [ drop f ] when [ "A" throw ] unless ] final-classes first false-class? ] unit-test +[ V{ fixnum } ] [ + [ + [ { fixnum } declare ] [ drop f ] if + dup [ dup 13 eq? [ t ] [ f ] if ] [ t ] if + [ "Oops" throw ] when + ] final-classes +] unit-test + [ V{ fixnum } ] [ [ >fixnum @@ -231,6 +240,14 @@ IN: compiler.tree.propagation.tests ] final-classes ] unit-test +[ ] [ + [ + dup dup dup [ 100 < ] [ drop f ] if dup + [ 2drop f ] [ 2drop f ] if + [ ] [ dup [ ] [ ] if ] if + ] final-info drop +] unit-test + [ V{ fixnum } ] [ [ { fixnum } declare (clone) ] final-classes ] unit-test @@ -389,14 +406,6 @@ IN: compiler.tree.propagation.tests ] final-literals ] unit-test -[ V{ 27 } ] [ - [ - dup number? over sequence? and [ - dup 10 < over 8 <= not and [ 3 * ] [ "A" throw ] if - ] [ "B" throw ] if - ] final-literals -] unit-test - [ V{ string string } ] [ [ 2dup [ dup string? [ "Oops" throw ] unless ] bi@ 2drop @@ -664,7 +673,7 @@ M: array iterate first t ; inline ] unit-test [ V{ fixnum } ] [ - [ { fixnum fixnum } declare [ nth-unsafe ] curry call ] final-classes + [ { fixnum fixnum } declare iota [ nth-unsafe ] curry call ] final-classes ] unit-test [ V{ f } ] [ @@ -925,3 +934,21 @@ M: tuple-with-read-only-slot clone ! Could be bignum not integer but who cares [ V{ integer } ] [ [ 10 >bignum bitand ] final-classes ] unit-test + +[ t ] [ [ { fixnum fixnum } declare min ] { min } inlined? ] unit-test +[ f ] [ [ { fixnum fixnum } declare min ] { fixnum-min } inlined? ] unit-test + +[ t ] [ [ { float float } declare min ] { min } inlined? ] unit-test +[ f ] [ [ { float float } declare min ] { float-min } inlined? ] unit-test + +[ t ] [ [ { fixnum fixnum } declare max ] { max } inlined? ] unit-test +[ f ] [ [ { fixnum fixnum } declare max ] { fixnum-max } inlined? ] unit-test + +[ t ] [ [ { float float } declare max ] { max } inlined? ] unit-test +[ f ] [ [ { float float } declare max ] { float-max } inlined? ] unit-test + +! Propagation should not call equal?, hashcode, etc on literals in user code +[ V{ } ] [ [ 4 [ 2drop ] with each ] final-info ] unit-test + +! Reduction +[ 1 ] [ [ 4 [ nth-unsafe ] [ ] unless ] final-info length ] unit-test diff --git a/basis/compiler/tree/propagation/recursive/recursive-tests.factor b/basis/compiler/tree/propagation/recursive/recursive-tests.factor index 974bb584eb..42325d97ca 100644 --- a/basis/compiler/tree/propagation/recursive/recursive-tests.factor +++ b/basis/compiler/tree/propagation/recursive/recursive-tests.factor @@ -27,14 +27,16 @@ IN: compiler.tree.propagation.recursive.tests ] unit-test [ t ] [ + T{ interval f { -268435456 t } { 268435455 t } } T{ interval f { 1 t } { 268435455 t } } - T{ interval f { -268435456 t } { 268435455 t } } tuck + over integer generalize-counter-interval = ] unit-test [ t ] [ + T{ interval f { -268435456 t } { 268435455 t } } T{ interval f { 1 t } { 268435455 t } } - T{ interval f { -268435456 t } { 268435455 t } } tuck + over fixnum generalize-counter-interval = ] unit-test diff --git a/basis/compiler/tree/propagation/simd/simd.factor b/basis/compiler/tree/propagation/simd/simd.factor index 1637148b88..250a9379e8 100644 --- a/basis/compiler/tree/propagation/simd/simd.factor +++ b/basis/compiler/tree/propagation/simd/simd.factor @@ -1,57 +1,81 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors byte-arrays combinators fry sequences -compiler.tree.propagation.info cpu.architecture kernel words math -math.intervals math.vectors.simd.intrinsics ; +USING: accessors assocs byte-arrays combinators compiler.cfg.builder +continuations fry sequences compiler.tree.propagation.info +cpu.architecture kernel words make math math.intervals +math.vectors.simd.intrinsics namespaces ; IN: compiler.tree.propagation.simd -{ - (simd-v+) - (simd-v-) - (simd-vneg) - (simd-vabs) - (simd-v+-) - (simd-v*) - (simd-v/) - (simd-vmin) - (simd-vmax) - (simd-sum) - (simd-vsqrt) - (simd-vbitand) - (simd-vbitandn) - (simd-vbitor) - (simd-vbitxor) - (simd-vbitnot) - (simd-vand) - (simd-vandn) - (simd-vor) - (simd-vxor) - (simd-vnot) - (simd-vlshift) - (simd-vrshift) - (simd-hlshift) - (simd-hrshift) - (simd-vshuffle-bytes) - (simd-vshuffle-elements) - (simd-(vmerge-head)) - (simd-(vmerge-tail)) - (simd-(v>float)) - (simd-(v>integer)) - (simd-(vpack-signed)) - (simd-(vpack-unsigned)) - (simd-(vunpack-head)) - (simd-(vunpack-tail)) - (simd-v<=) - (simd-v<) - (simd-v=) - (simd-v>) - (simd-v>=) - (simd-vunordered?) - (simd-with) - (simd-gather-2) - (simd-gather-4) - alien-vector -} [ { byte-array } "default-output-classes" set-word-prop ] each +CONSTANT: vector>vector-intrinsics + { + (simd-v+) + (simd-v-) + (simd-vneg) + (simd-v+-) + (simd-vs+) + (simd-vs-) + (simd-vs*) + (simd-v*) + (simd-v*high) + (simd-v*hs+) + (simd-v/) + (simd-vmin) + (simd-vmax) + (simd-vavg) + (simd-vsqrt) + (simd-vabs) + (simd-vbitand) + (simd-vbitandn) + (simd-vbitor) + (simd-vbitxor) + (simd-vbitnot) + (simd-vand) + (simd-vandn) + (simd-vor) + (simd-vxor) + (simd-vnot) + (simd-vlshift) + (simd-vrshift) + (simd-hlshift) + (simd-hrshift) + (simd-vshuffle-elements) + (simd-vshuffle-bytes) + (simd-vmerge-head) + (simd-vmerge-tail) + (simd-v<=) + (simd-v<) + (simd-v=) + (simd-v>) + (simd-v>=) + (simd-vunordered?) + (simd-v>float) + (simd-v>integer) + (simd-vpack-signed) + (simd-vpack-unsigned) + (simd-vunpack-head) + (simd-vunpack-tail) + (simd-with) + (simd-gather-2) + (simd-gather-4) + alien-vector + } + +CONSTANT: vector-other-intrinsics + { + (simd-v.) + (simd-vsad) + (simd-sum) + (simd-vany?) + (simd-vall?) + (simd-vnone?) + (simd-select) + set-alien-vector + } + +: vector-intrinsics ( -- x ) + vector>vector-intrinsics vector-other-intrinsics append ; + +vector>vector-intrinsics [ { byte-array } "default-output-classes" set-word-prop ] each : scalar-output-class ( rep -- class ) dup literal?>> [ @@ -79,12 +103,24 @@ IN: compiler.tree.propagation.simd real [0,inf] value-info-intersect ] "outputs" set-word-prop -! If SIMD is not available, inline alien-vector and set-alien-vector -! to get a speedup +: clone-with-value-infos ( node -- node' ) + clone dup in-d>> [ dup value-info ] H{ } map>assoc >>info ; + +: try-intrinsic ( node intrinsic-quot -- ? ) + '[ + _ clone-with-value-infos + _ with-dummy-cfg-builder + t + ] [ drop f ] recover ; + : inline-unless-intrinsic ( word -- ) - dup '[ drop _ dup "intrinsic" word-prop [ drop f ] [ def>> ] if ] + dup '[ + _ swap over "intrinsic" word-prop + "always-inline-simd-intrinsics" get not swap and + ! word node intrinsic + [ try-intrinsic [ drop f ] [ def>> ] if ] + [ drop def>> ] if* + ] "custom-inlining" set-word-prop ; -\ alien-vector inline-unless-intrinsic - -\ set-alien-vector inline-unless-intrinsic +vector-intrinsics [ inline-unless-intrinsic ] each diff --git a/basis/compiler/tree/propagation/simple/simple.factor b/basis/compiler/tree/propagation/simple/simple.factor index 5de5e26a30..225f10d342 100644 --- a/basis/compiler/tree/propagation/simple/simple.factor +++ b/basis/compiler/tree/propagation/simple/simple.factor @@ -4,7 +4,7 @@ USING: fry accessors kernel sequences sequences.private assocs words namespaces classes.algebra combinators combinators.short-circuit classes classes.tuple classes.tuple.private continuations arrays alien.c-types math -math.private slots generic definitions stack-checker.state +math.private slots generic definitions stack-checker.dependencies compiler.tree compiler.tree.propagation.info compiler.tree.propagation.nodes @@ -80,7 +80,7 @@ M: #declare propagate-before : (fold-call) ( #call word -- info ) [ [ out-d>> ] [ in-d>> [ value-info literal>> ] map ] bi ] [ '[ _ execute ] ] bi* '[ _ _ with-datastack [ ] map nip ] - [ drop [ object-info ] replicate ] + [ drop length [ object-info ] replicate ] recover ; : fold-call ( #call word -- ) @@ -153,8 +153,6 @@ M: #call propagate-after [ out-d>> ] [ params>> return>> ] bi [ drop ] [ c-type-class swap first set-value-info ] if-void ; -M: #alien-invoke propagate-before propagate-alien-invoke ; - -M: #alien-indirect propagate-before propagate-alien-invoke ; +M: #alien-node propagate-before propagate-alien-invoke ; M: #return annotate-node dup in-d>> (annotate-node) ; diff --git a/basis/compiler/tree/propagation/transforms/transforms.factor b/basis/compiler/tree/propagation/transforms/transforms.factor index b0605bfb35..2d145ef74f 100644 --- a/basis/compiler/tree/propagation/transforms/transforms.factor +++ b/basis/compiler/tree/propagation/transforms/transforms.factor @@ -1,13 +1,14 @@ -! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg. +! Copyright (C) 2008, 2010 Slava Pestov, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel sequences words fry generic accessors +USING: alien.c-types kernel sequences words fry generic accessors classes.tuple classes classes.algebra definitions -stack-checker.state quotations classes.tuple.private math +stack-checker.dependencies quotations classes.tuple.private math math.partial-dispatch math.private math.intervals sets.private math.floats.private math.integers.private layouts math.order vectors hashtables combinators effects generalizations assocs -sets combinators.short-circuit sequences.private locals +sets combinators.short-circuit sequences.private locals growable stack-checker namespaces compiler.tree.propagation.info ; +FROM: math => float ; IN: compiler.tree.propagation.transforms \ equal? [ @@ -131,26 +132,6 @@ IN: compiler.tree.propagation.transforms ] "custom-inlining" set-word-prop ] each -! Integrate this with generic arithmetic optimization instead? -: both-inputs? ( #call class -- ? ) - [ in-d>> first2 ] dip '[ value-info class>> _ class<= ] both? ; - -\ min [ - { - { [ dup fixnum both-inputs? ] [ [ fixnum-min ] ] } - { [ dup float both-inputs? ] [ [ float-min ] ] } - [ f ] - } cond nip -] "custom-inlining" set-word-prop - -\ max [ - { - { [ dup fixnum both-inputs? ] [ [ fixnum-max ] ] } - { [ dup float both-inputs? ] [ [ float-max ] ] } - [ f ] - } cond nip -] "custom-inlining" set-word-prop - ! Generate more efficient code for common idiom \ clone [ in-d>> first value-info literal>> { @@ -208,7 +189,7 @@ ERROR: bad-partial-eval quot word ; \ index [ dup sequence? [ dup length 4 >= [ - dup length zip >hashtable '[ _ at ] + dup length iota zip >hashtable '[ _ at ] ] [ drop f ] if ] [ drop f ] if ] 1 define-partial-eval @@ -247,7 +228,7 @@ CONSTANT: lookup-table-at-max 256 } 1&& ; : lookup-table-seq ( assoc -- table ) - [ keys supremum 1 + ] keep '[ _ at ] { } map-as ; + [ keys supremum 1 + iota ] keep '[ _ at ] { } map-as ; : lookup-table-quot ( seq -- newquot ) lookup-table-seq @@ -309,3 +290,18 @@ CONSTANT: lookup-table-at-max 256 [ [ >fixnum ] dip fixnum-bit? ] f ? ; \ bit? [ bit-quot ] "custom-inlining" set-word-prop + +! Speeds up sum-file, sort and reverse-complement benchmarks by +! compiling decoder-readln better +\ push [ + in-d>> second value-info class>> growable class<= + [ \ push def>> ] [ f ] if +] "custom-inlining" set-word-prop + +! We want to constant-fold calls to heap-size, and recompile those +! calls when a C type is redefined +\ heap-size [ + dup word? [ + [ inlined-dependency depends-on ] [ heap-size '[ _ ] ] bi + ] [ drop f ] if +] 1 define-partial-eval diff --git a/basis/compiler/tree/tree.factor b/basis/compiler/tree/tree.factor index 7fa096b623..a1d1b4db61 100644 --- a/basis/compiler/tree/tree.factor +++ b/basis/compiler/tree/tree.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2004, 2008 Slava Pestov. +! Copyright (C) 2004, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: fry arrays generic assocs kernel math namespaces parser sequences words vectors math.intervals classes @@ -10,8 +10,6 @@ IN: compiler.tree TUPLE: node < identity-tuple ; -M: node hashcode* drop node hashcode* ; - TUPLE: #introduce < node out-d ; : #introduce ( out-d -- node ) @@ -151,7 +149,12 @@ TUPLE: #alien-indirect < #alien-node in-d out-d ; : #alien-indirect ( params -- node ) \ #alien-indirect new-alien-node ; -TUPLE: #alien-callback < #alien-node ; +TUPLE: #alien-assembly < #alien-node in-d out-d ; + +: #alien-assembly ( params -- node ) + \ #alien-assembly new-alien-node ; + +TUPLE: #alien-callback < node params ; : #alien-callback ( params -- node ) \ #alien-callback new @@ -189,4 +192,5 @@ M: vector #recursive, #recursive node, ; M: vector #copy, #copy node, ; M: vector #alien-invoke, #alien-invoke node, ; M: vector #alien-indirect, #alien-indirect node, ; +M: vector #alien-assembly, #alien-assembly node, ; M: vector #alien-callback, #alien-callback node, ; diff --git a/basis/compiler/tree/tuple-unboxing/tuple-unboxing.factor b/basis/compiler/tree/tuple-unboxing/tuple-unboxing.factor old mode 100755 new mode 100644 index de2848ea78..d4ca3010ce --- a/basis/compiler/tree/tuple-unboxing/tuple-unboxing.factor +++ b/basis/compiler/tree/tuple-unboxing/tuple-unboxing.factor @@ -164,9 +164,7 @@ M: #branch unbox-tuples* dup in-d>> assert-not-unboxed ; M: #return unbox-tuples* dup in-d>> assert-not-unboxed ; -M: #alien-invoke unbox-tuples* dup in-d>> assert-not-unboxed ; - -M: #alien-indirect unbox-tuples* dup in-d>> assert-not-unboxed ; +M: #alien-node unbox-tuples* dup in-d>> assert-not-unboxed ; M: #alien-callback unbox-tuples* ; diff --git a/basis/compression/huffman/huffman.factor b/basis/compression/huffman/huffman.factor old mode 100755 new mode 100644 diff --git a/basis/compression/inflate/inflate.factor b/basis/compression/inflate/inflate.factor index 567c435c2e..d96946d53d 100644 --- a/basis/compression/inflate/inflate.factor +++ b/basis/compression/inflate/inflate.factor @@ -36,7 +36,7 @@ CONSTANT: clen-shuffle { 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15 } 5 bitstream bs:read 1 + 4 bitstream bs:read 4 + clen-shuffle swap head - dup length iota [ 3 bitstream bs:read ] replicate + dup length [ 3 bitstream bs:read ] replicate get-table bitstream swap [ 2dup + ] dip swap :> k! @@ -64,13 +64,13 @@ CONSTANT: clen-shuffle { 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15 } MEMO: static-huffman-tables ( -- obj ) [ - 0 143 [a,b] [ 8 ] replicate - 144 255 [a,b] [ 9 ] replicate append - 256 279 [a,b] [ 7 ] replicate append - 280 287 [a,b] [ 8 ] replicate append + 0 143 [a,b] length [ 8 ] replicate + 144 255 [a,b] length [ 9 ] replicate append + 256 279 [a,b] length [ 7 ] replicate append + 280 287 [a,b] length [ 8 ] replicate append ] append-outputs - 0 31 [a,b] [ 5 ] replicate 2array - [ [ length>> [0,b) ] [ ] bi get-table ] map ; + 0 31 [a,b] length [ 5 ] replicate 2array + [ [ length>> iota ] [ ] bi get-table ] map ; CONSTANT: length-table { diff --git a/basis/compression/run-length/run-length.factor b/basis/compression/run-length/run-length.factor index cde2a7e113..ce25cd6a63 100644 --- a/basis/compression/run-length/run-length.factor +++ b/basis/compression/run-length/run-length.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2009 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays combinators grouping kernel locals math -math.matrices math.order multiline sequence-parser sequences +math.matrices math.order multiline sequences.parser sequences tools.continuations ; IN: compression.run-length diff --git a/basis/compression/zlib/ffi/ffi.factor b/basis/compression/zlib/ffi/ffi.factor old mode 100755 new mode 100644 diff --git a/basis/compression/zlib/zlib-tests.factor b/basis/compression/zlib/zlib-tests.factor old mode 100755 new mode 100644 index 1baeba73d9..b9bc502d46 --- a/basis/compression/zlib/zlib-tests.factor +++ b/basis/compression/zlib/zlib-tests.factor @@ -1,9 +1,12 @@ ! Copyright (C) 2009 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel tools.test compression.zlib classes ; +USING: accessors kernel tools.test compression.zlib classes ; +QUALIFIED-WITH: compression.zlib.ffi ffi IN: compression.zlib.tests : compress-me ( -- byte-array ) B{ 1 2 3 4 5 } ; [ t ] [ compress-me [ compress uncompress ] keep = ] unit-test [ t ] [ compress-me compress compressed instance? ] unit-test + +[ ffi:Z_DATA_ERROR zlib-error-message ] [ string>> "data error" = ] must-fail-with diff --git a/basis/compression/zlib/zlib.factor b/basis/compression/zlib/zlib.factor old mode 100755 new mode 100644 index 7818173498..c662eec049 --- a/basis/compression/zlib/zlib.factor +++ b/basis/compression/zlib/zlib.factor @@ -19,7 +19,9 @@ ERROR: zlib-failed n string ; dup compression.zlib.ffi:Z_ERRNO = [ drop errno "native libc error" ] [ - dup { + dup + neg ! zlib error codes are negative + { "no error" "libc_error" "stream error" "data error" "memory error" "buffer error" "zlib version error" diff --git a/basis/concurrency/combinators/combinators-tests.factor b/basis/concurrency/combinators/combinators-tests.factor index d3f3229171..f33f6513a9 100644 --- a/basis/concurrency/combinators/combinators-tests.factor +++ b/basis/concurrency/combinators/combinators-tests.factor @@ -17,12 +17,12 @@ IN: concurrency.combinators.tests [ error>> "Even" = ] must-fail-with [ V{ 0 3 6 9 } ] -[ 10 [ 3 mod zero? ] parallel-filter ] unit-test +[ 10 iota [ 3 mod zero? ] parallel-filter ] unit-test [ 10 ] [ V{ } clone - 10 over [ push ] curry parallel-each + 10 iota over [ push ] curry parallel-each length ] unit-test @@ -41,7 +41,7 @@ IN: concurrency.combinators.tests [ 20 ] [ V{ } clone - 10 10 pick [ [ push ] [ push ] bi ] curry 2parallel-each + 10 iota 10 iota pick [ [ push ] [ push ] bi ] curry 2parallel-each length ] unit-test diff --git a/basis/concurrency/combinators/combinators.factor b/basis/concurrency/combinators/combinators.factor old mode 100755 new mode 100644 diff --git a/basis/concurrency/distributed/distributed.factor b/basis/concurrency/distributed/distributed.factor index 244f1d95a3..0015b10cef 100644 --- a/basis/concurrency/distributed/distributed.factor +++ b/basis/concurrency/distributed/distributed.factor @@ -60,6 +60,4 @@ M: thread (serialize) ( obj -- ) [ H{ } clone \ registered-remote-threads set-global -] "remote-thread-registry" add-init-hook - - +] "remote-thread-registry" add-startup-hook diff --git a/basis/concurrency/mailboxes/mailboxes.factor b/basis/concurrency/mailboxes/mailboxes.factor old mode 100755 new mode 100644 diff --git a/basis/cords/cords-tests.factor b/basis/cords/cords-tests.factor deleted file mode 100644 index 898e4e51c8..0000000000 --- a/basis/cords/cords-tests.factor +++ /dev/null @@ -1,5 +0,0 @@ -USING: cords strings tools.test kernel sequences ; -IN: cords.tests - -[ "hello world" ] [ "hello" " world" cord-append dup like ] unit-test -[ "hello world" ] [ { "he" "llo" " world" } cord-concat dup like ] unit-test diff --git a/basis/cords/cords.factor b/basis/cords/cords.factor deleted file mode 100644 index a50de60c45..0000000000 --- a/basis/cords/cords.factor +++ /dev/null @@ -1,72 +0,0 @@ -! Copyright (C) 2008 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs sequences sorting binary-search math -math.order arrays combinators kernel ; -IN: cords - -> length ] [ second>> length ] bi + ; inline - -M: simple-cord virtual-seq first>> ; inline - -M: simple-cord virtual@ - 2dup first>> length < - [ first>> ] [ [ first>> length - ] [ second>> ] bi ] if ; inline - -TUPLE: multi-cord - { count read-only } { seqs read-only } ; - -M: multi-cord length count>> ; inline - -M: multi-cord virtual@ - dupd - seqs>> [ first <=> ] with search nip - [ first - ] [ second ] bi ; inline - -M: multi-cord virtual-seq - seqs>> [ f ] [ first second ] if-empty ; inline - -: ( seqs -- cord ) - dup length 2 = [ - first2 simple-cord boa - ] [ - [ 0 [ length + ] accumulate ] keep zip multi-cord boa - ] if ; inline - -PRIVATE> - -UNION: cord simple-cord multi-cord ; - -INSTANCE: cord virtual-sequence - -INSTANCE: multi-cord virtual-sequence - -: cord-append ( seq1 seq2 -- cord ) - { - { [ over empty? ] [ nip ] } - { [ dup empty? ] [ drop ] } - { [ 2dup [ cord? ] both? ] [ [ seqs>> values ] bi@ append ] } - { [ over cord? ] [ [ seqs>> values ] dip suffix ] } - { [ dup cord? ] [ seqs>> values swap prefix ] } - [ 2array ] - } cond ; inline - -: cord-concat ( seqs -- cord ) - { - { [ dup empty? ] [ drop f ] } - { [ dup length 1 = ] [ first ] } - [ - [ - { - { [ dup cord? ] [ seqs>> values ] } - { [ dup empty? ] [ drop { } ] } - [ 1array ] - } cond - ] map concat - ] - } cond ; inline diff --git a/basis/core-foundation/fsevents/fsevents.factor b/basis/core-foundation/fsevents/fsevents.factor old mode 100755 new mode 100644 index 24ac24bb6a..37dbcd1e4f --- a/basis/core-foundation/fsevents/fsevents.factor +++ b/basis/core-foundation/fsevents/fsevents.factor @@ -156,7 +156,7 @@ SYMBOL: event-stream-callbacks [ event-stream-callbacks [ [ drop expired? not ] assoc-filter H{ } assoc-like ] change-global -] "core-foundation" add-init-hook +] "core-foundation" add-startup-hook : add-event-source-callback ( quot -- id ) event-stream-counter diff --git a/basis/core-foundation/run-loop/run-loop.factor b/basis/core-foundation/run-loop/run-loop.factor index 0b61274b22..2370dd4562 100644 --- a/basis/core-foundation/run-loop/run-loop.factor +++ b/basis/core-foundation/run-loop/run-loop.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors alien alien.c-types alien.syntax kernel math namespaces sequences destructors combinators threads heaps -deques calendar core-foundation core-foundation.strings +deques calendar system core-foundation core-foundation.strings core-foundation.file-descriptors core-foundation.timers core-foundation.time ; IN: core-foundation.run-loop @@ -96,12 +96,15 @@ TUPLE: run-loop fds sources timers ; : ((reset-timer)) ( timer counter timestamp -- ) nip >CFAbsoluteTime CFRunLoopTimerSetNextFireDate ; +: nano-count>timestamp ( x -- timestamp ) + nano-count - nanoseconds now time+ ; + : (reset-timer) ( timer counter -- ) yield { { [ dup 0 = ] [ now ((reset-timer)) ] } { [ run-queue deque-empty? not ] [ 1 - (reset-timer) ] } { [ sleep-queue heap-empty? ] [ 5 minutes hence ((reset-timer)) ] } - [ sleep-queue heap-peek nip micros>timestamp ((reset-timer)) ] + [ sleep-queue heap-peek nip nano-count>timestamp ((reset-timer)) ] } cond ; : reset-timer ( timer -- ) @@ -121,8 +124,8 @@ PRIVATE> : init-thread-timer ( -- ) timer-callback add-timer-to-run-loop ; -: run-one-iteration ( us -- handled? ) +: run-one-iteration ( nanos -- handled? ) reset-run-loop CFRunLoopDefaultMode - swap [ microseconds ] [ 5 minutes ] if* >CFTimeInterval + swap [ nanoseconds ] [ 5 minutes ] if* >CFTimeInterval t CFRunLoopRunInMode kCFRunLoopRunHandledSource = ; diff --git a/basis/core-text/core-text-tests.factor b/basis/core-text/core-text-tests.factor index a5cf69fdee..b6b54df7c3 100644 --- a/basis/core-text/core-text-tests.factor +++ b/basis/core-text/core-text-tests.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: tools.test core-text core-text.fonts core-foundation core-foundation.dictionaries destructors arrays kernel generalizations -math accessors core-foundation.utilities combinators hashtables colors +locals math accessors core-foundation.utilities combinators hashtables colors colors.constants ; IN: core-text.tests @@ -18,10 +18,11 @@ IN: core-text.tests ] with-destructors ] unit-test -: test-typographic-bounds ( string font -- ? ) +:: test-typographic-bounds ( string font -- ? ) [ - test-font &CFRelease tuck COLOR: white &CFRelease - compute-line-metrics { + font test-font &CFRelease :> ctfont + string ctfont COLOR: white &CFRelease :> ctline + ctfont ctline compute-line-metrics { [ width>> float? ] [ ascent>> float? ] [ descent>> float? ] @@ -33,4 +34,4 @@ IN: core-text.tests [ t ] [ "Hello world" "Chicago" test-typographic-bounds ] unit-test -[ t ] [ "日本語" "Helvetica" test-typographic-bounds ] unit-test \ No newline at end of file +[ t ] [ "日本語" "Helvetica" test-typographic-bounds ] unit-test diff --git a/basis/core-text/core-text.factor b/basis/core-text/core-text.factor index e431df9414..7af6792e79 100644 --- a/basis/core-text/core-text.factor +++ b/basis/core-text/core-text.factor @@ -149,4 +149,4 @@ SYMBOL: cached-lines : cached-line ( font string -- line ) cached-lines get [ ] 2cache ; -[ cached-lines set-global ] "core-text" add-init-hook +[ cached-lines set-global ] "core-text" add-startup-hook diff --git a/basis/core-text/fonts/fonts.factor b/basis/core-text/fonts/fonts.factor index 5c57034632..63b9a0f6e1 100644 --- a/basis/core-text/fonts/fonts.factor +++ b/basis/core-text/fonts/fonts.factor @@ -127,4 +127,4 @@ MEMO: (cache-font-metrics) ( font -- metrics ) [ \ (cache-font) reset-memoized \ (cache-font-metrics) reset-memoized -] "core-text.fonts" add-init-hook +] "core-text.fonts" add-startup-hook diff --git a/basis/cpu/architecture/architecture.factor b/basis/cpu/architecture/architecture.factor index 6723956780..03090dc4b5 100644 --- a/basis/cpu/architecture/architecture.factor +++ b/basis/cpu/architecture/architecture.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2006, 2009 Slava Pestov. +! Copyright (C) 2006, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs generic kernel kernel.private math memory namespaces make sequences layouts system hashtables @@ -95,7 +95,7 @@ double-rep vector-rep scalar-rep ; -: unsign-rep ( rep -- rep' ) +: signed-rep ( rep -- rep' ) { { uint-4-rep int-4-rep } { ulonglong-2-rep longlong-2-rep } @@ -105,7 +105,7 @@ scalar-rep ; { ushort-scalar-rep short-scalar-rep } { uint-scalar-rep int-scalar-rep } { ulonglong-scalar-rep longlong-scalar-rep } - } ?at drop ; + } ?at drop ; foldable : widen-vector-rep ( rep -- rep' ) { @@ -115,7 +115,19 @@ scalar-rep ; { uchar-16-rep ushort-8-rep } { ushort-8-rep uint-4-rep } { uint-4-rep ulonglong-2-rep } - } at ; + { float-4-rep double-2-rep } + } at ; foldable + +: narrow-vector-rep ( rep -- rep' ) + { + { short-8-rep char-16-rep } + { int-4-rep short-8-rep } + { longlong-2-rep int-4-rep } + { ushort-8-rep uchar-16-rep } + { uint-4-rep ushort-8-rep } + { ulonglong-2-rep uint-4-rep } + { double-2-rep float-4-rep } + } at ; foldable ! Register classes SINGLETONS: int-regs float-regs ; @@ -271,14 +283,18 @@ HOOK: %add-sub-vector cpu ( dst src1 src2 rep -- ) HOOK: %sub-vector cpu ( dst src1 src2 rep -- ) HOOK: %saturated-sub-vector cpu ( dst src1 src2 rep -- ) HOOK: %mul-vector cpu ( dst src1 src2 rep -- ) +HOOK: %mul-high-vector cpu ( dst src1 src2 rep -- ) +HOOK: %mul-horizontal-add-vector cpu ( dst src1 src2 rep -- ) HOOK: %saturated-mul-vector cpu ( dst src1 src2 rep -- ) HOOK: %div-vector cpu ( dst src1 src2 rep -- ) HOOK: %min-vector cpu ( dst src1 src2 rep -- ) HOOK: %max-vector cpu ( dst src1 src2 rep -- ) +HOOK: %avg-vector cpu ( dst src1 src2 rep -- ) HOOK: %dot-vector cpu ( dst src1 src2 rep -- ) +HOOK: %sad-vector cpu ( dst src1 src2 rep -- ) HOOK: %sqrt-vector cpu ( dst src rep -- ) -HOOK: %horizontal-add-vector cpu ( dst src rep -- ) -HOOK: %horizontal-sub-vector cpu ( dst src rep -- ) +HOOK: %horizontal-add-vector cpu ( dst src1 src2 rep -- ) +HOOK: %horizontal-sub-vector cpu ( dst src1 src2 rep -- ) HOOK: %abs-vector cpu ( dst src rep -- ) HOOK: %and-vector cpu ( dst src1 src2 rep -- ) HOOK: %andn-vector cpu ( dst src1 src2 rep -- ) @@ -320,11 +336,15 @@ HOOK: %add-sub-vector-reps cpu ( -- reps ) HOOK: %sub-vector-reps cpu ( -- reps ) HOOK: %saturated-sub-vector-reps cpu ( -- reps ) HOOK: %mul-vector-reps cpu ( -- reps ) +HOOK: %mul-high-vector-reps cpu ( -- reps ) +HOOK: %mul-horizontal-add-vector-reps cpu ( -- reps ) HOOK: %saturated-mul-vector-reps cpu ( -- reps ) HOOK: %div-vector-reps cpu ( -- reps ) HOOK: %min-vector-reps cpu ( -- reps ) HOOK: %max-vector-reps cpu ( -- reps ) +HOOK: %avg-vector-reps cpu ( -- reps ) HOOK: %dot-vector-reps cpu ( -- reps ) +HOOK: %sad-vector-reps cpu ( -- reps ) HOOK: %sqrt-vector-reps cpu ( -- reps ) HOOK: %horizontal-add-vector-reps cpu ( -- reps ) HOOK: %horizontal-sub-vector-reps cpu ( -- reps ) @@ -385,6 +405,10 @@ M: object %shr-vector-imm-reps { } ; M: object %horizontal-shl-vector-imm-reps { } ; M: object %horizontal-shr-vector-imm-reps { } ; +ALIAS: %merge-vector-head-reps %merge-vector-reps +ALIAS: %merge-vector-tail-reps %merge-vector-reps +ALIAS: %tail>head-vector-reps %unpack-vector-head-reps + HOOK: %unbox-alien cpu ( dst src -- ) HOOK: %unbox-any-c-ptr cpu ( dst src -- ) HOOK: %box-alien cpu ( dst src temp -- ) @@ -479,8 +503,27 @@ HOOK: dummy-int-params? cpu ( -- ? ) ! If t, all int parameters are shadowed by dummy FP parameters HOOK: dummy-fp-params? cpu ( -- ? ) -HOOK: %prepare-unbox cpu ( n -- ) +! Load a value (from the data stack in the ds register). +! The value is then passed as a parameter to a VM to_*() function +HOOK: %pop-stack cpu ( n -- ) +! Store a value (to the data stack in the VM's current context) +! The value is passed to a VM to_*() function -- used for +! callback returns +HOOK: %pop-context-stack cpu ( -- ) + +! Store a value (to the data stack in the ds register). +! The value was returned from a VM from_*() function +HOOK: %push-stack cpu ( -- ) + +! Store a value (to the data stack in the VM's current context) +! The value is returned from a VM from_*() function -- used for +! callback parameters +HOOK: %push-context-stack cpu ( -- ) + +! Call a function to convert a tagged pointer returned by +! %pop-stack or %pop-context-stack into a value that can be +! passed to a C function, or returned from a callback HOOK: %unbox cpu ( n rep func -- ) HOOK: %unbox-long-long cpu ( n func -- ) @@ -489,6 +532,10 @@ HOOK: %unbox-small-struct cpu ( c-type -- ) HOOK: %unbox-large-struct cpu ( n c-type -- ) +! Call a function to convert a value into a tagged pointer, +! possibly allocating a bignum, float, or alien instance, +! which is then pushed on the data stack by %push-stack or +! %push-context-stack HOOK: %box cpu ( n rep func -- ) HOOK: %box-long-long cpu ( n func -- ) @@ -503,7 +550,9 @@ HOOK: %save-param-reg cpu ( stack reg rep -- ) HOOK: %load-param-reg cpu ( stack reg rep -- ) -HOOK: %save-context cpu ( temp1 temp2 callback-allowed? -- ) +HOOK: %restore-context cpu ( temp1 temp2 -- ) + +HOOK: %save-context cpu ( temp1 temp2 -- ) HOOK: %prepare-var-args cpu ( -- ) @@ -527,7 +576,6 @@ HOOK: %nest-stacks cpu ( -- ) HOOK: %unnest-stacks cpu ( -- ) -! Return to caller with stdcall unwinding (only for x86) -HOOK: %callback-return cpu ( params -- ) +HOOK: callback-return-rewind cpu ( params -- n ) -M: object %callback-return drop %return ; +M: object callback-return-rewind drop 0 ; diff --git a/basis/cpu/arm/assembler/assembler.factor b/basis/cpu/arm/assembler/assembler.factor old mode 100755 new mode 100644 diff --git a/basis/cpu/ppc/bootstrap.factor b/basis/cpu/ppc/bootstrap.factor index c16d564e13..698fc6257a 100644 --- a/basis/cpu/ppc/bootstrap.factor +++ b/basis/cpu/ppc/bootstrap.factor @@ -1,9 +1,9 @@ -! Copyright (C) 2007, 2008 Slava Pestov. +! Copyright (C) 2007, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: bootstrap.image.private kernel kernel.private namespaces -system cpu.ppc.assembler compiler.codegen.fixup compiler.units -compiler.constants math math.private layouts words -vocabs slots.private locals.backend ; +system cpu.ppc.assembler compiler.units compiler.constants math +math.private math.ranges layouts words vocabs slots.private +locals locals.backend generic.single.private fry sequences ; FROM: cpu.ppc.assembler => B ; IN: bootstrap.ppc @@ -12,17 +12,92 @@ big-endian on CONSTANT: ds-reg 13 CONSTANT: rs-reg 14 +CONSTANT: vm-reg 15 +CONSTANT: ctx-reg 16 -: factor-area-size ( -- n ) 4 bootstrap-cells ; +: factor-area-size ( -- n ) 16 ; : stack-frame ( -- n ) - factor-area-size c-area-size + 4 bootstrap-cells align ; + reserved-size + factor-area-size + + 16 align ; -: next-save ( -- n ) stack-frame bootstrap-cell - ; -: xt-save ( -- n ) stack-frame 2 bootstrap-cells - ; +: next-save ( -- n ) stack-frame 4 - ; +: xt-save ( -- n ) stack-frame 8 - ; + +: param-size ( -- n ) 32 ; + +: save-at ( m -- n ) reserved-size + param-size + ; + +: save-int ( register offset -- ) [ 1 ] dip save-at STW ; +: restore-int ( register offset -- ) [ 1 ] dip save-at LWZ ; + +: save-fp ( register offset -- ) [ 1 ] dip save-at STFD ; +: restore-fp ( register offset -- ) [ 1 ] dip save-at LFD ; + +: save-vec ( register offset -- ) save-at 2 LI 2 1 STVXL ; +: restore-vec ( register offset -- ) save-at 2 LI 2 1 LVXL ; + +: nv-int-regs ( -- seq ) 13 31 [a,b] ; +: nv-fp-regs ( -- seq ) 14 31 [a,b] ; +: nv-vec-regs ( -- seq ) 20 31 [a,b] ; + +: saved-int-regs-size ( -- n ) 96 ; +: saved-fp-regs-size ( -- n ) 144 ; +: saved-vec-regs-size ( -- n ) 208 ; + +: callback-frame-size ( -- n ) + reserved-size + param-size + + saved-int-regs-size + + saved-fp-regs-size + + saved-vec-regs-size + + 16 align ; [ - 0 3 LOAD32 rc-absolute-ppc-2/2 rt-immediate jit-rel + 0 MFLR + 1 1 callback-frame-size neg STWU + 0 1 callback-frame-size lr-save + STW + + nv-int-regs [ 4 * save-int ] each-index + nv-fp-regs [ 8 * 80 + save-fp ] each-index + nv-vec-regs [ 16 * 224 + save-vec ] each-index + + 0 vm-reg LOAD32 rc-absolute-ppc-2/2 rt-vm jit-rel + + 0 2 LOAD32 rc-absolute-ppc-2/2 rt-entry-point jit-rel + 2 MTLR + BLRL + + nv-vec-regs [ 16 * 224 + restore-vec ] each-index + nv-fp-regs [ 8 * 80 + restore-fp ] each-index + nv-int-regs [ 4 * restore-int ] each-index + + 0 1 callback-frame-size lr-save + LWZ + 1 1 0 LWZ + 0 MTLR + BLR +] callback-stub jit-define + +: jit-conditional* ( test-quot false-quot -- ) + [ '[ 4 /i 1 + @ ] ] dip jit-conditional ; inline + +: jit-load-context ( -- ) + ctx-reg vm-reg vm-context-offset LWZ ; + +: jit-save-context ( -- ) + jit-load-context + 1 ctx-reg context-callstack-top-offset STW + ds-reg ctx-reg context-datastack-offset STW + rs-reg ctx-reg context-retainstack-offset STW ; + +: jit-restore-context ( -- ) + jit-load-context + ds-reg ctx-reg context-datastack-offset LWZ + rs-reg ctx-reg context-retainstack-offset LWZ ; + +[ + 0 3 LOAD32 rc-absolute-ppc-2/2 rt-literal jit-rel 11 3 profile-count-offset LWZ 11 11 1 tag-fixnum ADDI 11 3 profile-count-offset STW @@ -33,46 +108,42 @@ CONSTANT: rs-reg 14 ] jit-profiling jit-define [ - 0 3 LOAD32 rc-absolute-ppc-2/2 rt-this jit-rel + 0 2 LOAD32 rc-absolute-ppc-2/2 rt-this jit-rel 0 MFLR 1 1 stack-frame SUBI - 3 1 xt-save STW - stack-frame 3 LI - 3 1 next-save STW + 2 1 xt-save STW + stack-frame 2 LI + 2 1 next-save STW 0 1 lr-save stack-frame + STW ] jit-prolog jit-define [ - 0 3 LOAD32 rc-absolute-ppc-2/2 rt-immediate jit-rel + 0 3 LOAD32 rc-absolute-ppc-2/2 rt-literal jit-rel 3 ds-reg 4 STWU -] jit-push-immediate jit-define +] jit-push jit-define [ - 0 3 LOAD32 rc-absolute-ppc-2/2 rt-stack-chain jit-rel - 4 3 0 LWZ - 1 4 0 STW - 4 0 swap LOAD32 rc-absolute-ppc-2/2 rt-vm jit-rel - 0 5 LOAD32 rc-absolute-ppc-2/2 rt-primitive jit-rel - 5 MTCTR - BCTR + jit-save-context + 3 vm-reg MR + 0 4 LOAD32 rc-absolute-ppc-2/2 rt-dlsym jit-rel + 4 MTLR + BLRL + jit-restore-context ] jit-primitive jit-define -[ 0 BL rc-relative-ppc-3 rt-xt-pic jit-rel ] jit-word-call jit-define +[ 0 BL rc-relative-ppc-3 rt-entry-point-pic jit-rel ] jit-word-call jit-define [ 0 6 LOAD32 rc-absolute-ppc-2/2 rt-here jit-rel - 0 B rc-relative-ppc-3 rt-xt-pic-tail jit-rel + 0 B rc-relative-ppc-3 rt-entry-point-pic-tail jit-rel ] jit-word-jump jit-define -[ 0 B rc-relative-ppc-3 rt-xt jit-rel ] jit-word-special jit-define - [ 3 ds-reg 0 LWZ ds-reg dup 4 SUBI 0 3 \ f type-number CMPI - 2 BEQ - 0 B rc-relative-ppc-3 rt-xt jit-rel - 0 B rc-relative-ppc-3 rt-xt jit-rel + [ BEQ ] [ 0 B rc-relative-ppc-3 rt-entry-point jit-rel ] jit-conditional* + 0 B rc-relative-ppc-3 rt-entry-point jit-rel ] jit-if jit-define : jit->r ( -- ) @@ -123,32 +194,22 @@ CONSTANT: rs-reg 14 [ jit->r - 0 BL rc-relative-ppc-3 rt-xt jit-rel + 0 BL rc-relative-ppc-3 rt-entry-point jit-rel jit-r> ] jit-dip jit-define [ jit-2>r - 0 BL rc-relative-ppc-3 rt-xt jit-rel + 0 BL rc-relative-ppc-3 rt-entry-point jit-rel jit-2r> ] jit-2dip jit-define [ jit-3>r - 0 BL rc-relative-ppc-3 rt-xt jit-rel + 0 BL rc-relative-ppc-3 rt-entry-point jit-rel jit-3r> ] jit-3dip jit-define -: prepare-(execute) ( -- operand ) - 3 ds-reg 0 LWZ - ds-reg dup 4 SUBI - 4 3 word-xt-offset LWZ - 4 ; - -[ prepare-(execute) MTCTR BCTR ] jit-execute-jump jit-define - -[ prepare-(execute) MTLR BLRL ] jit-execute-call jit-define - [ 0 1 lr-save stack-frame + LWZ 1 1 stack-frame ADDI @@ -179,35 +240,57 @@ CONSTANT: rs-reg 14 3 4 MR load-tag 0 4 tuple type-number tag-fixnum CMPI - 2 BNE - 4 3 tuple type-number neg bootstrap-cell + LWZ + [ BNE ] + [ 4 3 tuple type-number neg 4 + LWZ ] + jit-conditional* ] pic-tuple jit-define [ - 0 4 0 CMPI rc-absolute-ppc-2 rt-immediate jit-rel + 0 4 0 CMPI rc-absolute-ppc-2 rt-literal jit-rel ] pic-check-tag jit-define [ - 0 5 LOAD32 rc-absolute-ppc-2/2 rt-immediate jit-rel + 0 5 LOAD32 rc-absolute-ppc-2/2 rt-literal jit-rel 4 0 5 CMP ] pic-check-tuple jit-define -[ 2 BNE 0 B rc-relative-ppc-3 rt-xt jit-rel ] pic-hit jit-define +[ + [ BNE ] [ 0 B rc-relative-ppc-3 rt-entry-point jit-rel ] jit-conditional* +] pic-hit jit-define + +! Inline cache miss entry points +: jit-load-return-address ( -- ) 6 MFLR ; + +! These are always in tail position with an existing stack +! frame, and the stack. The frame setup takes this into account. +: jit-inline-cache-miss ( -- ) + jit-save-context + 3 6 MR + 4 vm-reg MR + 0 5 LOAD32 "inline_cache_miss" f rc-absolute-ppc-2/2 jit-dlsym + 5 MTLR + BLRL + jit-restore-context ; + +[ jit-load-return-address jit-inline-cache-miss ] +[ 3 MTLR BLRL ] +[ 3 MTCTR BCTR ] +\ inline-cache-miss define-combinator-primitive + +[ jit-inline-cache-miss ] +[ 3 MTLR BLRL ] +[ 3 MTCTR BCTR ] +\ inline-cache-miss-tail define-combinator-primitive ! ! ! Megamorphic caches [ ! cache = ... - 0 3 LOAD32 rc-absolute-ppc-2/2 rt-immediate jit-rel + 0 3 LOAD32 rc-absolute-ppc-2/2 rt-literal jit-rel ! key = hashcode(class) - 5 4 3 SRAWI - 6 4 8 SRAWI - 5 5 6 ADD - 6 4 13 SRAWI - 5 5 6 ADD - 5 5 3 SLWI + 5 4 1 SRAWI ! key &= cache.length - 1 - 5 5 mega-cache-size get 1 - bootstrap-cell * ANDI + 5 5 mega-cache-size get 1 - 4 * ANDI ! cache += array-start-offset 3 3 array-start-offset ADDI ! cache += key @@ -215,37 +298,121 @@ CONSTANT: rs-reg 14 ! if(get(cache) == class) 6 3 0 LWZ 6 0 4 CMP - 10 BNE - ! megamorphic_cache_hits++ - 0 4 LOAD32 rc-absolute-ppc-2/2 rt-megamorphic-cache-hits jit-rel - 5 4 0 LWZ - 5 5 1 ADDI - 5 4 0 STW - ! ... goto get(cache + bootstrap-cell) - 3 3 4 LWZ - 3 3 word-xt-offset LWZ - 3 MTCTR - BCTR + [ BNE ] + [ + ! megamorphic_cache_hits++ + 0 4 LOAD32 rc-absolute-ppc-2/2 rt-megamorphic-cache-hits jit-rel + 5 4 0 LWZ + 5 5 1 ADDI + 5 4 0 STW + ! ... goto get(cache + 4) + 3 3 4 LWZ + 3 3 word-entry-point-offset LWZ + 3 MTCTR + BCTR + ] + jit-conditional* ! fall-through on miss ] mega-lookup jit-define -[ - 0 2 LOAD32 rc-absolute-ppc-2/2 rt-xt jit-rel - 2 MTCTR - BCTR -] callback-stub jit-define - ! ! ! Sub-primitives ! Quotations and words [ 3 ds-reg 0 LWZ ds-reg dup 4 SUBI - 4 0 swap LOAD32 0 jit-literal rc-absolute-ppc-2/2 rt-vm jit-rel - 5 3 quot-xt-offset LWZ - 5 MTCTR + 5 3 quot-entry-point-offset LWZ +] +[ 5 MTLR BLRL ] +[ 5 MTCTR BCTR ] \ (call) define-combinator-primitive + +[ + 3 ds-reg 0 LWZ + ds-reg dup 4 SUBI + 4 3 word-entry-point-offset LWZ +] +[ 4 MTLR BLRL ] +[ 4 MTCTR BCTR ] \ (execute) define-combinator-primitive + +[ + 3 ds-reg 0 LWZ + ds-reg dup 4 SUBI + 4 3 word-entry-point-offset LWZ + 4 MTCTR BCTR +] jit-execute jit-define + +! Special primitives +[ + jit-restore-context + ! Save ctx->callstack_bottom + 1 ctx-reg context-callstack-bottom-offset STW + ! Call quotation + 5 3 quot-entry-point-offset LWZ + 5 MTLR + BLRL + jit-save-context +] \ c-to-factor define-sub-primitive + +[ + ! Unwind stack frames + 1 4 MR + + ! Load VM pointer into vm-reg, since we're entering from + ! C code + 0 vm-reg LOAD32 0 rc-absolute-ppc-2/2 jit-vm + + ! Load ds and rs registers + jit-restore-context + + ! We have changed the stack; load return address again + 0 1 lr-save LWZ + 0 MTLR + + ! Call quotation + 4 3 quot-entry-point-offset LWZ + 4 MTCTR BCTR -] \ (call) define-sub-primitive +] \ unwind-native-frames define-sub-primitive + +[ + ! Load callstack object + 6 ds-reg 0 LWZ + ds-reg ds-reg 4 SUBI + ! Get ctx->callstack_bottom + jit-load-context + 3 ctx-reg context-callstack-bottom-offset LWZ + ! Get top of callstack object -- 'src' for memcpy + 4 6 callstack-top-offset ADDI + ! Get callstack length, in bytes --- 'len' for memcpy + 5 6 callstack-length-offset LWZ + 5 5 tag-bits get SRAWI + ! Compute new stack pointer -- 'dst' for memcpy + 3 5 3 SUBF + ! Install new stack pointer + 1 3 MR + ! Call memcpy; arguments are now in the correct registers + 1 1 -64 STWU + 0 2 LOAD32 "factor_memcpy" f rc-absolute-ppc-2/2 jit-dlsym + 2 MTLR + BLRL + 1 1 0 LWZ + ! Return with new callstack + 0 1 lr-save LWZ + 0 MTLR + BLR +] \ set-callstack define-sub-primitive + +[ + jit-save-context + 4 vm-reg MR + 0 2 LOAD32 "lazy_jit_compile" f rc-absolute-ppc-2/2 jit-dlsym + 2 MTLR + BLRL + 5 3 quot-entry-point-offset LWZ +] +[ 5 MTLR BLRL ] +[ 5 MTCTR BCTR ] +\ lazy-jit-compile define-combinator-primitive ! Objects [ @@ -329,14 +496,6 @@ CONSTANT: rs-reg 14 3 ds-reg 4 STWU ] \ dupd define-sub-primitive -[ - 3 ds-reg 0 LWZ - 4 ds-reg -4 LWZ - 3 ds-reg 4 STWU - 4 ds-reg -4 STW - 3 ds-reg -8 STW -] \ tuck define-sub-primitive - [ 3 ds-reg 0 LWZ 4 ds-reg -4 LWZ @@ -374,7 +533,7 @@ CONSTANT: rs-reg 14 ! Comparisons : jit-compare ( insn -- ) t jit-literal - 0 3 LOAD32 rc-absolute-ppc-2/2 rt-immediate jit-rel + 0 3 LOAD32 rc-absolute-ppc-2/2 rt-literal jit-rel 4 ds-reg 0 LWZ 5 ds-reg -4 LWZU 5 0 4 CMP @@ -400,8 +559,7 @@ CONSTANT: rs-reg 14 3 3 tag-mask get ANDI \ f type-number 4 LI 0 3 0 CMPI - 2 BNE - 1 tag-fixnum 4 LI + [ BNE ] [ 1 tag-fixnum 4 LI ] jit-conditional* 4 ds-reg 0 STW ] \ both-fixnums? define-sub-primitive @@ -446,8 +604,7 @@ CONSTANT: rs-reg 14 7 4 6 SRAW 7 7 0 0 31 tag-bits get - RLWINM 0 3 0 CMPI - 2 BGT - 5 7 MR + [ BGT ] [ 5 7 MR ] jit-conditional* 5 ds-reg 0 STW ] \ fixnum-shift-fast define-sub-primitive @@ -483,7 +640,7 @@ CONSTANT: rs-reg 14 [ 3 ds-reg 0 LWZ - 3 3 1 SRAWI + 3 3 2 SRAWI rs-reg 3 3 LWZX 3 ds-reg 0 STW ] \ get-local define-sub-primitive @@ -491,8 +648,52 @@ CONSTANT: rs-reg 14 [ 3 ds-reg 0 LWZ ds-reg ds-reg 4 SUBI - 3 3 1 SRAWI + 3 3 2 SRAWI rs-reg 3 rs-reg SUBF ] \ drop-locals define-sub-primitive +! Overflowing fixnum arithmetic +:: jit-overflow ( insn func -- ) + ds-reg ds-reg 4 SUBI + jit-save-context + 3 ds-reg 0 LWZ + 4 ds-reg 4 LWZ + 0 0 LI + 0 MTXER + 6 4 3 insn call( d a s -- ) + 6 ds-reg 0 STW + [ BNO ] + [ + 5 vm-reg MR + 0 6 LOAD32 func f rc-absolute-ppc-2/2 jit-dlsym + 6 MTLR + BLRL + ] + jit-conditional* ; + +[ [ ADDO. ] "overflow_fixnum_add" jit-overflow ] \ fixnum+ define-sub-primitive + +[ [ SUBFO. ] "overflow_fixnum_subtract" jit-overflow ] \ fixnum- define-sub-primitive + +[ + ds-reg ds-reg 4 SUBI + jit-save-context + 3 ds-reg 0 LWZ + 3 3 tag-bits get SRAWI + 4 ds-reg 4 LWZ + 0 0 LI + 0 MTXER + 6 3 4 MULLWO. + 6 ds-reg 0 STW + [ BNO ] + [ + 4 4 tag-bits get SRAWI + 5 vm-reg MR + 0 6 LOAD32 "overflow_fixnum_multiply" f rc-absolute-ppc-2/2 jit-dlsym + 6 MTLR + BLRL + ] + jit-conditional* +] \ fixnum* define-sub-primitive + [ "bootstrap.ppc" forget-vocab ] with-compilation-unit diff --git a/basis/cpu/ppc/linux/bootstrap.factor b/basis/cpu/ppc/linux/bootstrap.factor index a5250414ab..2f463dea00 100644 --- a/basis/cpu/ppc/linux/bootstrap.factor +++ b/basis/cpu/ppc/linux/bootstrap.factor @@ -1,10 +1,10 @@ -! Copyright (C) 2007, 2008 Slava Pestov. +! Copyright (C) 2007, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: parser layouts system kernel sequences ; +USING: parser system kernel sequences ; IN: bootstrap.ppc -: c-area-size ( -- n ) 10 bootstrap-cells ; -: lr-save ( -- n ) bootstrap-cell ; +: reserved-size ( -- n ) 24 ; +: lr-save ( -- n ) 4 ; << "vocab:cpu/ppc/bootstrap.factor" parse-file suffix! >> call diff --git a/basis/cpu/ppc/macosx/bootstrap.factor b/basis/cpu/ppc/macosx/bootstrap.factor index 2aa0ddc4a2..0960011c70 100644 --- a/basis/cpu/ppc/macosx/bootstrap.factor +++ b/basis/cpu/ppc/macosx/bootstrap.factor @@ -1,10 +1,10 @@ -! Copyright (C) 2007, 2008 Slava Pestov. +! Copyright (C) 2007, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: parser layouts system kernel sequences ; +USING: parser system kernel sequences ; IN: bootstrap.ppc -: c-area-size ( -- n ) 14 bootstrap-cells ; -: lr-save ( -- n ) 2 bootstrap-cells ; +: reserved-size ( -- n ) 24 ; +: lr-save ( -- n ) 8 ; << "vocab:cpu/ppc/bootstrap.factor" parse-file suffix! >> call diff --git a/basis/cpu/ppc/macosx/macosx.factor b/basis/cpu/ppc/macosx/macosx.factor index c742cf2ddc..152a3aa720 100644 --- a/basis/cpu/ppc/macosx/macosx.factor +++ b/basis/cpu/ppc/macosx/macosx.factor @@ -4,12 +4,6 @@ USING: accessors system kernel layouts alien.c-types cpu.architecture cpu.ppc ; IN: cpu.ppc.macosx -<< -4 "longlong" c-type (>>align) -4 "ulonglong" c-type (>>align) -4 "double" c-type (>>align) ->> - M: macosx reserved-area-size 6 cells ; M: macosx lr-save 2 cells ; diff --git a/basis/cpu/ppc/ppc.factor b/basis/cpu/ppc/ppc.factor index 0f33df8df7..a914b3551e 100644 --- a/basis/cpu/ppc/ppc.factor +++ b/basis/cpu/ppc/ppc.factor @@ -15,7 +15,10 @@ IN: cpu.ppc ! PowerPC register assignments: ! r2-r12: integer vregs -! r15-r29 +! r13: data stack +! r14: retain stack +! r15: VM pointer +! r16-r29: integer vregs ! r30: integer scratch ! f0-f29: float vregs ! f30: float scratch @@ -31,18 +34,9 @@ enable-float-intrinsics \ ##float>integer t frame-required? set-word-prop >> -: %load-vm-addr ( reg -- ) - 0 swap LOAD32 0 rc-absolute-ppc-2/2 rel-vm ; - -: %load-vm-field-addr ( reg symbol -- ) - [ 0 swap LOAD32 ] dip - vm-field-offset rc-absolute-ppc-2/2 rel-vm ; - -M: ppc %vm-field-ptr ( dst field -- ) %load-vm-field-addr ; - M: ppc machine-registers { - { int-regs $[ 2 12 [a,b] 15 29 [a,b] append ] } + { int-regs $[ 2 12 [a,b] 16 29 [a,b] append ] } { float-regs $[ 0 29 [a,b] ] } } ; @@ -59,6 +53,14 @@ M: ppc %alien-global ( register symbol dll -- ) CONSTANT: ds-reg 13 CONSTANT: rs-reg 14 +CONSTANT: vm-reg 15 + +: %load-vm-addr ( reg -- ) vm-reg MR ; + +: %load-vm-field-addr ( reg symbol -- ) + [ vm-reg ] dip vm-field-offset ADDI ; + +M: ppc %vm-field-ptr ( dst field -- ) %load-vm-field-addr ; GENERIC: loc-reg ( loc -- reg ) @@ -79,10 +81,10 @@ M: ppc %inc-r ( n -- ) rs-reg (%inc) ; HOOK: reserved-area-size os ( -- n ) ! The start of the stack frame contains the size of this frame -! as well as the currently executing XT +! as well as the currently executing code block : factor-area-size ( -- n ) 2 cells ; foldable -: next-save ( n -- i ) cell - ; -: xt-save ( n -- i ) 2 cells - ; +: next-save ( n -- i ) cell - ; foldable +: xt-save ( n -- i ) 2 cells - ; foldable ! Next, we have the spill area as well as the FFI parameter area. ! It is safe for them to overlap, since basic blocks with FFI calls @@ -124,7 +126,7 @@ M: ppc stack-frame-size ( stack-frame -- i ) M: ppc %call ( word -- ) 0 BL rc-relative-ppc-3 rel-word-pic ; M: ppc %jump ( word -- ) - 0 6 LOAD32 8 rc-absolute-ppc-2/2 rel-here + 0 6 LOAD32 4 rc-absolute-ppc-2/2 rel-here 0 B rc-relative-ppc-3 rel-word-pic-tail ; M: ppc %jump-label ( label -- ) B ; @@ -132,7 +134,7 @@ M: ppc %return ( -- ) BLR ; M:: ppc %dispatch ( src temp -- ) 0 temp LOAD32 - 4 cells rc-absolute-ppc-2/2 rel-here + 3 cells rc-absolute-ppc-2/2 rel-here temp temp src LWZX temp MTCTR BCTR ; @@ -256,35 +258,22 @@ M: ppc %double>single-float FRSP ; M: ppc %unbox-alien ( dst src -- ) alien-offset LWZ ; -M:: ppc %unbox-any-c-ptr ( dst src temp -- ) +M:: ppc %unbox-any-c-ptr ( dst src -- ) [ - { "is-byte-array" "end" "start" } [ define-label ] each - ! Address is computed in dst + "end" define-label 0 dst LI - ! Load object into scratch-reg - scratch-reg src MR - ! We come back here with displaced aliens - "start" resolve-label ! Is the object f? - 0 scratch-reg \ f type-number CMPI - ! If so, done + 0 src \ f type-number CMPI "end" get BEQ + ! Compute tag in dst register + dst src tag-mask get ANDI ! Is the object an alien? - 0 scratch-reg header-offset LWZ - 0 0 alien type-number tag-fixnum CMPI - "is-byte-array" get BNE - ! If so, load the offset - 0 scratch-reg alien-offset LWZ - ! Add it to address being computed - dst dst 0 ADD - ! Now recurse on the underlying alien - scratch-reg scratch-reg underlying-alien-offset LWZ - "start" get B - "is-byte-array" resolve-label - ! Add byte array address to address being computed - dst dst scratch-reg ADD - ! Add an offset to start of byte array's data area - dst dst byte-array-offset ADDI + 0 dst alien type-number CMPI + ! Add an offset to start of byte array's data + dst src byte-array-offset ADDI + "end" get BNE + ! If so, load the offset and add it to the address + dst src alien-offset LWZ "end" resolve-label ] with-scope ; @@ -293,53 +282,84 @@ M:: ppc %unbox-any-c-ptr ( dst src temp -- ) M:: ppc %box-alien ( dst src temp -- ) [ "f" define-label - dst %load-immediate + dst \ f type-number %load-immediate 0 src 0 CMPI "f" get BEQ dst 5 cells alien temp %allot temp \ f type-number %load-immediate temp dst 1 alien@ STW temp dst 2 alien@ STW - displacement dst 3 alien@ STW - displacement dst 4 alien@ STW + src dst 3 alien@ STW + src dst 4 alien@ STW "f" resolve-label ] with-scope ; -M:: ppc %box-displaced-alien ( dst displacement base displacement' base' base-class -- ) +M:: ppc %box-displaced-alien ( dst displacement base temp base-class -- ) + ! This is ridiculous [ "end" define-label - "alloc" define-label - "simple-case" define-label + "not-f" define-label + "not-alien" define-label + ! If displacement is zero, return the base dst base MR 0 displacement 0 CMPI "end" get BEQ - ! Quickly use displacement' before its needed for real, as allot temporary - displacement' :> temp - dst 4 cells alien temp %allot - ! If base is already a displaced alien, unpack it - 0 base \ f type-number CMPI - "simple-case" get BEQ - temp base header-offset LWZ - 0 temp alien type-number tag-fixnum CMPI - "simple-case" get BNE - ! displacement += base.displacement - temp base 3 alien@ LWZ - displacement' displacement temp ADD - ! base = base.base - base' base 1 alien@ LWZ - "alloc" get B - "simple-case" resolve-label - displacement' displacement MR - base' base MR - "alloc" resolve-label - ! Store underlying-alien slot - base' dst 1 alien@ STW - ! Store offset - displacement' dst 3 alien@ STW - ! Store expired slot (its ok to clobber displacement') + + ! Displacement is non-zero, we're going to be allocating a new + ! object + dst 5 cells alien temp %allot + + ! Set expired to f temp \ f type-number %load-immediate temp dst 2 alien@ STW + + ! Is base f? + 0 base \ f type-number CMPI + "not-f" get BNE + + ! Yes, it is f. Fill in new object + base dst 1 alien@ STW + displacement dst 3 alien@ STW + displacement dst 4 alien@ STW + + "end" get B + + "not-f" resolve-label + + ! Check base type + temp base tag-mask get ANDI + + ! Is base an alien? + 0 temp alien type-number CMPI + "not-alien" get BNE + + ! Yes, it is an alien. Set new alien's base to base.base + temp base 1 alien@ LWZ + temp dst 1 alien@ STW + + ! Compute displacement + temp base 3 alien@ LWZ + temp temp displacement ADD + temp dst 3 alien@ STW + + ! Compute address + temp base 4 alien@ LWZ + temp temp displacement ADD + temp dst 4 alien@ STW + + ! We are done + "end" get B + + ! Is base a byte array? It has to be, by now... + "not-alien" resolve-label + + base dst 1 alien@ STW + displacement dst 3 alien@ STW + temp base byte-array-offset ADDI + temp temp displacement ADD + temp dst 4 alien@ STW + "end" resolve-label ] with-scope ; @@ -373,7 +393,7 @@ M: ppc %set-alien-double -rot STFD ; scratch-reg nursery-ptr 0 STW ; :: store-header ( dst class -- ) - class type-number tag-fixnum scratch-reg LI + class type-number tag-header scratch-reg LI scratch-reg dst 0 STW ; : store-tagged ( dst tag -- ) @@ -544,14 +564,16 @@ M:: ppc %compare-float-unordered-branch ( label src1 src2 cc -- ) { stack-params [ [ 0 1 ] dip LWZ [ 0 1 ] dip param@ STW ] } } case ; -: next-param@ ( n -- x ) param@ stack-frame get total-size>> + ; +: next-param@ ( n -- reg x ) + 2 1 stack-frame get total-size>> LWZ + [ 2 ] dip param@ ; : store-to-frame ( src n rep -- ) { { int-rep [ [ 1 ] dip STW ] } { float-rep [ [ 1 ] dip STFS ] } { double-rep [ [ 1 ] dip STFD ] } - { stack-params [ [ [ 0 1 ] dip next-param@ LWZ 0 1 ] dip STW ] } + { stack-params [ [ [ 0 ] dip next-param@ LWZ 0 1 ] dip STW ] } } case ; M: ppc %spill ( src rep dst -- ) @@ -572,9 +594,34 @@ M:: ppc %save-param-reg ( stack reg rep -- ) M:: ppc %load-param-reg ( stack reg rep -- ) reg stack local@ rep load-from-frame ; -M: ppc %prepare-unbox ( n -- ) +M: ppc %pop-stack ( n -- ) [ 3 ] dip loc>operand LWZ ; +M: ppc %push-stack ( -- ) + ds-reg ds-reg 4 ADDI + int-regs return-reg ds-reg 0 STW ; + +:: %load-context-datastack ( dst -- ) + ! Load context struct + dst "ctx" %vm-field-ptr + dst dst 0 LWZ + ! Load context datastack pointer + dst dst "datastack" context-field-offset ADDI ; + +M: ppc %push-context-stack ( -- ) + 11 %load-context-datastack + 12 11 0 LWZ + 12 12 4 ADDI + 12 11 0 STW + int-regs return-reg 12 0 STW ; + +M: ppc %pop-context-stack ( -- ) + 11 %load-context-datastack + 12 11 0 LWZ + int-regs return-reg 12 0 LWZ + 12 12 4 SUBI + 12 11 0 STW ; + M: ppc %unbox ( n rep func -- ) ! Value must be in r3 4 %load-vm-addr @@ -632,35 +679,43 @@ M: ppc %box-large-struct ( n c-type -- ) [ [ 3 1 ] dip struct-return@ ADDI ] [ heap-size 4 LI ] bi* 5 %load-vm-addr ! Call the function - "box_value_struct" f %alien-invoke ; + "from_value_struct" f %alien-invoke ; -M:: ppc %save-context ( temp1 temp2 callback-allowed? -- ) - #! Save Factor stack pointers in case the C code calls a - #! callback which does a GC, which must reliably trace - #! all roots. - temp1 "stack_chain" %load-vm-field-addr +M:: ppc %restore-context ( temp1 temp2 -- ) + temp1 "ctx" %load-vm-field-addr + temp1 temp1 0 LWZ + temp2 1 stack-frame get total-size>> ADDI + temp2 temp1 "callstack-bottom" context-field-offset STW + ds-reg temp1 8 LWZ + rs-reg temp1 12 LWZ ; + +M:: ppc %save-context ( temp1 temp2 -- ) + temp1 "ctx" %load-vm-field-addr temp1 temp1 0 LWZ 1 temp1 0 STW - callback-allowed? [ - ds-reg temp1 8 STW - rs-reg temp1 12 STW - ] when ; + ds-reg temp1 8 STW + rs-reg temp1 12 STW ; M: ppc %alien-invoke ( symbol dll -- ) [ 11 ] 2dip %alien-global 11 MTLR BLRL ; M: ppc %alien-callback ( quot -- ) + 3 4 %restore-context 3 swap %load-reference - 4 %load-vm-addr - "c_to_factor" f %alien-invoke ; + 4 3 quot-entry-point-offset LWZ + 4 MTLR + BLRL + 3 4 %save-context ; M: ppc %prepare-alien-indirect ( -- ) - 3 %load-vm-addr - "unbox_alien" f %alien-invoke - 15 3 MR ; + 3 ds-reg 0 LWZ + ds-reg ds-reg 4 SUBI + 4 %load-vm-addr + "pinned_alien_offset" f %alien-invoke + 16 3 MR ; M: ppc %alien-indirect ( -- ) - 15 MTLR BLRL ; + 16 MTLR BLRL ; M: ppc %callback-value ( ctype -- ) ! Save top of data stack @@ -685,7 +740,7 @@ M: ppc %box-small-struct ( c-type -- ) #! Box a <= 16-byte struct returned in r3:r4:r5:r6 heap-size 7 LI 8 %load-vm-addr - "box_medium_struct" f %alien-invoke ; + "from_medium_struct" f %alien-invoke ; : %unbox-struct-1 ( -- ) ! Alien must be in r3. @@ -710,9 +765,7 @@ M: ppc %box-small-struct ( c-type -- ) 3 3 0 LWZ ; M: ppc %nest-stacks ( -- ) - ! Save current frame. See comment in vm/contexts.hpp - 3 1 stack-frame get total-size>> 2 cells - ADDI - 4 %load-vm-addr + 3 %load-vm-addr "nest_stacks" f %alien-invoke ; M: ppc %unnest-stacks ( -- ) @@ -720,7 +773,6 @@ M: ppc %unnest-stacks ( -- ) "unnest_stacks" f %alien-invoke ; M: ppc %unbox-small-struct ( size -- ) - #! Alien must be in EAX. heap-size cell align cell /i { { 1 [ %unbox-struct-1 ] } { 2 [ %unbox-struct-2 ] } diff --git a/basis/cpu/x86/32/32-tests.factor b/basis/cpu/x86/32/32-tests.factor new file mode 100644 index 0000000000..bc07e3a25b --- /dev/null +++ b/basis/cpu/x86/32/32-tests.factor @@ -0,0 +1,7 @@ +IN: cpu.x86.32.tests +USING: alien alien.c-types tools.test cpu.x86.assembler +cpu.x86.assembler.operands ; + +: assembly-test-1 ( -- x ) int { } "cdecl" [ EAX 3 MOV ] alien-assembly ; + +[ 3 ] [ assembly-test-1 ] unit-test diff --git a/basis/cpu/x86/32/32.factor b/basis/cpu/x86/32/32.factor old mode 100755 new mode 100644 index 8867ca6597..3348ef0e96 --- a/basis/cpu/x86/32/32.factor +++ b/basis/cpu/x86/32/32.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2005, 2009 Slava Pestov. +! Copyright (C) 2005, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: locals alien.c-types alien.libraries alien.syntax arrays kernel fry math namespaces sequences system layouts io @@ -8,7 +8,8 @@ compiler.codegen compiler.codegen.fixup compiler.cfg.instructions compiler.cfg.builder compiler.cfg.intrinsics compiler.cfg.stack-frame cpu.x86.assembler cpu.x86.assembler.operands cpu.x86 -cpu.architecture ; +cpu.architecture vm ; +FROM: layouts => cell ; IN: cpu.x86.32 M: x86.32 machine-registers @@ -20,8 +21,15 @@ M: x86.32 machine-registers M: x86.32 ds-reg ESI ; M: x86.32 rs-reg EDI ; M: x86.32 stack-reg ESP ; +M: x86.32 frame-reg EBP ; M: x86.32 temp-reg ECX ; +M: x86.32 %mov-vm-ptr ( reg -- ) + 0 MOV 0 rc-absolute-cell rel-vm ; + +M: x86.32 %vm-field-ptr ( dst field -- ) + [ 0 MOV ] dip vm-field-offset rc-absolute-cell rel-vm ; + : local@ ( n -- op ) stack-frame get extra-stack-space dup 16 assert= + stack@ ; @@ -42,7 +50,7 @@ M: x86.32 %mark-deck M:: x86.32 %dispatch ( src temp -- ) ! Load jump table base. temp src HEX: ffffffff [+] LEA - building get length cell - :> start + building get length :> start 0 rc-absolute-cell rel-here ! Go temp HEX: 7f [+] JMP @@ -53,10 +61,6 @@ M:: x86.32 %dispatch ( src temp -- ) [ align-code ] bi ; -! Registers for fastcall -: param-reg-1 ( -- reg ) EAX ; -: param-reg-2 ( -- reg ) EDX ; - M: x86.32 pic-tail-reg EBX ; M: x86.32 reserved-stack-space 4 cells ; @@ -136,7 +140,7 @@ M:: x86.32 %box-large-struct ( n c-type -- ) 8 save-vm-ptr 4 stack@ c-type heap-size MOV 0 stack@ EDX MOV - "box_value_struct" f %alien-invoke ; + "from_value_struct" f %alien-invoke ; M: x86.32 %prepare-box-struct ( -- ) ! Compute target address for value struct return @@ -150,11 +154,17 @@ M: x86.32 %box-small-struct ( c-type -- ) 8 stack@ swap heap-size MOV 4 stack@ EDX MOV 0 stack@ EAX MOV - "box_small_struct" f %alien-invoke ; + "from_small_struct" f %alien-invoke ; -M: x86.32 %prepare-unbox ( -- ) +M: x86.32 %pop-stack ( n -- ) EAX swap ds-reg reg-stack MOV ; +M: x86.32 %pop-context-stack ( -- ) + temp-reg %load-context-datastack + EAX temp-reg [] MOV + EAX EAX [] MOV + temp-reg [] bootstrap-cell SUB ; + : call-unbox-func ( func -- ) 4 save-vm-ptr 0 stack@ EAX MOV @@ -213,10 +223,7 @@ M:: x86.32 %unbox-large-struct ( n c-type -- ) "to_value_struct" f %alien-invoke ; M: x86.32 %nest-stacks ( -- ) - ! Save current frame. See comment in vm/contexts.hpp - EAX stack-reg stack-frame get total-size>> 3 cells - [+] LEA - 4 save-vm-ptr - 0 stack@ EAX MOV + 0 save-vm-ptr "nest_stacks" f %alien-invoke ; M: x86.32 %unnest-stacks ( -- ) @@ -224,21 +231,24 @@ M: x86.32 %unnest-stacks ( -- ) "unnest_stacks" f %alien-invoke ; M: x86.32 %prepare-alien-indirect ( -- ) - 0 save-vm-ptr - "unbox_alien" f %alien-invoke + EAX ds-reg [] MOV + ds-reg 4 SUB + 4 save-vm-ptr + 0 stack@ EAX MOV + "pinned_alien_offset" f %alien-invoke EBP EAX MOV ; M: x86.32 %alien-indirect ( -- ) EBP CALL ; M: x86.32 %alien-callback ( quot -- ) - ! Fastcall - param-reg-1 swap %load-reference - param-reg-2 %mov-vm-ptr - "c_to_factor" f %alien-invoke ; + EAX EDX %restore-context + EAX swap %load-reference + EAX quot-entry-point-offset [+] CALL + EAX EDX %save-context ; M: x86.32 %callback-value ( ctype -- ) - 0 %prepare-unbox + %pop-context-stack 4 stack@ EAX MOV 0 save-vm-ptr ! Restore data/call/retain stacks @@ -294,20 +304,6 @@ M: x86.32 %cleanup ( params -- ) [ drop ] } cond ; -M: x86.32 %callback-return ( n -- ) - #! a) If the callback is stdcall, we have to clean up the - #! caller's stack frame. - #! b) If the callback is returning a large struct, we have - #! to fix ESP. - { - { [ dup abi>> "stdcall" = ] [ - - [ params>> ] [ return>> ] bi + - ] } - { [ dup return>> large-struct? ] [ drop 4 ] } - [ drop 0 ] - } cond RET ; - M:: x86.32 %call-gc ( gc-root-count temp -- ) temp gc-root-base special@ LEA 8 save-vm-ptr @@ -321,6 +317,20 @@ M: x86.32 dummy-int-params? f ; M: x86.32 dummy-fp-params? f ; +M: x86.32 callback-return-rewind ( params -- n ) + #! a) If the callback is stdcall, we have to clean up the + #! caller's stack frame. + #! b) If the callback is returning a large struct, we have + #! to fix ESP. + { + { [ dup abi>> "stdcall" = ] [ + + [ params>> ] [ return>> ] bi + + ] } + { [ dup return>> large-struct? ] [ drop 4 ] } + [ drop 0 ] + } cond ; + ! Dreadful M: object flatten-value-type (flatten-int-type) ; diff --git a/basis/cpu/x86/32/bootstrap.factor b/basis/cpu/x86/32/bootstrap.factor index f777040e86..d11aa952d9 100644 --- a/basis/cpu/x86/32/bootstrap.factor +++ b/basis/cpu/x86/32/bootstrap.factor @@ -1,39 +1,229 @@ -! Copyright (C) 2007, 2009 Slava Pestov. +! Copyright (C) 2007, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: bootstrap.image.private kernel namespaces system -cpu.x86.assembler cpu.x86.assembler.operands layouts -vocabs parser compiler.constants sequences ; +USING: bootstrap.image.private kernel kernel.private namespaces +system cpu.x86.assembler cpu.x86.assembler.operands layouts +vocabs parser compiler.constants sequences math math.private +generic.single.private ; IN: bootstrap.x86 4 \ cell set -: stack-frame-size ( -- n ) 4 bootstrap-cells ; +: stack-frame-size ( -- n ) 8 bootstrap-cells ; : shift-arg ( -- reg ) ECX ; : div-arg ( -- reg ) EAX ; : mod-arg ( -- reg ) EDX ; -: arg1 ( -- reg ) EAX ; -: arg2 ( -- reg ) EDX ; : temp0 ( -- reg ) EAX ; : temp1 ( -- reg ) EDX ; : temp2 ( -- reg ) ECX ; : temp3 ( -- reg ) EBX ; : safe-reg ( -- reg ) EAX ; : stack-reg ( -- reg ) ESP ; +: frame-reg ( -- reg ) EBP ; +: vm-reg ( -- reg ) ECX ; +: ctx-reg ( -- reg ) EBP ; +: nv-regs ( -- seq ) { ESI EDI EBX } ; : ds-reg ( -- reg ) ESI ; : rs-reg ( -- reg ) EDI ; : fixnum>slot@ ( -- ) temp0 2 SAR ; : rex-length ( -- n ) 0 ; [ - ! load stack_chain - temp0 0 [] MOV rc-absolute-cell rt-stack-chain jit-rel - ! save stack pointer - temp0 [] stack-reg MOV - ! pass vm ptr to primitive - arg1 0 MOV rc-absolute-cell rt-vm jit-rel + ! save stack frame size + stack-frame-size PUSH + ! push entry point + 0 PUSH rc-absolute-cell rt-this jit-rel + ! alignment + ESP stack-frame-size 3 bootstrap-cells - SUB +] jit-prolog jit-define + +: jit-load-vm ( -- ) + vm-reg 0 MOV 0 rc-absolute-cell jit-vm ; + +: jit-load-context ( -- ) + ! VM pointer must be in vm-reg already + ctx-reg vm-reg vm-context-offset [+] MOV ; + +: jit-save-context ( -- ) + EDX RSP -4 [+] LEA + ctx-reg context-callstack-top-offset [+] EDX MOV + ctx-reg context-datastack-offset [+] ds-reg MOV + ctx-reg context-retainstack-offset [+] rs-reg MOV ; + +: jit-restore-context ( -- ) + ds-reg ctx-reg context-datastack-offset [+] MOV + rs-reg ctx-reg context-retainstack-offset [+] MOV ; + +[ + jit-load-vm + jit-load-context + jit-save-context ! call the primitive - 0 JMP rc-relative rt-primitive jit-rel + ESP [] vm-reg MOV + 0 CALL rc-relative rt-dlsym jit-rel + ! restore ds, rs registers + jit-restore-context ] jit-primitive jit-define +[ + ! Load quotation + EAX EBP 8 [+] MOV + ! save ctx->callstack_bottom, load ds, rs registers + jit-load-vm + jit-load-context + jit-restore-context + EDX stack-reg stack-frame-size 4 - [+] LEA + ctx-reg context-callstack-bottom-offset [+] EDX MOV + ! call the quotation + EAX quot-entry-point-offset [+] CALL + ! save ds, rs registers + jit-save-context +] \ c-to-factor define-sub-primitive + +[ + EAX ds-reg [] MOV + ds-reg bootstrap-cell SUB +] +[ EAX quot-entry-point-offset [+] CALL ] +[ EAX quot-entry-point-offset [+] JMP ] +\ (call) define-combinator-primitive + +[ + ! Clear x87 stack, but preserve rounding mode and exception flags + ESP 2 SUB + ESP [] FNSTCW + FNINIT + ESP [] FLDCW + ESP 2 ADD + + ! Load arguments + EAX ESP stack-frame-size [+] MOV + EDX ESP stack-frame-size 4 + [+] MOV + + ! Unwind stack frames + ESP EDX MOV + + ! Load ds and rs registers + jit-load-vm + jit-load-context + jit-restore-context + + ! Call quotation + EAX quot-entry-point-offset [+] JMP +] \ unwind-native-frames define-sub-primitive + +[ + ! Load callstack object + EBX ds-reg [] MOV + ds-reg bootstrap-cell SUB + ! Get ctx->callstack_bottom + jit-load-vm + jit-load-context + EAX ctx-reg context-callstack-bottom-offset [+] MOV + ! Get top of callstack object -- 'src' for memcpy + EBP EBX callstack-top-offset [+] LEA + ! Get callstack length, in bytes --- 'len' for memcpy + EDX EBX callstack-length-offset [+] MOV + EDX tag-bits get SHR + ! Compute new stack pointer -- 'dst' for memcpy + EAX EDX SUB + ! Install new stack pointer + ESP EAX MOV + ! Call memcpy + EDX PUSH + EBP PUSH + EAX PUSH + 0 CALL "factor_memcpy" f rc-relative jit-dlsym + ESP 12 ADD + ! Return with new callstack + 0 RET +] \ set-callstack define-sub-primitive + +[ + jit-load-vm + jit-load-context + jit-save-context + + ! Store arguments + ESP [] EAX MOV + ESP 4 [+] vm-reg MOV + + ! Call VM + 0 CALL "lazy_jit_compile" f rc-relative jit-dlsym +] +[ EAX quot-entry-point-offset [+] CALL ] +[ EAX quot-entry-point-offset [+] JMP ] +\ lazy-jit-compile define-combinator-primitive + +! Inline cache miss entry points +: jit-load-return-address ( -- ) + EBX ESP stack-frame-size bootstrap-cell - [+] MOV ; + +! These are always in tail position with an existing stack +! frame, and the stack. The frame setup takes this into account. +: jit-inline-cache-miss ( -- ) + jit-load-vm + jit-load-context + jit-save-context + ESP 4 [+] vm-reg MOV + ESP [] EBX MOV + 0 CALL "inline_cache_miss" f rc-relative jit-dlsym + jit-restore-context ; + +[ jit-load-return-address jit-inline-cache-miss ] +[ EAX CALL ] +[ EAX JMP ] +\ inline-cache-miss define-combinator-primitive + +[ jit-inline-cache-miss ] +[ EAX CALL ] +[ EAX JMP ] +\ inline-cache-miss-tail define-combinator-primitive + +! Overflowing fixnum arithmetic +: jit-overflow ( insn func -- ) + ds-reg 4 SUB + jit-load-vm + jit-load-context + jit-save-context + EAX ds-reg [] MOV + EDX ds-reg 4 [+] MOV + EBX EAX MOV + [ [ EBX EDX ] dip call( dst src -- ) ] dip + ds-reg [] EBX MOV + [ JNO ] + [ + ESP [] EAX MOV + ESP 4 [+] EDX MOV + ESP 8 [+] vm-reg MOV + [ 0 CALL ] dip f rc-relative jit-dlsym + ] + jit-conditional ; + +[ [ ADD ] "overflow_fixnum_add" jit-overflow ] \ fixnum+ define-sub-primitive + +[ [ SUB ] "overflow_fixnum_subtract" jit-overflow ] \ fixnum- define-sub-primitive + +[ + ds-reg 4 SUB + jit-load-vm + jit-load-context + jit-save-context + EBX ds-reg [] MOV + EAX EBX MOV + EBP ds-reg 4 [+] MOV + EBP tag-bits get SAR + EBP IMUL + ds-reg [] EAX MOV + [ JNO ] + [ + EBX tag-bits get SAR + ESP [] EBX MOV + ESP 4 [+] EBP MOV + ESP 8 [+] vm-reg MOV + 0 CALL "overflow_fixnum_multiply" f rc-relative jit-dlsym + ] + jit-conditional +] \ fixnum* define-sub-primitive + << "vocab:cpu/x86/bootstrap.factor" parse-file suffix! >> call diff --git a/basis/cpu/x86/64/64-tests.factor b/basis/cpu/x86/64/64-tests.factor new file mode 100644 index 0000000000..6d171af7ea --- /dev/null +++ b/basis/cpu/x86/64/64-tests.factor @@ -0,0 +1,15 @@ +USING: alien alien.c-types cpu.architecture cpu.x86.64 +cpu.x86.assembler cpu.x86.assembler.operands tools.test ; +IN: cpu.x86.64.tests + +: assembly-test-1 ( -- x ) int { } "cdecl" [ RAX 3 MOV ] alien-assembly ; + +[ 3 ] [ assembly-test-1 ] unit-test + +: assembly-test-2 ( a b -- x ) + int { int int } "cdecl" [ + param-reg-0 param-reg-1 ADD + int-regs return-reg param-reg-0 MOV + ] alien-assembly ; + +[ 23 ] [ 17 6 assembly-test-2 ] unit-test diff --git a/basis/cpu/x86/64/64.factor b/basis/cpu/x86/64/64.factor index cbc5c4d7e5..d3196397c3 100644 --- a/basis/cpu/x86/64/64.factor +++ b/basis/cpu/x86/64/64.factor @@ -1,17 +1,20 @@ -! Copyright (C) 2005, 2009 Slava Pestov. +! Copyright (C) 2005, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors arrays kernel math namespaces make sequences system -layouts alien alien.c-types alien.accessors slots +USING: accessors arrays kernel math namespaces make sequences +system layouts alien alien.c-types alien.accessors slots splitting assocs combinators locals compiler.constants -compiler.codegen compiler.codegen.fixup compiler.cfg.instructions -compiler.cfg.builder compiler.cfg.intrinsics compiler.cfg.stack-frame -cpu.x86.assembler cpu.x86.assembler.operands cpu.x86 cpu.architecture ; +compiler.codegen compiler.codegen.fixup +compiler.cfg.instructions compiler.cfg.builder +compiler.cfg.intrinsics compiler.cfg.stack-frame +cpu.x86.assembler cpu.x86.assembler.operands cpu.x86 +cpu.architecture vm ; +FROM: layouts => cell cells ; IN: cpu.x86.64 -: param-reg-1 ( -- reg ) int-regs param-regs first ; inline -: param-reg-2 ( -- reg ) int-regs param-regs second ; inline -: param-reg-3 ( -- reg ) int-regs param-regs third ; inline -: param-reg-4 ( -- reg ) int-regs param-regs fourth ; inline +: param-reg-0 ( -- reg ) 0 int-regs param-reg ; inline +: param-reg-1 ( -- reg ) 1 int-regs param-reg ; inline +: param-reg-2 ( -- reg ) 2 int-regs param-reg ; inline +: param-reg-3 ( -- reg ) 3 int-regs param-reg ; inline M: x86.64 pic-tail-reg RBX ; @@ -21,18 +24,27 @@ M: float-regs return-reg drop XMM0 ; M: x86.64 ds-reg R14 ; M: x86.64 rs-reg R15 ; M: x86.64 stack-reg RSP ; +M: x86.64 frame-reg RBP ; M: x86.64 extra-stack-space drop 0 ; M: x86.64 machine-registers { - { int-regs { RAX RCX RDX RBX RBP RSI RDI R8 R9 R10 R11 R12 R13 } } + { int-regs { RAX RCX RDX RBX RBP RSI RDI R8 R9 R10 R11 R12 } } { float-regs { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 XMM9 XMM10 XMM11 XMM12 XMM13 XMM14 XMM15 } } } ; +: vm-reg ( -- reg ) R13 ; inline + +M: x86.64 %mov-vm-ptr ( reg -- ) + vm-reg MOV ; + +M: x86.64 %vm-field-ptr ( dst field -- ) + [ vm-reg ] dip vm-field-offset [+] LEA ; + : param@ ( n -- op ) reserved-stack-space + stack@ ; M: x86.64 %prologue ( n -- ) @@ -56,9 +68,9 @@ M: x86.64 %mark-deck [+] card-mark MOV ; M:: x86.64 %dispatch ( src temp -- ) - building get length :> start ! Load jump table base. temp HEX: ffffffff MOV + building get length :> start 0 rc-absolute-cell rel-here ! Add jump table base temp src ADD @@ -66,7 +78,7 @@ M:: x86.64 %dispatch ( src temp -- ) building get length :> end ! Fix up the displacement above cell code-alignment - [ end start - 2 - + building get dup pop* push ] + [ end start - + building get dup pop* push ] [ align-code ] bi ; @@ -77,9 +89,9 @@ M: stack-params copy-register* { [ over integer? ] [ R11 swap MOV param@ R11 MOV ] } } cond ; -M: x86 %save-param-reg [ param@ ] 2dip %copy ; +M: x86.64 %save-param-reg [ param@ ] 2dip %copy ; -M: x86 %load-param-reg [ swap param@ ] dip %copy ; +M: x86.64 %load-param-reg [ swap param@ ] dip %copy ; : with-return-regs ( quot -- ) [ @@ -88,11 +100,17 @@ M: x86 %load-param-reg [ swap param@ ] dip %copy ; call ] with-scope ; inline -M: x86.64 %prepare-unbox ( n -- ) - param-reg-1 swap ds-reg reg-stack MOV ; +M: x86.64 %pop-stack ( n -- ) + param-reg-0 swap ds-reg reg-stack MOV ; + +M: x86.64 %pop-context-stack ( -- ) + temp-reg %load-context-datastack + param-reg-0 temp-reg [] MOV + param-reg-0 param-reg-0 [] MOV + temp-reg [] bootstrap-cell SUB ; M:: x86.64 %unbox ( n rep func -- ) - param-reg-2 %mov-vm-ptr + param-reg-1 %mov-vm-ptr ! Call the unboxer func f %alien-invoke ! Store the return value on the C stack if this is an @@ -104,15 +122,15 @@ M: x86.64 %unbox-long-long ( n func -- ) [ int-rep ] dip %unbox ; : %unbox-struct-field ( c-type i -- ) - ! Alien must be in param-reg-1. + ! Alien must be in param-reg-0. R11 swap cells [+] swap rep>> reg-class-of { { int-regs [ int-regs get pop swap MOV ] } { float-regs [ float-regs get pop swap MOVSD ] } } case ; M: x86.64 %unbox-small-struct ( c-type -- ) - ! Alien must be in param-reg-1. - param-reg-2 %mov-vm-ptr + ! Alien must be in param-reg-0. + param-reg-1 %mov-vm-ptr "alien_offset" f %alien-invoke ! Move alien_offset() return value to R11 so that we don't ! clobber it. @@ -122,12 +140,12 @@ M: x86.64 %unbox-small-struct ( c-type -- ) ] with-return-regs ; M:: x86.64 %unbox-large-struct ( n c-type -- ) - ! Source is in param-reg-1 - ! Load destination address into param-reg-2 - param-reg-2 n param@ LEA - ! Load structure size into param-reg-3 - param-reg-3 c-type heap-size MOV - param-reg-4 %mov-vm-ptr + ! Source is in param-reg-0 + ! Load destination address into param-reg-1 + param-reg-1 n param@ LEA + ! Load structure size into param-reg-2 + param-reg-2 c-type heap-size MOV + param-reg-3 %mov-vm-ptr ! Copy the struct to the C stack "to_value_struct" f %alien-invoke ; @@ -145,7 +163,7 @@ M:: x86.64 %box ( n rep func -- ) ] [ rep load-return-value ] if - rep int-rep? [ param-reg-2 ] [ param-reg-1 ] if %mov-vm-ptr + rep int-rep? [ param-reg-1 ] [ param-reg-0 ] if %mov-vm-ptr func f %alien-invoke ; M: x86.64 %box-long-long ( n func -- ) @@ -163,11 +181,11 @@ M: x86.64 %box-small-struct ( c-type -- ) #! Box a <= 16-byte struct. [ [ flatten-value-type [ %box-struct-field ] each-index ] - [ param-reg-3 swap heap-size MOV ] bi - param-reg-1 0 box-struct-field@ MOV - param-reg-2 1 box-struct-field@ MOV - param-reg-4 %mov-vm-ptr - "box_small_struct" f %alien-invoke + [ param-reg-2 swap heap-size MOV ] bi + param-reg-0 0 box-struct-field@ MOV + param-reg-1 1 box-struct-field@ MOV + param-reg-3 %mov-vm-ptr + "from_small_struct" f %alien-invoke ] with-return-regs ; : struct-return@ ( n -- operand ) @@ -175,12 +193,12 @@ M: x86.64 %box-small-struct ( c-type -- ) M: x86.64 %box-large-struct ( n c-type -- ) ! Struct size is parameter 2 - param-reg-2 swap heap-size MOV + param-reg-1 swap heap-size MOV ! Compute destination address - param-reg-1 swap struct-return@ LEA - param-reg-3 %mov-vm-ptr + param-reg-0 swap struct-return@ LEA + param-reg-2 %mov-vm-ptr ! Copy the struct from the C stack - "box_value_struct" f %alien-invoke ; + "from_value_struct" f %alien-invoke ; M: x86.64 %prepare-box-struct ( -- ) ! Compute target address for value struct return @@ -196,37 +214,38 @@ M: x86.64 %alien-invoke R11 CALL ; M: x86.64 %nest-stacks ( -- ) - ! Save current frame. See comment in vm/contexts.hpp - param-reg-1 stack-reg stack-frame get total-size>> 3 cells - [+] LEA - param-reg-2 %mov-vm-ptr + param-reg-0 %mov-vm-ptr "nest_stacks" f %alien-invoke ; M: x86.64 %unnest-stacks ( -- ) - param-reg-1 %mov-vm-ptr + param-reg-0 %mov-vm-ptr "unnest_stacks" f %alien-invoke ; M: x86.64 %prepare-alien-indirect ( -- ) + param-reg-0 ds-reg [] MOV + ds-reg 8 SUB param-reg-1 %mov-vm-ptr - "unbox_alien" f %alien-invoke + "pinned_alien_offset" f %alien-invoke RBP RAX MOV ; M: x86.64 %alien-indirect ( -- ) RBP CALL ; M: x86.64 %alien-callback ( quot -- ) - param-reg-1 swap %load-reference - param-reg-2 %mov-vm-ptr - "c_to_factor" f %alien-invoke ; + param-reg-0 param-reg-1 %restore-context + param-reg-0 swap %load-reference + param-reg-0 quot-entry-point-offset [+] CALL + param-reg-0 param-reg-1 %save-context ; M: x86.64 %callback-value ( ctype -- ) - 0 %prepare-unbox + %pop-context-stack RSP 8 SUB - param-reg-1 PUSH - param-reg-1 %mov-vm-ptr + param-reg-0 PUSH + param-reg-0 %mov-vm-ptr ! Restore data/call/retain stacks "unnest_stacks" f %alien-invoke - ! Put former top of data stack in param-reg-1 - param-reg-1 POP + ! Put former top of data stack in param-reg-0 + param-reg-0 POP RSP 8 ADD ! Unbox former top of data stack to return registers unbox-return ; @@ -252,11 +271,11 @@ M:: x86.64 %binary-float-function ( dst src1 src2 func -- ) M:: x86.64 %call-gc ( gc-root-count temp -- ) ! Pass pointer to start of GC roots as first parameter - param-reg-1 gc-root-base param@ LEA + param-reg-0 gc-root-base param@ LEA ! Pass number of roots as second parameter - param-reg-2 gc-root-count MOV + param-reg-1 gc-root-count MOV ! Pass VM ptr as third parameter - param-reg-3 %mov-vm-ptr + param-reg-2 %mov-vm-ptr ! Call GC "inline_gc" f %alien-invoke ; diff --git a/basis/cpu/x86/64/bootstrap.factor b/basis/cpu/x86/64/bootstrap.factor index 0fc029fdfe..828598074f 100644 --- a/basis/cpu/x86/64/bootstrap.factor +++ b/basis/cpu/x86/64/bootstrap.factor @@ -1,8 +1,9 @@ -! Copyright (C) 2007, 2009 Slava Pestov. +! Copyright (C) 2007, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: bootstrap.image.private kernel namespaces system -layouts vocabs parser compiler.constants math -cpu.x86.assembler cpu.x86.assembler.operands sequences ; +USING: bootstrap.image.private kernel kernel.private namespaces +system layouts vocabs parser compiler.constants math +math.private cpu.x86.assembler cpu.x86.assembler.operands +sequences generic.single.private ; IN: bootstrap.x86 8 \ cell set @@ -14,26 +15,193 @@ IN: bootstrap.x86 : temp1 ( -- reg ) RSI ; : temp2 ( -- reg ) RDX ; : temp3 ( -- reg ) RBX ; +: return-reg ( -- reg ) RAX ; : safe-reg ( -- reg ) RAX ; : stack-reg ( -- reg ) RSP ; +: frame-reg ( -- reg ) RBP ; +: ctx-reg ( -- reg ) R12 ; +: vm-reg ( -- reg ) R13 ; : ds-reg ( -- reg ) R14 ; : rs-reg ( -- reg ) R15 ; : fixnum>slot@ ( -- ) temp0 1 SAR ; : rex-length ( -- n ) 1 ; [ - ! load stack_chain - temp0 0 MOV rc-absolute-cell rt-stack-chain jit-rel - temp0 temp0 [] MOV - ! save stack pointer - temp0 [] stack-reg MOV - ! load vm ptr - arg1 0 MOV rc-absolute-cell rt-vm jit-rel - ! load XT - temp1 0 MOV rc-absolute-cell rt-primitive jit-rel - ! go - temp1 JMP + ! load entry point + safe-reg 0 MOV rc-absolute-cell rt-this jit-rel + ! save stack frame size + stack-frame-size PUSH + ! push entry point + safe-reg PUSH + ! alignment + RSP stack-frame-size 3 bootstrap-cells - SUB +] jit-prolog jit-define + +: jit-load-context ( -- ) + ctx-reg vm-reg vm-context-offset [+] MOV ; + +: jit-save-context ( -- ) + jit-load-context + safe-reg RSP -8 [+] LEA + ctx-reg context-callstack-top-offset [+] safe-reg MOV + ctx-reg context-datastack-offset [+] ds-reg MOV + ctx-reg context-retainstack-offset [+] rs-reg MOV ; + +: jit-restore-context ( -- ) + jit-load-context + ds-reg ctx-reg context-datastack-offset [+] MOV + rs-reg ctx-reg context-retainstack-offset [+] MOV ; + +[ + jit-save-context + ! call the primitive + arg1 vm-reg MOV + RAX 0 MOV rc-absolute-cell rt-dlsym jit-rel + RAX CALL + jit-restore-context ] jit-primitive jit-define +[ + jit-restore-context + ! save ctx->callstack_bottom + safe-reg stack-reg stack-frame-size 8 - [+] LEA + ctx-reg context-callstack-bottom-offset [+] safe-reg MOV + ! call the quotation + arg1 quot-entry-point-offset [+] CALL + jit-save-context +] \ c-to-factor define-sub-primitive + +[ + arg1 ds-reg [] MOV + ds-reg bootstrap-cell SUB +] +[ arg1 quot-entry-point-offset [+] CALL ] +[ arg1 quot-entry-point-offset [+] JMP ] +\ (call) define-combinator-primitive + +[ + ! Clear x87 stack, but preserve rounding mode and exception flags + RSP 2 SUB + RSP [] FNSTCW + FNINIT + RSP [] FLDCW + + ! Unwind stack frames + RSP arg2 MOV + + ! Load VM pointer into vm-reg, since we're entering from + ! C code + vm-reg 0 MOV 0 rc-absolute-cell jit-vm + + ! Load ds and rs registers + jit-restore-context + + ! Call quotation + arg1 quot-entry-point-offset [+] JMP +] \ unwind-native-frames define-sub-primitive + +[ + ! Load callstack object + arg4 ds-reg [] MOV + ds-reg bootstrap-cell SUB + ! Get ctx->callstack_bottom + jit-load-context + arg1 ctx-reg context-callstack-bottom-offset [+] MOV + ! Get top of callstack object -- 'src' for memcpy + arg2 arg4 callstack-top-offset [+] LEA + ! Get callstack length, in bytes --- 'len' for memcpy + arg3 arg4 callstack-length-offset [+] MOV + arg3 tag-bits get SHR + ! Compute new stack pointer -- 'dst' for memcpy + arg1 arg3 SUB + ! Install new stack pointer + RSP arg1 MOV + ! Call memcpy; arguments are now in the correct registers + ! Create register shadow area for Win64 + RSP 32 SUB + safe-reg 0 MOV "factor_memcpy" f rc-absolute-cell jit-dlsym + safe-reg CALL + ! Tear down register shadow area + RSP 32 ADD + ! Return with new callstack + 0 RET +] \ set-callstack define-sub-primitive + +[ + jit-save-context + arg2 vm-reg MOV + safe-reg 0 MOV "lazy_jit_compile" f rc-absolute-cell jit-dlsym + safe-reg CALL +] +[ return-reg quot-entry-point-offset [+] CALL ] +[ return-reg quot-entry-point-offset [+] JMP ] +\ lazy-jit-compile define-combinator-primitive + +! Inline cache miss entry points +: jit-load-return-address ( -- ) + RBX RSP stack-frame-size bootstrap-cell - [+] MOV ; + +! These are always in tail position with an existing stack +! frame, and the stack. The frame setup takes this into account. +: jit-inline-cache-miss ( -- ) + jit-save-context + arg1 RBX MOV + arg2 vm-reg MOV + RAX 0 MOV "inline_cache_miss" f rc-absolute-cell jit-dlsym + RAX CALL + jit-restore-context ; + +[ jit-load-return-address jit-inline-cache-miss ] +[ RAX CALL ] +[ RAX JMP ] +\ inline-cache-miss define-combinator-primitive + +[ jit-inline-cache-miss ] +[ RAX CALL ] +[ RAX JMP ] +\ inline-cache-miss-tail define-combinator-primitive + +! Overflowing fixnum arithmetic +: jit-overflow ( insn func -- ) + ds-reg 8 SUB + jit-save-context + arg1 ds-reg [] MOV + arg2 ds-reg 8 [+] MOV + arg3 arg1 MOV + [ [ arg3 arg2 ] dip call ] dip + ds-reg [] arg3 MOV + [ JNO ] + [ + arg3 vm-reg MOV + RAX 0 MOV f rc-absolute-cell jit-dlsym + RAX CALL + ] + jit-conditional ; inline + +[ [ ADD ] "overflow_fixnum_add" jit-overflow ] \ fixnum+ define-sub-primitive + +[ [ SUB ] "overflow_fixnum_subtract" jit-overflow ] \ fixnum- define-sub-primitive + +[ + ds-reg 8 SUB + jit-save-context + RCX ds-reg [] MOV + RBX ds-reg 8 [+] MOV + RBX tag-bits get SAR + RAX RCX MOV + RBX IMUL + ds-reg [] RAX MOV + [ JNO ] + [ + arg1 RCX MOV + arg1 tag-bits get SAR + arg2 RBX MOV + arg3 vm-reg MOV + RAX 0 MOV "overflow_fixnum_multiply" f rc-absolute-cell jit-dlsym + RAX CALL + ] + jit-conditional +] \ fixnum* define-sub-primitive + << "vocab:cpu/x86/bootstrap.factor" parse-file suffix! >> call diff --git a/basis/cpu/x86/64/unix/bootstrap.factor b/basis/cpu/x86/64/unix/bootstrap.factor index 238fad984a..d19b5306a0 100644 --- a/basis/cpu/x86/64/unix/bootstrap.factor +++ b/basis/cpu/x86/64/unix/bootstrap.factor @@ -6,8 +6,11 @@ sequences system vocabs ; IN: bootstrap.x86 : stack-frame-size ( -- n ) 4 bootstrap-cells ; +: nv-regs ( -- seq ) { RBX R12 R13 R14 R15 } ; : arg1 ( -- reg ) RDI ; : arg2 ( -- reg ) RSI ; +: arg3 ( -- reg ) RDX ; +: arg4 ( -- reg ) RCX ; << "vocab:cpu/x86/64/bootstrap.factor" parse-file suffix! >> call diff --git a/basis/cpu/x86/64/winnt/bootstrap.factor b/basis/cpu/x86/64/winnt/bootstrap.factor index 2e3944fcaf..113a13918f 100644 --- a/basis/cpu/x86/64/winnt/bootstrap.factor +++ b/basis/cpu/x86/64/winnt/bootstrap.factor @@ -1,13 +1,16 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: bootstrap.image.private kernel namespaces system -layouts vocabs parser sequences cpu.x86.assembler parser +USING: bootstrap.image.private kernel namespaces system layouts +vocabs sequences cpu.x86.assembler parser cpu.x86.assembler.operands ; IN: bootstrap.x86 : stack-frame-size ( -- n ) 8 bootstrap-cells ; +: nv-regs ( -- seq ) { RBX RSI RDI R12 R13 R14 R15 } ; : arg1 ( -- reg ) RCX ; : arg2 ( -- reg ) RDX ; +: arg3 ( -- reg ) R8 ; +: arg4 ( -- reg ) R9 ; << "vocab:cpu/x86/64/bootstrap.factor" parse-file suffix! >> call diff --git a/basis/cpu/x86/assembler/assembler.factor b/basis/cpu/x86/assembler/assembler.factor index 57738ce4ba..b075b121a5 100644 --- a/basis/cpu/x86/assembler/assembler.factor +++ b/basis/cpu/x86/assembler/assembler.factor @@ -375,6 +375,7 @@ PRIVATE> : NOP ( -- ) HEX: 90 , ; : PAUSE ( -- ) HEX: f3 , HEX: 90 , ; +: RDTSC ( -- ) HEX: 0f , HEX: 31 , ; : RDPMC ( -- ) HEX: 0f , HEX: 33 , ; ! x87 Floating Point Unit @@ -385,6 +386,13 @@ PRIVATE> : FLDS ( operand -- ) { BIN: 000 f HEX: d9 } 1-operand ; : FLDL ( operand -- ) { BIN: 000 f HEX: dd } 1-operand ; +: FNSTCW ( operand -- ) { BIN: 111 f HEX: d9 } 1-operand ; +: FNSTSW ( operand -- ) { BIN: 111 f HEX: dd } 1-operand ; +: FLDCW ( operand -- ) { BIN: 101 f HEX: d9 } 1-operand ; + +: FNCLEX ( -- ) HEX: db , HEX: e2 , ; +: FNINIT ( -- ) HEX: db , HEX: e3 , ; + ! SSE multimedia instructions [ POP ] each + + frame-reg POP + + ! Callbacks which return structs, or use stdcall, need a + ! parameter here. See the comment in callback-return-rewind + ! in cpu.x86.32 + HEX: ffff RET rc-absolute-2 rt-untagged jit-rel +] callback-stub jit-define + [ ! Load word - temp0 0 MOV rc-absolute-cell rt-immediate jit-rel + temp0 0 MOV rc-absolute-cell rt-literal jit-rel ! Bump profiling counter temp0 profile-count-offset [+] 1 tag-fixnum ADD ! Load word->code temp0 temp0 word-code-offset [+] MOV - ! Compute word XT + ! Compute word entry point temp0 compiled-header-size ADD - ! Jump to XT + ! Jump to entry point temp0 JMP ] jit-profiling jit-define -[ - ! load XT - temp0 0 MOV rc-absolute-cell rt-this jit-rel - ! save stack frame size - stack-frame-size PUSH - ! push XT - temp0 PUSH - ! alignment - stack-reg stack-frame-size 3 bootstrap-cells - SUB -] jit-prolog jit-define - [ ! load literal - temp0 0 MOV rc-absolute-cell rt-immediate jit-rel + temp0 0 MOV rc-absolute-cell rt-literal jit-rel ! increment datastack pointer ds-reg bootstrap-cell ADD ! store literal on datastack ds-reg [] temp0 MOV -] jit-push-immediate jit-define +] jit-push jit-define [ temp3 0 MOV rc-absolute-cell rt-here jit-rel - 0 JMP rc-relative rt-xt-pic-tail jit-rel + 0 JMP rc-relative rt-entry-point-pic-tail jit-rel ] jit-word-jump jit-define [ - 0 CALL rc-relative rt-xt-pic jit-rel + 0 CALL rc-relative rt-entry-point-pic jit-rel ] jit-word-call jit-define -[ - 0 JMP rc-relative rt-xt jit-rel -] jit-word-special jit-define - [ ! load boolean temp0 ds-reg [] MOV @@ -62,9 +93,9 @@ big-endian off ! compare boolean with f temp0 \ f type-number CMP ! jump to true branch if not equal - 0 JNE rc-relative rt-xt jit-rel + 0 JNE rc-relative rt-entry-point jit-rel ! jump to false branch if equal - 0 JMP rc-relative rt-xt jit-rel + 0 JMP rc-relative rt-entry-point jit-rel ] jit-if jit-define : jit->r ( -- ) @@ -117,36 +148,39 @@ big-endian off [ jit->r - 0 CALL rc-relative rt-xt jit-rel + 0 CALL rc-relative rt-entry-point jit-rel jit-r> ] jit-dip jit-define [ jit-2>r - 0 CALL rc-relative rt-xt jit-rel + 0 CALL rc-relative rt-entry-point jit-rel jit-2r> ] jit-2dip jit-define [ jit-3>r - 0 CALL rc-relative rt-xt jit-rel + 0 CALL rc-relative rt-entry-point jit-rel jit-3r> ] jit-3dip jit-define -: prepare-(execute) ( -- operand ) +[ ! load from stack temp0 ds-reg [] MOV ! pop stack ds-reg bootstrap-cell SUB - ! execute word - temp0 word-xt-offset [+] ; - -[ prepare-(execute) JMP ] jit-execute-jump jit-define - -[ prepare-(execute) CALL ] jit-execute-call jit-define +] +[ temp0 word-entry-point-offset [+] CALL ] +[ temp0 word-entry-point-offset [+] JMP ] +\ (execute) define-combinator-primitive + +[ + temp0 ds-reg [] MOV + ds-reg bootstrap-cell SUB + temp0 word-entry-point-offset [+] JMP +] jit-execute jit-define [ - ! unwind stack frame stack-reg stack-frame-size bootstrap-cell - ADD ] jit-epilog jit-define @@ -176,26 +210,27 @@ big-endian off temp0 temp1 MOV load-tag temp1 tuple type-number tag-fixnum CMP - [ temp1 temp0 tuple type-number neg bootstrap-cell + [+] MOV ] { } make - [ length JNE ] [ % ] bi + [ JNE ] + [ temp1 temp0 tuple type-number neg bootstrap-cell + [+] MOV ] + jit-conditional ] pic-tuple jit-define [ - temp1 HEX: ffffffff CMP rc-absolute rt-immediate jit-rel + temp1 HEX: ffffffff CMP rc-absolute rt-literal jit-rel ] pic-check-tag jit-define [ - temp2 HEX: ffffffff MOV rc-absolute-cell rt-immediate jit-rel + temp2 HEX: ffffffff MOV rc-absolute-cell rt-literal jit-rel temp1 temp2 CMP ] pic-check-tuple jit-define -[ 0 JE rc-relative rt-xt jit-rel ] pic-hit jit-define +[ 0 JE rc-relative rt-entry-point jit-rel ] pic-hit jit-define ! ! ! Megamorphic caches [ ! cache = ... - temp0 0 MOV rc-absolute-cell rt-immediate jit-rel + temp0 0 MOV rc-absolute-cell rt-literal jit-rel ! key = hashcode(class) temp2 temp1 MOV bootstrap-cell 4 = [ temp2 1 SHR ] when @@ -213,29 +248,12 @@ big-endian off temp1 [] 1 ADD ! goto get(cache + bootstrap-cell) temp0 temp0 bootstrap-cell [+] MOV - temp0 word-xt-offset [+] JMP + temp0 word-entry-point-offset [+] JMP ! fall-through on miss ] mega-lookup jit-define -[ - safe-reg 0 MOV rc-absolute-cell rt-xt jit-rel - safe-reg JMP -] callback-stub jit-define - ! ! ! Sub-primitives -! Quotations and words -[ - ! load from stack - arg1 ds-reg [] MOV - ! pop stack - ds-reg bootstrap-cell SUB - ! pass vm pointer - arg2 0 MOV 0 jit-literal rc-absolute-cell rt-vm jit-rel - ! call quotation - arg1 quot-xt-offset [+] JMP -] \ (call) define-sub-primitive - ! Objects [ ! load from stack @@ -335,15 +353,6 @@ big-endian off ds-reg [] temp0 MOV ] \ dupd define-sub-primitive -[ - temp0 ds-reg [] MOV - temp1 ds-reg -1 bootstrap-cells [+] MOV - ds-reg bootstrap-cell ADD - ds-reg [] temp0 MOV - ds-reg -1 bootstrap-cells [+] temp1 MOV - ds-reg -2 bootstrap-cells [+] temp0 MOV -] \ tuck define-sub-primitive - [ temp0 ds-reg [] MOV temp1 ds-reg bootstrap-cell neg [+] MOV @@ -382,7 +391,7 @@ big-endian off : jit-compare ( insn -- ) ! load t t jit-literal - temp3 0 MOV rc-absolute-cell rt-immediate jit-rel + temp3 0 MOV rc-absolute-cell rt-literal jit-rel ! load f temp1 \ f type-number MOV ! load first value diff --git a/basis/cpu/x86/features/features.factor b/basis/cpu/x86/features/features.factor index b21aa762d8..30b2ce3b57 100644 --- a/basis/cpu/x86/features/features.factor +++ b/basis/cpu/x86/features/features.factor @@ -1,23 +1,80 @@ -! Copyright (C) 2009 Slava Pestov. +! Copyright (C) 2009, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: system kernel memoize math math.order math.parser -namespaces alien.c-types alien.syntax combinators locals init io -compiler compiler.units accessors ; +USING: accessors alien alien.c-types combinators compiler +compiler.codegen.fixup compiler.units cpu.architecture +cpu.x86.assembler cpu.x86.assembler.operands init io kernel +locals math math.order math.parser memoize namespaces system ; IN: cpu.x86.features MEMO: sse-version ( -- n ) - sse_version - "sse-version" get string>number [ min ] when* ; + (sse-version) "sse-version" get string>number [ min ] when* ; -[ \ sse-version reset-memoized ] "cpu.x86.features" add-init-hook +[ \ sse-version reset-memoized ] "cpu.x86.features" add-startup-hook : sse? ( -- ? ) sse-version 10 >= ; : sse2? ( -- ? ) sse-version 20 >= ; @@ -39,7 +96,18 @@ MEMO: sse-version ( -- n ) HOOK: instruction-count cpu ( -- n ) -M: x86 instruction-count read_timestamp_counter ; +M: x86.32 instruction-count + longlong { } "cdecl" [ + RDTSC + ] alien-assembly ; + +M: x86.64 instruction-count + longlong { } "cdecl" [ + RAX 0 MOV + RDTSC + RDX 32 SHL + RAX RDX OR + ] alien-assembly ; : count-instructions ( quot -- n ) - instruction-count [ call ] dip instruction-count swap - ; inline + instruction-count [ call instruction-count ] dip - ; inline diff --git a/basis/cpu/x86/x86.factor b/basis/cpu/x86/x86.factor index a63b92e050..f2751b1be2 100644 --- a/basis/cpu/x86/x86.factor +++ b/basis/cpu/x86/x86.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2005, 2009 Slava Pestov. +! Copyright (C) 2005, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs alien alien.c-types arrays strings cpu.x86.assembler cpu.x86.assembler.private cpu.x86.assembler.operands @@ -24,6 +24,8 @@ M: x86 vector-regs float-regs ; HOOK: stack-reg cpu ( -- reg ) +HOOK: frame-reg cpu ( -- reg ) + HOOK: reserved-stack-space cpu ( -- n ) HOOK: extra-stack-space cpu ( stack-frame -- n ) @@ -84,7 +86,7 @@ M: x86 %call ( word -- ) 0 CALL rc-relative rel-word-pic ; : xt-tail-pic-offset ( -- n ) #! See the comment in vm/cpu-x86.hpp - cell 4 + 1 + ; inline + 4 1 + ; inline M: x86 %jump ( word -- ) pic-tail-reg 0 MOV xt-tail-pic-offset rc-absolute-cell rel-here @@ -417,11 +419,7 @@ M: x86 %shl int-rep two-operand [ SHL ] emit-shift ; M: x86 %shr int-rep two-operand [ SHR ] emit-shift ; M: x86 %sar int-rep two-operand [ SAR ] emit-shift ; -: %mov-vm-ptr ( reg -- ) - 0 MOV 0 rc-absolute-cell rel-vm ; - -M: x86 %vm-field-ptr ( dst field -- ) - [ 0 MOV ] dip vm-field-offset rc-absolute-cell rel-vm ; +HOOK: %mov-vm-ptr cpu ( reg -- ) : load-allot-ptr ( nursery-ptr allot-ptr -- ) [ drop "nursery" %vm-field-ptr ] [ swap [] MOV ] 2bi ; @@ -430,7 +428,7 @@ M: x86 %vm-field-ptr ( dst field -- ) [ [] ] dip data-alignment get align ADD ; : store-header ( temp class -- ) - [ [] ] [ type-number tag-fixnum ] bi* MOV ; + [ [] ] [ type-number tag-header ] bi* MOV ; : store-tagged ( dst tag -- ) type-number OR ; @@ -472,6 +470,23 @@ M: x86 %load-gc-root ( gc-root register -- ) swap gc-root@ MOV ; M: x86 %alien-global ( dst symbol library -- ) [ 0 MOV ] 2dip rc-absolute-cell rel-dlsym ; +M: x86 %push-stack ( -- ) + ds-reg cell ADD + ds-reg [] int-regs return-reg MOV ; + +:: %load-context-datastack ( dst -- ) + ! Load context struct + dst "ctx" %vm-field-ptr + dst dst [] MOV + ! Load context datastack pointer + dst "datastack" context-field-offset ADD ; + +M: x86 %push-context-stack ( -- ) + temp-reg %load-context-datastack + temp-reg [] bootstrap-cell ADD + temp-reg temp-reg [] MOV + temp-reg [] int-regs return-reg MOV ; + M: x86 %epilogue ( n -- ) cell - incr-stack-reg ; :: %boolean ( dst temp word -- ) @@ -649,45 +664,8 @@ M: x86 %fill-vector-reps { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } } } available-reps ; -! M:: x86 %broadcast-vector ( dst src rep -- ) -! rep unsign-rep { -! { float-4-rep [ -! dst src float-4-rep %copy -! dst dst { 0 0 0 0 } SHUFPS -! ] } -! { double-2-rep [ -! dst src MOVDDUP -! ] } -! { longlong-2-rep [ -! dst src = -! [ dst dst PUNPCKLQDQ ] -! [ dst src { 0 1 0 1 } PSHUFD ] -! if -! ] } -! { int-4-rep [ -! dst src { 0 0 0 0 } PSHUFD -! ] } -! { short-8-rep [ -! dst src { 0 0 0 0 } PSHUFLW -! dst dst PUNPCKLQDQ -! ] } -! { char-16-rep [ -! dst src char-16-rep %copy -! dst dst PUNPCKLBW -! dst dst { 0 0 0 0 } PSHUFLW -! dst dst PUNPCKLQDQ -! ] } -! } case ; -! -! M: x86 %broadcast-vector-reps -! { -! ! Can't do this with sse1 since it will want to unbox -! ! a double-precision float and convert to single precision -! { sse2? { float-4-rep double-2-rep longlong-2-rep ulonglong-2-rep int-4-rep uint-4-rep short-8-rep ushort-8-rep char-16-rep uchar-16-rep } } -! } available-reps ; - M:: x86 %gather-vector-4 ( dst src1 src2 src3 src4 rep -- ) - rep unsign-rep { + rep signed-rep { { float-4-rep [ dst src1 float-4-rep %copy dst src2 UNPCKLPS @@ -710,7 +688,7 @@ M: x86 %gather-vector-4-reps } available-reps ; M:: x86 %gather-vector-2 ( dst src1 src2 rep -- ) - rep unsign-rep { + rep signed-rep { { double-2-rep [ dst src1 double-2-rep %copy dst src2 MOVLHPS @@ -763,7 +741,7 @@ M: x86 %gather-vector-2-reps M:: x86 %shuffle-vector-imm ( dst src shuffle rep -- ) dst src rep %copy - dst shuffle rep unsign-rep { + dst shuffle rep signed-rep { { double-2-rep [ >float-4-shuffle float-4-shuffle ] } { float-4-rep [ float-4-shuffle ] } { int-4-rep [ int-4-shuffle ] } @@ -786,7 +764,7 @@ M: x86 %shuffle-vector-reps M: x86 %merge-vector-head [ two-operand ] keep - unsign-rep { + signed-rep { { double-2-rep [ MOVLHPS ] } { float-4-rep [ UNPCKLPS ] } { longlong-2-rep [ PUNPCKLQDQ ] } @@ -797,7 +775,7 @@ M: x86 %merge-vector-head M: x86 %merge-vector-tail [ two-operand ] keep - unsign-rep { + signed-rep { { double-2-rep [ UNPCKHPD ] } { float-4-rep [ UNPCKHPS ] } { longlong-2-rep [ PUNPCKHQDQ ] } @@ -826,7 +804,7 @@ M: x86 %signed-pack-vector-reps M: x86 %unsigned-pack-vector [ two-operand ] keep - unsign-rep { + signed-rep { { int-4-rep [ PACKUSDW ] } { short-8-rep [ PACKUSWB ] } } case ; @@ -883,6 +861,7 @@ M: x86 %float>integer-vector-reps : (%compare-float-vector) ( dst src rep double single -- ) [ double-2-rep eq? ] 2dip if ; inline + : %compare-float-vector ( dst src rep cc -- ) { { cc< [ [ CMPLTPD ] [ CMPLTPS ] (%compare-float-vector) ] } @@ -896,13 +875,14 @@ M: x86 %float>integer-vector-reps } case ; :: (%compare-int-vector) ( dst src rep int64 int32 int16 int8 -- ) - rep unsign-rep :> rep' + rep signed-rep :> rep' dst src rep' { { longlong-2-rep [ int64 call ] } { int-4-rep [ int32 call ] } { short-8-rep [ int16 call ] } { char-16-rep [ int8 call ] } } case ; inline + : %compare-int-vector ( dst src rep cc -- ) { { cc= [ [ PCMPEQQ ] [ PCMPEQD ] [ PCMPEQW ] [ PCMPEQB ] (%compare-int-vector) ] } @@ -921,6 +901,7 @@ M: x86 %compare-vector ( dst src1 src2 rep cc -- ) { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep } } { sse4.1? { longlong-2-rep ulonglong-2-rep } } } available-reps ; + : %compare-vector-ord-reps ( -- reps ) { { sse? { float-4-rep } } @@ -1106,6 +1087,32 @@ M: x86 %mul-vector-reps { sse4.1? { int-4-rep uint-4-rep } } } available-reps ; +M: x86 %mul-high-vector ( dst src1 src2 rep -- ) + [ two-operand ] keep + { + { short-8-rep [ PMULHW ] } + { ushort-8-rep [ PMULHUW ] } + } case ; + +M: x86 %mul-high-vector-reps + { + { sse2? { short-8-rep ushort-8-rep } } + } available-reps ; + +M: x86 %mul-horizontal-add-vector ( dst src1 src2 rep -- ) + [ two-operand ] keep + { + { char-16-rep [ PMADDUBSW ] } + { uchar-16-rep [ PMADDUBSW ] } + { short-8-rep [ PMADDWD ] } + } case ; + +M: x86 %mul-horizontal-add-vector-reps + { + { sse2? { short-8-rep } } + { ssse3? { char-16-rep uchar-16-rep } } + } available-reps ; + M: x86 %div-vector ( dst src1 src2 rep -- ) [ two-operand ] keep { @@ -1159,37 +1166,54 @@ M: x86 %max-vector-reps { sse4.1? { char-16-rep ushort-8-rep int-4-rep uint-4-rep } } } available-reps ; +M: x86 %avg-vector ( dst src1 src2 rep -- ) + [ two-operand ] keep + { + { uchar-16-rep [ PAVGB ] } + { ushort-8-rep [ PAVGW ] } + } case ; + +M: x86 %avg-vector-reps + { + { sse2? { uchar-16-rep ushort-8-rep } } + } available-reps ; + M: x86 %dot-vector [ two-operand ] keep { - { float-4-rep [ - sse4.1? - [ HEX: ff DPPS ] - [ [ MULPS ] [ drop dup float-4-rep %horizontal-add-vector ] 2bi ] - if - ] } - { double-2-rep [ - sse4.1? - [ HEX: ff DPPD ] - [ [ MULPD ] [ drop dup double-2-rep %horizontal-add-vector ] 2bi ] - if - ] } + { float-4-rep [ HEX: ff DPPS ] } + { double-2-rep [ HEX: ff DPPD ] } } case ; M: x86 %dot-vector-reps { - { sse3? { float-4-rep double-2-rep } } + { sse4.1? { float-4-rep double-2-rep } } } available-reps ; -M: x86 %horizontal-add-vector ( dst src rep -- ) +M: x86 %sad-vector + [ two-operand ] keep { - { float-4-rep [ [ float-4-rep %copy ] [ HADDPS ] [ HADDPS ] 2tri ] } - { double-2-rep [ [ double-2-rep %copy ] [ HADDPD ] 2bi ] } + { uchar-16-rep [ PSADBW ] } + } case ; + +M: x86 %sad-vector-reps + { + { sse2? { uchar-16-rep } } + } available-reps ; + +M: x86 %horizontal-add-vector ( dst src1 src2 rep -- ) + [ two-operand ] keep + signed-rep { + { float-4-rep [ HADDPS ] } + { double-2-rep [ HADDPD ] } + { int-4-rep [ PHADDD ] } + { short-8-rep [ PHADDW ] } } case ; M: x86 %horizontal-add-vector-reps { { sse3? { float-4-rep double-2-rep } } + { ssse3? { int-4-rep uint-4-rep short-8-rep ushort-8-rep } } } available-reps ; M: x86 %horizontal-shl-vector-imm ( dst src1 src2 rep -- ) @@ -1197,7 +1221,7 @@ M: x86 %horizontal-shl-vector-imm ( dst src1 src2 rep -- ) M: x86 %horizontal-shl-vector-imm-reps { - { sse2? { char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } } + { sse2? { char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep float-4-rep double-2-rep } } } available-reps ; M: x86 %horizontal-shr-vector-imm ( dst src1 src2 rep -- ) @@ -1205,7 +1229,7 @@ M: x86 %horizontal-shr-vector-imm ( dst src1 src2 rep -- ) M: x86 %horizontal-shr-vector-imm-reps { - { sse2? { char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } } + { sse2? { char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep float-4-rep double-2-rep } } } available-reps ; M: x86 %abs-vector ( dst src rep -- ) @@ -1329,7 +1353,7 @@ M: x86 %shr-vector-imm-reps %shr-vector-reps ; M: x86 %integer>scalar drop MOVD ; -M:: x86 %scalar>integer ( dst src rep -- ) +:: %scalar>integer-32 ( dst src rep -- ) rep { { int-scalar-rep [ dst 32-bit-version-of src MOVD @@ -1365,6 +1389,15 @@ M:: x86 %scalar>integer ( dst src rep -- ) ] } } case ; +M: x86.32 %scalar>integer ( dst src rep -- ) %scalar>integer-32 ; + +M: x86.64 %scalar>integer ( dst src rep -- ) + { + { longlong-scalar-rep [ MOVD ] } + { ulonglong-scalar-rep [ MOVD ] } + [ %scalar>integer-32 ] + } case ; + M: x86 %vector>scalar %copy ; M: x86 %scalar>vector %copy ; @@ -1373,18 +1406,26 @@ M:: x86 %reload ( dst rep src -- ) dst src rep %copy ; M: x86 %loop-entry 16 code-alignment [ NOP ] times ; -M:: x86 %save-context ( temp1 temp2 callback-allowed? -- ) +M:: x86 %restore-context ( temp1 temp2 -- ) + #! Load Factor stack pointers on entry from C to Factor. + #! Also save callstack bottom! + temp1 "ctx" %vm-field-ptr + temp1 temp1 [] MOV + temp2 stack-reg stack-frame get total-size>> cell - [+] LEA + temp1 "callstack-bottom" context-field-offset [+] temp2 MOV + ds-reg temp1 "datastack" context-field-offset [+] MOV + rs-reg temp1 "retainstack" context-field-offset [+] MOV ; + +M:: x86 %save-context ( temp1 temp2 -- ) #! Save Factor stack pointers in case the C code calls a #! callback which does a GC, which must reliably trace #! all roots. - temp1 "stack_chain" %vm-field-ptr + temp1 "ctx" %vm-field-ptr temp1 temp1 [] MOV temp2 stack-reg cell neg [+] LEA - temp1 [] temp2 MOV - callback-allowed? [ - temp1 2 cells [+] ds-reg MOV - temp1 3 cells [+] rs-reg MOV - ] when ; + temp1 "callstack-top" context-field-offset [+] temp2 MOV + temp1 "datastack" context-field-offset [+] ds-reg MOV + temp1 "retainstack" context-field-offset [+] rs-reg MOV ; M: x86 value-struct? drop t ; @@ -1399,9 +1440,8 @@ M: x86 immediate-bitwise? ( n -- ? ) #! input values to callbacks; the callback has its own #! stack frame set up, and we want to read the frame #! set up by the caller. - stack-frame get total-size>> + stack@ ; + frame-reg swap 2 cells + [+] ; -enable-simd enable-min/max enable-fixnum-log2 @@ -1413,7 +1453,7 @@ enable-fixnum-log2 flush 1 exit ] when - ] "cpu.x86" add-init-hook ; + ] "cpu.x86" add-startup-hook ; : enable-sse2 ( version -- ) 20 >= [ @@ -1425,6 +1465,6 @@ enable-fixnum-log2 ] when ; : check-sse ( -- ) - [ { sse_version } compile ] with-optimizer + [ { (sse-version) } compile ] with-optimizer "Checking for multimedia extensions: " write sse-version [ sse-string write " detected" print ] [ enable-sse2 ] bi ; diff --git a/basis/csv/csv-tests.factor b/basis/csv/csv-tests.factor index 6ba8e2d5b8..829637b4aa 100644 --- a/basis/csv/csv-tests.factor +++ b/basis/csv/csv-tests.factor @@ -70,11 +70,12 @@ IN: csv.tests "can write csv too!" [ "foo1,bar1\nfoo2,bar2\n" ] -[ { { "foo1" "bar1" } { "foo2" "bar2" } } tuck write-csv >string ] named-unit-test +[ { { "foo1" "bar1" } { "foo2" "bar2" } } [ write-csv ] keep >string ] named-unit-test + "escapes quotes commas and newlines when writing" [ "\"fo\"\"o1\",bar1\n\"fo\no2\",\"b,ar2\"\n" ] -[ { { "fo\"o1" "bar1" } { "fo\no2" "b,ar2" } } tuck write-csv >string ] named-unit-test ! " +[ { { "fo\"o1" "bar1" } { "fo\no2" "b,ar2" } } [ write-csv ] keep >string ] named-unit-test ! " [ { { "writing" "some" "csv" "tests" } } ] [ diff --git a/basis/csv/csv.factor b/basis/csv/csv.factor old mode 100755 new mode 100644 diff --git a/basis/db/db.factor b/basis/db/db.factor index bd523b38e6..f26729f8ea 100644 --- a/basis/db/db.factor +++ b/basis/db/db.factor @@ -100,10 +100,10 @@ M: object execute-statement* ( statement type -- ) t >>bound? drop ; : sql-row ( result-set -- seq ) - dup #columns [ row-column ] with map ; + dup #columns [ row-column ] with { } map-integers ; : sql-row-typed ( result-set -- seq ) - dup #columns [ row-column-typed ] with map ; + dup #columns [ row-column-typed ] with { } map-integers ; : query-each ( statement quot: ( statement -- ) -- ) over more-rows? [ diff --git a/basis/db/queries/queries.factor b/basis/db/queries/queries.factor old mode 100755 new mode 100644 index e9aa01feb4..3ff93f49c6 --- a/basis/db/queries/queries.factor +++ b/basis/db/queries/queries.factor @@ -34,7 +34,7 @@ SINGLETON: retryable ] 2map >>bind-params ; M: retryable execute-statement* ( statement type -- ) - drop [ retries>> ] [ + drop [ retries>> iota ] [ [ nip [ query-results dispose t ] diff --git a/basis/db/sqlite/lib/lib.factor b/basis/db/sqlite/lib/lib.factor index 163026f5ff..53034d148a 100644 --- a/basis/db/sqlite/lib/lib.factor +++ b/basis/db/sqlite/lib/lib.factor @@ -32,14 +32,14 @@ ERROR: sqlite-sql-error < sql-error n string ; : sqlite-open ( path -- db ) normalize-path - "void*" + void* [ sqlite3_open sqlite-check-result ] keep *void* ; : sqlite-close ( db -- ) sqlite3_close sqlite-check-result ; : sqlite-prepare ( db sql -- handle ) - utf8 encode dup length "void*" "void*" + utf8 encode dup length void* void* [ sqlite3_prepare_v2 sqlite-check-result ] 2keep drop *void* ; diff --git a/basis/db/sqlite/sqlite.factor b/basis/db/sqlite/sqlite.factor old mode 100755 new mode 100644 index ffcbec70d0..8d26d3b098 --- a/basis/db/sqlite/sqlite.factor +++ b/basis/db/sqlite/sqlite.factor @@ -4,7 +4,7 @@ USING: alien arrays assocs classes compiler db hashtables io.files kernel math math.parser namespaces prettyprint fry sequences strings classes.tuple alien.c-types continuations db.sqlite.lib db.sqlite.ffi db.tuples words db.types combinators -math.intervals io nmake accessors vectors math.ranges random +math.intervals io locals nmake accessors vectors math.ranges random math.bitwise db.queries destructors db.tuples.private interpolate io.streams.string make db.private sequences.deep db.errors.sqlite ; @@ -85,12 +85,11 @@ M: literal-bind sqlite-bind-conversion ( tuple literal-bind -- array ) nip [ key>> ] [ value>> ] [ type>> ] tri ; -M: generator-bind sqlite-bind-conversion ( tuple generate-bind -- array ) - tuck - [ generator-singleton>> eval-generator tuck ] [ slot-name>> ] bi - rot set-slot-named - [ [ key>> ] [ type>> ] bi ] dip - swap ; +M:: generator-bind sqlite-bind-conversion ( tuple generate-bind -- array ) + generate-bind generator-singleton>> eval-generator :> obj + generate-bind slot-name>> :> name + obj name tuple set-slot-named + generate-bind key>> obj generate-bind type>> ; M: sqlite-statement bind-tuple ( tuple statement -- ) [ diff --git a/basis/db/tester/tester.factor b/basis/db/tester/tester.factor index 19140259bf..d0ea6cbcf1 100644 --- a/basis/db/tester/tester.factor +++ b/basis/db/tester/tester.factor @@ -67,7 +67,7 @@ test-2 "TEST2" { test-2 ensure-table ] with-db ] [ - 10 [ + 10 iota [ drop 10 [ dup [ @@ -85,7 +85,7 @@ test-2 "TEST2" { ] with-db ] [ [ - 10 [ + 10 iota [ 10 [ test-1-tuple insert-tuple yield ] times diff --git a/basis/db/types/types.factor b/basis/db/types/types.factor old mode 100755 new mode 100644 diff --git a/basis/debugger/debugger-docs.factor b/basis/debugger/debugger-docs.factor index 87e70d69e7..4bcd9c5b78 100644 --- a/basis/debugger/debugger-docs.factor +++ b/basis/debugger/debugger-docs.factor @@ -129,9 +129,6 @@ HELP: c-string-error. HELP: ffi-error. { $error-description "Thrown by " { $link dlopen } " and " { $link dlsym } " if a problem occurs while loading a native library or looking up a symbol. See " { $link "alien" } "." } ; -HELP: heap-scan-error. -{ $error-description "Thrown if " { $link next-object } " is called outside of a " { $link begin-scan } "/" { $link end-scan } " pair." } ; - HELP: undefined-symbol-error. { $error-description "Thrown if a previously-compiled " { $link alien-invoke } " call refers to a native library symbol which no longer exists." } ; diff --git a/basis/debugger/debugger.factor b/basis/debugger/debugger.factor index 690e631e81..5c76216c4f 100644 --- a/basis/debugger/debugger.factor +++ b/basis/debugger/debugger.factor @@ -26,6 +26,9 @@ M: object error. short. ; M: string error. print ; +: traceback-link. ( continuation -- ) + "[" write [ "Traceback" ] dip write-object "]" print ; + : :s ( -- ) error-continuation get data>> stack. ; @@ -103,9 +106,6 @@ HOOK: signal-error. os ( obj -- ) : ffi-error. ( obj -- ) "FFI error" print drop ; -: heap-scan-error. ( obj -- ) - "Cannot do next-object outside begin/end-scan" print drop ; - : undefined-symbol-error. ( obj -- ) "The image refers to a library or symbol that was not found at load time" print drop ; @@ -148,14 +148,13 @@ PREDICATE: vm-error < array { 6 [ array-size-error. ] } { 7 [ c-string-error. ] } { 8 [ ffi-error. ] } - { 9 [ heap-scan-error. ] } - { 10 [ undefined-symbol-error. ] } - { 11 [ datastack-underflow. ] } - { 12 [ datastack-overflow. ] } - { 13 [ retainstack-underflow. ] } - { 14 [ retainstack-overflow. ] } - { 15 [ memory-error. ] } - { 16 [ fp-trap-error. ] } + { 9 [ undefined-symbol-error. ] } + { 10 [ datastack-underflow. ] } + { 11 [ datastack-overflow. ] } + { 12 [ retainstack-underflow. ] } + { 13 [ retainstack-overflow. ] } + { 14 [ memory-error. ] } + { 15 [ fp-trap-error. ] } } ; inline M: vm-error summary drop "VM error" ; @@ -334,6 +333,8 @@ M: not-found-in-roots summary drop "Cannot resolve vocab: path" ; M: wrong-values summary drop "Quotation called with wrong stack effect" ; +M: stack-effect-omits-dashes summary drop "Stack effect must contain “--â€" ; + { { [ os windows? ] [ "debugger.windows" require ] } { [ os unix? ] [ "debugger.unix" require ] } diff --git a/basis/windows/dinput/constants/tags.txt b/basis/debugger/windows/tags.txt similarity index 100% rename from basis/windows/dinput/constants/tags.txt rename to basis/debugger/windows/tags.txt diff --git a/basis/debugger/windows/windows.factor b/basis/debugger/windows/windows.factor old mode 100755 new mode 100644 index 319f100e16..73c6b0e795 --- a/basis/debugger/windows/windows.factor +++ b/basis/debugger/windows/windows.factor @@ -32,6 +32,7 @@ CONSTANT: seh-names { $ STATUS_CONTROL_C_EXIT "STATUS_CONTROL_C_EXIT" } { $ STATUS_FLOAT_MULTIPLE_FAULTS "STATUS_FLOAT_MULTIPLE_FAULTS" } { $ STATUS_FLOAT_MULTIPLE_TRAPS "STATUS_FLOAT_MULTIPLE_TRAPS" } + { HEX: e06d7363 "Visual C++ exception" } } : seh-name. ( n -- ) diff --git a/basis/dlists/dlists-docs.factor b/basis/dlists/dlists-docs.factor old mode 100755 new mode 100644 diff --git a/basis/dlists/dlists-tests.factor b/basis/dlists/dlists-tests.factor old mode 100755 new mode 100644 diff --git a/basis/dlists/dlists.factor b/basis/dlists/dlists.factor old mode 100755 new mode 100644 diff --git a/basis/editors/editors.factor b/basis/editors/editors.factor index feb19af040..7e16c1c218 100644 --- a/basis/editors/editors.factor +++ b/basis/editors/editors.factor @@ -49,7 +49,7 @@ M: cannot-find-source error. : edit-error ( error -- ) [ error-file ] [ error-line ] bi - 2dup and [ edit-location ] [ 2drop ] if ; + over [ 1 or edit-location ] [ 2drop ] if ; : :edit ( -- ) error get edit-error ; diff --git a/basis/editors/emacs/windows/windows.factor b/basis/editors/emacs/windows/windows.factor old mode 100755 new mode 100644 diff --git a/basis/editors/etexteditor/etexteditor.factor b/basis/editors/etexteditor/etexteditor.factor old mode 100755 new mode 100644 diff --git a/basis/editors/notepad/notepad.factor b/basis/editors/notepad/notepad.factor old mode 100755 new mode 100644 diff --git a/basis/endian/endian-tests.factor b/basis/endian/endian-tests.factor old mode 100755 new mode 100644 diff --git a/basis/endian/endian.factor b/basis/endian/endian.factor old mode 100755 new mode 100644 diff --git a/basis/environment/environment.factor b/basis/environment/environment.factor index e60a52c995..ccdbd66d96 100644 --- a/basis/environment/environment.factor +++ b/basis/environment/environment.factor @@ -32,4 +32,4 @@ HOOK: (set-os-envs) os ( seq -- ) os windows? ";" ":" ? split [ add-vocab-root ] each ] when* -] "environment" add-init-hook +] "environment" add-startup-hook diff --git a/basis/environment/winnt/winnt.factor b/basis/environment/winnt/winnt.factor old mode 100755 new mode 100644 diff --git a/basis/farkup/farkup-tests.factor b/basis/farkup/farkup-tests.factor index 863dc522b2..7ef62bfb77 100644 --- a/basis/farkup/farkup-tests.factor +++ b/basis/farkup/farkup-tests.factor @@ -205,7 +205,7 @@ link-no-follow? off 100 [ drop random-markup [ convert-farkup drop t ] [ drop print f ] recover - ] all? + ] all-integers? ] unit-test [ "

http://foo.com/~foo

" ] [ "[[http://foo.com/~foo]]" convert-farkup ] unit-test diff --git a/basis/fry/fry-docs.factor b/basis/fry/fry-docs.factor index 9602933785..b3d2ff296e 100644 --- a/basis/fry/fry-docs.factor +++ b/basis/fry/fry-docs.factor @@ -2,17 +2,20 @@ USING: help.markup help.syntax quotations kernel ; IN: fry HELP: _ -{ $description "Fry specifier. Inserts a literal value into the fried quotation." } ; +{ $description "Fry specifier. Inserts a literal value into the fried quotation." } +{ $examples "See " { $link "fry.examples" } "." } ; HELP: @ -{ $description "Fry specifier. Splices a quotation into the fried quotation." } ; +{ $description "Fry specifier. Splices a quotation into the fried quotation." } +{ $examples "See " { $link "fry.examples" } "." } ; HELP: fry { $values { "quot" quotation } { "quot'" quotation } } { $description "Outputs a quotation that when called, fries " { $snippet "quot" } " by taking values from the stack and substituting them in." } { $notes "This word is used to implement " { $link POSTPONE: '[ } "; the following two lines are equivalent:" { $code "[ X ] fry call" "'[ X ]" } -} ; +} +{ $examples "See " { $link "fry.examples" } "." } ; HELP: '[ { $syntax "'[ code... ]" } @@ -59,7 +62,6 @@ $nl { { $link literalize } { $snippet ": literalize '[ _ ] ;" } } { { $link curry } { $snippet ": curry '[ _ @ ] ;" } } { { $link compose } { $snippet ": compose '[ @ @ ] ;" } } - { { $link bi@ } { $snippet ": bi@ tuck '[ _ @ _ @ ] call ;" } } } ; ARTICLE: "fry.philosophy" "Fried quotation philosophy" diff --git a/basis/fry/fry-tests.factor b/basis/fry/fry-tests.factor index 549db25e09..b341c462be 100644 --- a/basis/fry/fry-tests.factor +++ b/basis/fry/fry-tests.factor @@ -1,18 +1,43 @@ +! (c)2009 Slava Pestov, Eduardo Cavazos, Joe Groff bsd license USING: fry tools.test math prettyprint kernel io arrays sequences eval accessors ; IN: fry.tests +SYMBOLS: a b c d e f g h ; + +[ [ ] ] [ '[ ] ] unit-test +[ [ + ] ] [ '[ + ] ] unit-test +[ [ 1 ] ] [ 1 '[ _ ] ] unit-test +[ [ 1 ] ] [ [ 1 ] '[ @ ] ] unit-test +[ [ 1 2 ] ] [ [ 1 ] [ 2 ] '[ @ @ ] ] unit-test + +[ [ 1 2 a ] ] [ 1 2 '[ _ _ a ] ] unit-test +[ [ 1 2 ] ] [ 1 2 '[ _ _ ] ] unit-test +[ [ a 1 2 ] ] [ 1 2 '[ a _ _ ] ] unit-test +[ [ 1 2 a ] ] [ [ 1 ] [ 2 ] '[ @ @ a ] ] unit-test +[ [ 1 a 2 b ] ] [ 1 2 '[ _ a _ b ] ] unit-test +[ [ 1 a 2 b ] ] [ 1 [ 2 ] '[ _ a @ b ] ] unit-test +[ [ a 1 b ] ] [ 1 '[ a _ b ] ] unit-test + +[ [ a 1 b ] ] [ [ 1 ] '[ a @ b ] ] unit-test +[ [ a 1 2 ] ] [ [ 1 ] [ 2 ] '[ a @ @ ] ] unit-test + +[ [ a [ 1 ] b ] ] [ 1 '[ a [ _ ] b ] ] unit-test +[ [ a 1 b [ c 2 d ] e 3 f ] ] [ 1 2 3 '[ a _ b [ c _ d ] e _ f ] ] unit-test +[ [ a 1 b [ c 2 d [ e 3 f ] ] g 4 h ] ] [ 1 2 3 4 '[ a _ b [ c _ d [ e _ f ] ] g _ h ] ] unit-test +[ [ a 1 b [ [ c 2 d ] e 3 f ] g 4 h ] ] [ 1 2 3 4 '[ a _ b [ [ c _ d ] e _ f ] g _ h ] ] unit-test + [ [ 3 + ] ] [ 3 '[ _ + ] ] unit-test [ [ 1 3 + ] ] [ 1 3 '[ _ _ + ] ] unit-test -[ [ 1 [ + ] call ] ] [ 1 [ + ] '[ _ @ ] ] unit-test +[ [ 1 + ] ] [ 1 [ + ] '[ _ @ ] ] unit-test -[ [ 1 [ + ] call . ] ] [ 1 [ + ] '[ _ @ . ] ] unit-test +[ [ 1 + . ] ] [ 1 [ + ] '[ _ @ . ] ] unit-test -[ [ [ + ] [ - ] [ call ] dip call ] ] [ [ + ] [ - ] '[ @ @ ] ] unit-test +[ [ + - ] ] [ [ + ] [ - ] '[ @ @ ] ] unit-test -[ [ "a" "b" [ write ] dip print ] ] +[ [ "a" write "b" print ] ] [ "a" "b" '[ _ write _ print ] ] unit-test [ 1/2 ] [ @@ -39,7 +64,7 @@ IN: fry.tests [ "hi" 3 ] [ "h" "i" 3 [ append ] funny-dip ] unit-test [ { 1 2 3 } ] [ - 3 1 '[ _ [ _ + ] map ] call + 3 1 '[ _ iota [ _ + ] map ] call ] unit-test [ { 1 { 2 { 3 } } } ] [ diff --git a/basis/fry/fry.factor b/basis/fry/fry.factor index 184c6247a6..e58253692f 100644 --- a/basis/fry/fry.factor +++ b/basis/fry/fry.factor @@ -1,7 +1,6 @@ -! Copyright (C) 2008 Slava Pestov, Eduardo Cavazos. -! See http://factorcode.org/license.txt for BSD license. -USING: kernel sequences combinators parser splitting math -quotations arrays make words locals.backend summary sets ; +! (c)2009 Slava Pestov, Eduardo Cavazos, Joe Groff bsd license +USING: accessors combinators kernel locals.backend math parser +quotations sequences sets splitting words ; IN: fry : _ ( -- * ) "Only valid inside a fry" throw ; @@ -9,21 +8,10 @@ IN: fry ERROR: >r/r>-in-fry-error ; +GENERIC: fry ( quot -- quot' ) + ] - } case ; - -M: >r/r>-in-fry-error summary - drop - "Explicit retain stack manipulation is not permitted in fried quotations" ; - : check-fry ( quot -- quot ) dup { load-local load-locals get-local drop-locals } intersect [ >r/r>-in-fry-error ] unless-empty ; @@ -36,21 +24,124 @@ M: callable count-inputs [ count-inputs ] map-sum ; M: fry-specifier count-inputs drop 1 ; M: object count-inputs drop 0 ; -GENERIC: deep-fry ( obj -- ) +MIXIN: fried +PREDICATE: fried-callable < callable + count-inputs 0 > ; +INSTANCE: fried-callable fried -: shallow-fry ( quot -- quot' curry# ) - check-fry - [ [ deep-fry ] each ] [ ] make - [ dup \ @ = [ drop [ _ call ] ] [ 1array ] if ] map concat - { _ } split [ spread>quot ] [ length 1 - ] bi ; +: (ncurry) ( quot n -- quot ) + { + { 0 [ ] } + { 1 [ \ curry suffix! ] } + { 2 [ \ 2curry suffix! ] } + { 3 [ \ 3curry suffix! ] } + [ [ \ 3curry suffix! ] dip 3 - (ncurry) ] + } case ; + +: wrap-non-callable ( obj -- quot ) + dup callable? [ ] [ [ call ] curry ] if ; inline + +: [ncurry] ( n -- quot ) + [ V{ } clone ] dip (ncurry) >quotation ; + +: [ndip] ( quot n -- quot' ) + { + { 0 [ wrap-non-callable ] } + { 1 [ \ dip [ ] 2sequence ] } + { 2 [ \ 2dip [ ] 2sequence ] } + { 3 [ \ 3dip [ ] 2sequence ] } + [ [ \ 3dip [ ] 2sequence ] dip 3 - [ndip] ] + } case ; + +: (make-curry) ( tail quot -- quot' ) + swap [ncurry] curry [ compose ] compose ; + +: make-compose ( consecutive quot -- consecutive quot' ) + [ + [ [ ] ] + [ [ncurry] ] if-zero + ] [ + [ [ compose ] ] + [ [ compose compose ] curry ] if-empty + ] bi* compose + 0 swap ; + +: make-curry ( consecutive quot -- consecutive' quot' ) + [ 1 + ] dip + [ [ ] ] [ (make-curry) 0 swap ] if-empty ; + +: convert-curry ( consecutive quot -- consecutive' quot' ) + [ [ ] make-curry ] [ + dup first \ @ = + [ rest >quotation make-compose ] + [ >quotation make-curry ] if + ] if-empty ; + +: prune-curries ( seq -- seq' ) + dup [ empty? not ] find + [ [ 1 + tail ] dip but-last prefix ] + [ 2drop { } ] if* ; + +: convert-curries ( seq -- tail seq' ) + unclip-slice [ 0 swap [ convert-curry ] map ] dip + [ prune-curries ] + [ >quotation 1quotation prefix ] if-empty ; + +: mark-composes ( quot -- quot' ) + [ dup \ @ = [ drop [ _ @ ] ] [ 1quotation ] if ] map concat ; inline + +: shallow-fry ( quot -- quot' ) + check-fry mark-composes + { _ } split convert-curries + [ [ [ ] ] [ [ ] (make-curry) but-last ] if-zero ] + [ spread>quot swap [ [ ] (make-curry) compose ] unless-zero ] if-empty ; + +DEFER: dredge-fry + +TUPLE: dredge-fry-state + { in-quot read-only } + { prequot read-only } + { quot read-only } ; + +: ( quot -- dredge-fry ) + V{ } clone V{ } clone dredge-fry-state boa ; inline + +: in-quot-slices ( n i state -- head tail ) + in-quot>> + [ ] + [ [ drop ] 2dip swap 1 + tail-slice ] 3bi ; inline + +: push-head-slice ( head state -- ) + quot>> [ push-all ] [ \ _ swap push ] bi ; inline + +: push-subquot ( tail elt state -- ) + [ fry swap >quotation count-inputs [ndip] ] dip prequot>> push-all ; inline + +: (dredge-fry-subquot) ( n state i elt -- ) + rot { + [ nip in-quot-slices ] ! head tail i elt state + [ [ 2drop swap ] dip push-head-slice ] + [ [ drop ] 2dip push-subquot ] + [ [ 1 + ] [ drop ] [ ] tri* dredge-fry ] + } 3cleave ; inline recursive + +: (dredge-fry-simple) ( n state -- ) + [ in-quot>> swap tail-slice ] [ quot>> ] bi push-all ; inline recursive + +: dredge-fry ( n dredge-fry -- ) + 2dup in-quot>> [ fried? ] find-from + [ (dredge-fry-subquot) ] + [ drop (dredge-fry-simple) ] if* ; inline recursive PRIVATE> -: fry ( quot -- quot' ) shallow-fry [ncurry] swap prefix ; - -M: callable deep-fry - [ count-inputs \ _ % ] [ fry % ] bi ; - -M: object deep-fry , ; +M: callable fry ( quot -- quot' ) + [ [ [ ] ] ] [ + 0 swap + [ dredge-fry ] [ + [ prequot>> >quotation ] + [ quot>> >quotation shallow-fry ] bi append + ] bi + ] if-empty ; SYNTAX: '[ parse-quotation fry append! ; diff --git a/basis/ftp/server/server.factor b/basis/ftp/server/server.factor index 7653a922ea..251a99115e 100644 --- a/basis/ftp/server/server.factor +++ b/basis/ftp/server/server.factor @@ -3,13 +3,13 @@ USING: accessors assocs byte-arrays calendar classes combinators combinators.short-circuit concurrency.promises continuations destructors ftp io io.backend io.directories -io.encodings io.encodings.8-bit io.encodings.binary +io.encodings io.encodings.binary tools.files io.encodings.utf8 io.files io.files.info io.pathnames io.launcher.unix.parser io.servers.connection io.sockets io.streams.duplex io.streams.string io.timeouts kernel make math math.bitwise math.parser namespaces sequences splitting threads unicode.case logging calendar.format -strings io.files.links io.files.types ; +strings io.files.links io.files.types io.encodings.8-bit.latin1 ; IN: ftp.server SYMBOL: server diff --git a/basis/furnace/auth/features/edit-profile/edit-profile.factor b/basis/furnace/auth/features/edit-profile/edit-profile.factor old mode 100755 new mode 100644 diff --git a/basis/furnace/cache/cache.factor b/basis/furnace/cache/cache.factor index fe2840c9eb..51de8c0be6 100644 --- a/basis/furnace/cache/cache.factor +++ b/basis/furnace/cache/cache.factor @@ -22,7 +22,7 @@ server-state f : expire-state ( class -- ) new - -1/0. millis [a,b] >>expires + -1/0. system-micros [a,b] >>expires delete-tuples ; TUPLE: server-state-manager < filter-responder timeout ; @@ -33,4 +33,4 @@ TUPLE: server-state-manager < filter-responder timeout ; 20 minutes >>timeout ; inline : touch-state ( state manager -- ) - timeout>> hence timestamp>millis >>expires drop ; + timeout>> hence timestamp>micros >>expires drop ; diff --git a/basis/furnace/utilities/utilities.factor b/basis/furnace/utilities/utilities.factor old mode 100755 new mode 100644 diff --git a/basis/game/input/dinput/dinput.factor b/basis/game/input/dinput/dinput.factor old mode 100755 new mode 100644 index f03147205f..964b952cb8 --- a/basis/game/input/dinput/dinput.factor +++ b/basis/game/input/dinput/dinput.factor @@ -4,9 +4,10 @@ continuations game.input game.input.dinput.keys-array io.encodings.utf16 io.encodings.utf16n kernel locals math math.bitwise math.rectangles namespaces parser sequences shuffle specialized-arrays ui.backend.windows vectors -windows.com windows.dinput windows.dinput.constants -windows.errors windows.kernel32 windows.messages -windows.ole32 windows.user32 classes.struct alien.data ; +windows.com windows.directx.dinput +windows.directx.dinput.constants .errors windows.kernel32 +windows.messages .ole32 windows.user32 classes.struct +alien.data ; SPECIALIZED-ARRAY: DIDEVICEOBJECTDATA IN: game.input.dinput diff --git a/basis/game/input/dinput/keys-array/keys-array.factor b/basis/game/input/dinput/keys-array/keys-array.factor old mode 100755 new mode 100644 diff --git a/basis/game/input/input-docs.factor b/basis/game/input/input-docs.factor old mode 100755 new mode 100644 diff --git a/basis/game/input/input.factor b/basis/game/input/input.factor old mode 100755 new mode 100644 index 377a89a884..261f19cb9e --- a/basis/game/input/input.factor +++ b/basis/game/input/input.factor @@ -35,7 +35,7 @@ M: f (reset-game-input) ; : reset-game-input ( -- ) (reset-game-input) ; -[ reset-game-input ] "game-input" add-init-hook +[ reset-game-input ] "game-input" add-startup-hook PRIVATE> @@ -75,9 +75,8 @@ SYMBOLS: get-controllers [ product-id = ] with filter ; : find-controller-instance ( product-id instance-id -- controller/f ) get-controllers [ - tuck [ product-id = ] - [ instance-id = ] 2bi* and + [ instance-id = ] bi-curry bi* and ] with with find nip ; TUPLE: keyboard-state keys ; diff --git a/basis/game/input/iokit/iokit.factor b/basis/game/input/iokit/iokit.factor old mode 100755 new mode 100644 index 258f19ed5e..efc586e1ef --- a/basis/game/input/iokit/iokit.factor +++ b/basis/game/input/iokit/iokit.factor @@ -4,7 +4,7 @@ sequences locals combinators.short-circuit threads namespaces assocs arrays combinators hints alien core-foundation.run-loop accessors sequences.private alien.c-types alien.data math parser game.input vectors -bit-arrays ; +bit-arrays unix.types ; IN: game.input.iokit SINGLETON: iokit-game-input-backend diff --git a/basis/generalizations/generalizations-docs.factor b/basis/generalizations/generalizations-docs.factor index e9a709030e..5b869f138e 100644 --- a/basis/generalizations/generalizations-docs.factor +++ b/basis/generalizations/generalizations-docs.factor @@ -212,7 +212,7 @@ HELP: nwith } ; HELP: napply -{ $values { "n" integer } } +{ $values { "quot" quotation } { "n" integer } } { $description "A generalization of " { $link bi@ } " and " { $link tri@ } " that can work for any stack depth." } { $examples @@ -332,18 +332,6 @@ HELP: nappend-as { nappend nappend-as } related-words -HELP: ntuck -{ $values - { "n" integer } -} -{ $description "A generalization of " { $link tuck } " that can work for any stack depth. The top item will be copied and placed " { $snippet "n" } " items down on the stack." } ; - -HELP: nspin -{ $values - { "n" integer } -} -{ $description "A generalization of " { $link spin } " that can work for any stack depth. The top " { $snippet "n" } " items will be reversed in order." } ; - ARTICLE: "sequence-generalizations" "Generalized sequence operations" { $subsections narray @@ -363,8 +351,6 @@ ARTICLE: "shuffle-generalizations" "Generalized shuffle words" -nrot nnip ndrop - ntuck - nspin mnswap nweave } ; diff --git a/basis/generalizations/generalizations-tests.factor b/basis/generalizations/generalizations-tests.factor index c54e35002f..0c35f15714 100644 --- a/basis/generalizations/generalizations-tests.factor +++ b/basis/generalizations/generalizations-tests.factor @@ -26,8 +26,6 @@ IN: generalizations.tests { 0 } [ 0 1 2 3 4 4 ndrop ] unit-test [ [ 1 ] 5 ndip ] must-infer [ 1 2 3 4 ] [ 2 3 4 [ 1 ] 3 ndip ] unit-test -[ 5 nspin ] must-infer -[ 1 5 4 3 2 ] [ 1 2 3 4 5 4 nspin ] unit-test [ 1 2 3 4 5 [ drop drop drop drop drop 2 ] 5 nkeep ] must-infer [ 1 2 3 4 5 2 '[ drop drop drop drop drop _ ] 5 nkeep ] must-infer @@ -66,7 +64,7 @@ IN: generalizations.tests { 3 5 } [ 2 nweave ] must-infer-as [ { 0 1 2 } { 3 5 4 } { 7 8 6 } ] -[ 9 [ ] each { [ 3array ] [ swap 3array ] [ rot 3array ] } 3 nspread ] unit-test +[ 9 [ ] each-integer { [ 3array ] [ swap 3array ] [ rot 3array ] } 3 nspread ] unit-test [ 1 2 3 4 1 2 3 ] [ 1 2 3 4 3 nover ] unit-test diff --git a/basis/generalizations/generalizations.factor b/basis/generalizations/generalizations.factor index 8d6d6f2ac0..6c8a0b5fde 100644 --- a/basis/generalizations/generalizations.factor +++ b/basis/generalizations/generalizations.factor @@ -71,9 +71,6 @@ MACRO: ndrop ( n -- ) MACRO: nnip ( n -- ) '[ [ _ ndrop ] dip ] ; -MACRO: ntuck ( n -- ) - 2 + '[ dup _ -nrot ] ; - MACRO: ndip ( n -- ) [ [ dip ] curry ] n*quot [ call ] compose ; @@ -112,8 +109,8 @@ MACRO: cleave* ( n -- ) [ 1 - [ [ [ keep ] curry ] dip compose ] n*quot [ call ] compose ] if-zero ; -MACRO: napply ( n -- ) - [ [ drop ] ] dip [ '[ tuck _ 2dip call ] ] times ; +: napply ( quot n -- ) + [ dupn ] [ spread* ] bi ; inline : apply-curry ( ...a quot n -- ) [ [curry] ] dip napply ; inline @@ -139,6 +136,3 @@ MACRO: nbi-curry ( n -- ) : nappend ( n -- seq ) narray concat ; inline -MACRO: nspin ( n -- ) - [ [ ] ] swap [ swap [ ] curry compose ] n*quot [ call ] 3append ; - diff --git a/basis/glib/glib.factor b/basis/glib/glib.factor old mode 100755 new mode 100644 diff --git a/basis/grouping/grouping-docs.factor b/basis/grouping/grouping-docs.factor index e1044b0feb..2c2fee1d70 100644 --- a/basis/grouping/grouping-docs.factor +++ b/basis/grouping/grouping-docs.factor @@ -52,7 +52,7 @@ HELP: { $examples { $example "USING: arrays kernel prettyprint sequences grouping ;" - "9 >array 3 reverse! concat >array ." "{ 6 7 8 3 4 5 0 1 2 }" + "9 iota >array 3 reverse! concat >array ." "{ 6 7 8 3 4 5 0 1 2 }" } { $example "USING: kernel prettyprint sequences grouping ;" @@ -67,7 +67,7 @@ HELP: { $examples { $example "USING: arrays kernel prettyprint sequences grouping ;" - "9 >array 3 " + "9 iota >array 3 " "dup [ reverse! drop ] each concat >array ." "{ 2 1 0 5 4 3 8 7 6 }" } diff --git a/basis/half-floats/half-floats.factor b/basis/half-floats/half-floats.factor old mode 100755 new mode 100644 index d0f6a09067..4c84bb81cc --- a/basis/half-floats/half-floats.factor +++ b/basis/half-floats/half-floats.factor @@ -39,6 +39,7 @@ SYMBOL: half [ [ >float half>bits ] 2dip set-alien-unsigned-2 ] >>setter 2 >>size 2 >>align + 2 >>align-first [ >float ] >>unboxer-quot \ half define-primitive-type diff --git a/basis/heaps/heaps-tests.factor b/basis/heaps/heaps-tests.factor index c1985c516f..703cf53080 100644 --- a/basis/heaps/heaps-tests.factor +++ b/basis/heaps/heaps-tests.factor @@ -31,7 +31,7 @@ IN: heaps.tests [ heap-push-all ] keep heap-pop-all ; : random-alist ( n -- alist ) - [ + iota [ drop 32 random-bits dup number>string ] H{ } map>assoc ; @@ -40,16 +40,16 @@ IN: heaps.tests 14 [ [ t ] swap [ 2^ test-heap-sort ] curry unit-test -] each +] each-integer : test-entry-indices ( n -- ? ) random-alist [ heap-push-all ] keep - data>> dup length swap [ index>> ] map sequence= ; + data>> dup length iota swap [ index>> ] map sequence= ; 14 [ [ t ] swap [ 2^ test-entry-indices ] curry unit-test -] each +] each-integer : sort-entries ( entries -- entries' ) [ key>> ] sort-with ; @@ -66,4 +66,4 @@ IN: heaps.tests 11 [ [ t ] swap [ 2^ delete-test sequence= ] curry unit-test -] each +] each-integer diff --git a/basis/help/apropos/apropos.factor b/basis/help/apropos/apropos.factor index 3bcc815191..e77e7bccad 100644 --- a/basis/help/apropos/apropos.factor +++ b/basis/help/apropos/apropos.factor @@ -73,4 +73,4 @@ M: apropos >link ; INSTANCE: apropos topic : apropos ( str -- ) - print-topic ; + print-topic nl ; diff --git a/basis/help/help.factor b/basis/help/help.factor index ddd6ce23fc..6fb87d7a33 100644 --- a/basis/help/help.factor +++ b/basis/help/help.factor @@ -129,7 +129,7 @@ M: word set-article-parent swap "help-parent" set-word-prop ; SYMBOL: help-hook -help-hook [ [ print-topic ] ] initialize +help-hook [ [ print-topic nl ] ] initialize : help ( topic -- ) help-hook get call( topic -- ) ; diff --git a/basis/help/lint/lint.factor b/basis/help/lint/lint.factor old mode 100755 new mode 100644 diff --git a/basis/hints/hints-docs.factor b/basis/hints/hints-docs.factor index 56a2cb9142..46bdc698b7 100644 --- a/basis/hints/hints-docs.factor +++ b/basis/hints/hints-docs.factor @@ -20,7 +20,7 @@ HELP: specialized-def { $description "Outputs the definition of a word after it has been split into specialized branches. This is the definition which will actually be compiled by the compiler." } ; HELP: HINTS: -{ $values { "defspec" "a definition specifier" } { "hints..." "a list of sequences of classes or literals" } } +{ $values { "defspec" "a word or method" } { "hints..." "a list of sequences of classes or literals" } } { $description "Defines specialization hints for a word or a method." $nl "Each sequence in the list will cause a specialized version of the word to be compiled. Classes are tested for using their predicate, and literals are tested using " { $link eq? } "." } @@ -35,8 +35,8 @@ $nl "M: assoc count-occurrences" " swap [ = nip ] curry assoc-filter assoc-size ;" "" - "HINTS: { sequence count-occurrences } { object array } ;" - "HINTS: { assoc count-occurrences } { object hashtable } ;" + "HINTS: M\ sequence count-occurrences { object array } ;" + "HINTS: M\ assoc count-occurrences { object hashtable } ;" } } ; diff --git a/basis/hints/hints.factor b/basis/hints/hints.factor index 1ca5bf1bc5..e4bbb3459e 100644 --- a/basis/hints/hints.factor +++ b/basis/hints/hints.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs byte-arrays byte-vectors classes combinators definitions effects fry generic generic.single @@ -24,7 +24,7 @@ M: object specializer-declaration class ; "specializer" word-prop ; : make-specializer ( specs -- quot ) - dup length + dup length iota [ (picker) 2array ] 2map [ drop object eq? not ] assoc-filter [ [ t ] ] [ diff --git a/basis/http/client/client-docs.factor b/basis/http/client/client-docs.factor index 330db4467b..04077fc2f7 100644 --- a/basis/http/client/client-docs.factor +++ b/basis/http/client/client-docs.factor @@ -1,7 +1,7 @@ USING: http help.markup help.syntax io.pathnames io.streams.string -io.encodings.8-bit io.encodings.binary kernel urls +io.encodings.binary kernel urls urls.encoding byte-arrays strings assocs sequences destructors -http.client.post-data.private ; +http.client.post-data.private io.encodings.8-bit.latin1 ; IN: http.client HELP: download-failed diff --git a/basis/http/client/client.factor b/basis/http/client/client.factor index 016e347e89..482a23aeaa 100644 --- a/basis/http/client/client.factor +++ b/basis/http/client/client.factor @@ -5,7 +5,7 @@ sequences strings splitting calendar continuations accessors vectors math.order hashtables byte-arrays destructors io io.sockets io.streams.string io.files io.timeouts io.pathnames io.encodings io.encodings.string io.encodings.ascii -io.encodings.utf8 io.encodings.8-bit io.encodings.binary io.crlf +io.encodings.utf8 io.encodings.binary io.crlf io.streams.duplex fry ascii urls urls.encoding present locals http http.parsers http.client.post-data ; IN: http.client diff --git a/basis/http/http-docs.factor b/basis/http/http-docs.factor index 0dca26fd32..2de2323394 100644 --- a/basis/http/http-docs.factor +++ b/basis/http/http-docs.factor @@ -103,9 +103,10 @@ HELP: post-data $nl "Instances contain the following slots:" { $table - { { $slot "raw" } { "The raw bytes of the POST data" } } - { { $slot "content" } { "The POST data. This can be in a higher-level form, such as an assoc of POST parameters, a string, or an XML document" } } - { { $slot "content-type" } "A MIME type" } + { { $slot "data" } { "The POST data. This can be in a higher-level form, such as an assoc of POST parameters, a string, or an XML document" } } + { { $slot "params" } { "Parameters passed in the POST request." } } + { { $slot "content-type" } { "A MIME type" } } + { { $slot "content-encoding" } { "Encoding used for the POST data" } } } } ; HELP: set-header diff --git a/basis/http/http-tests.factor b/basis/http/http-tests.factor index 3fe5e84abd..35d01c1014 100644 --- a/basis/http/http-tests.factor +++ b/basis/http/http-tests.factor @@ -2,7 +2,8 @@ USING: http http.server http.client http.client.private tools.test multiline io.streams.string io.encodings.utf8 io.encodings.8-bit io.encodings.binary io.encodings.string io.encodings.ascii kernel arrays splitting sequences assocs io.sockets db db.sqlite -continuations urls hashtables accessors namespaces xml.data ; +continuations urls hashtables accessors namespaces xml.data +io.encodings.8-bit.latin1 ; IN: http.tests [ "text/plain" latin1 ] [ "text/plain" parse-content-type ] unit-test diff --git a/basis/http/http.factor b/basis/http/http.factor old mode 100755 new mode 100644 index 4bcfbeb76d..6f898e949c --- a/basis/http/http.factor +++ b/basis/http/http.factor @@ -5,9 +5,7 @@ sequences splitting sorting sets strings vectors hashtables quotations arrays byte-arrays math.parser calendar calendar.format present urls fry io io.encodings io.encodings.iana io.encodings.binary -io.encodings.8-bit io.crlf ascii -http.parsers -base64 ; +io.crlf ascii io.encodings.8-bit.latin1 http.parsers base64 ; IN: http CONSTANT: max-redirects 10 diff --git a/basis/http/server/server.factor b/basis/http/server/server.factor old mode 100755 new mode 100644 diff --git a/basis/images/bitmap/bitmap.factor b/basis/images/bitmap/bitmap.factor old mode 100755 new mode 100644 diff --git a/basis/images/bitmap/loading/loading.factor b/basis/images/bitmap/loading/loading.factor index 50926666f6..702fd14472 100644 --- a/basis/images/bitmap/loading/loading.factor +++ b/basis/images/bitmap/loading/loading.factor @@ -2,9 +2,9 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors alien.c-types arrays byte-arrays combinators compression.run-length fry grouping images images.loader io -io.binary io.encodings.8-bit io.encodings.binary +io.binary io.encodings.binary io.encodings.string io.streams.limited kernel math math.bitwise -sequences specialized-arrays summary images.bitmap ; +io.encodings.8-bit.latin1 sequences specialized-arrays summary images.bitmap ; QUALIFIED-WITH: bitstreams b SPECIALIZED-ARRAY: ushort IN: images.bitmap.loading diff --git a/basis/images/images.factor b/basis/images/images.factor old mode 100755 new mode 100644 diff --git a/basis/images/jpeg/jpeg.factor b/basis/images/jpeg/jpeg.factor index 4f10808b04..9a67d43e7d 100644 --- a/basis/images/jpeg/jpeg.factor +++ b/basis/images/jpeg/jpeg.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2009 Marc Fauconneau. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays byte-arrays combinators -grouping compression.huffman images +grouping compression.huffman images fry images.processing io io.binary io.encodings.binary io.files io.streams.byte-array kernel locals math math.bitwise math.constants math.functions math.matrices math.order @@ -137,7 +137,7 @@ TUPLE: jpeg-color-info data>> binary [ - read1 [0,b) + read1 iota [ drop read1 jpeg> color-info>> nth clone read1 16 /mod [ >>dc-huff-table ] [ >>ac-huff-table ] bi* @@ -198,7 +198,7 @@ MEMO: yuv>bgr-matrix ( -- m ) { 8 8 } coord-matrix [ { u v } [ wave ] 2map product ] map^2 1 u v [ 0 = [ 2 sqrt / ] when ] bi@ 4 / m*n ; -MEMO: dct-matrix ( -- m ) 64 [0,b) [ 8 /mod dct-vect flatten ] map ; +MEMO: dct-matrix ( -- m ) 64 iota [ 8 /mod dct-vect flatten ] map ; : mb-dim ( component -- dim ) [ h>> ] [ v>> ] bi 2array ; @@ -232,7 +232,7 @@ MEMO: dct-matrix-blas ( -- m ) dct-matrix >float-blas-matrix ; block dup length>> sqrt >fixnum group flip dup matrix-dim coord-matrix flip [ - [ first2 spin nth nth ] + [ '[ _ [ second ] [ first ] bi ] dip nth nth ] [ x,y v+ color-id jpeg-image draw-color ] bi ] with each^2 ; @@ -295,7 +295,7 @@ MEMO: dct-matrix-blas ( -- m ) dct-matrix >float-blas-matrix ; binary [ [ { HEX: FF } read-until - read1 tuck HEX: 00 = and + read1 [ HEX: 00 = and ] keep swap ] [ drop ] produce swap >marker { EOI } assert= diff --git a/basis/images/memory/memory.factor b/basis/images/memory/memory.factor index ccf891d770..883a097511 100644 --- a/basis/images/memory/memory.factor +++ b/basis/images/memory/memory.factor @@ -10,7 +10,7 @@ IN: images.memory b curr :> a curr width tail-slice :> x - x length [0,b) + x length iota filter { { filter-none [ drop ] } { filter-sub [ [| n | n x nth n a nth + 256 wrap n x set-nth ] each ] } @@ -290,6 +290,14 @@ ERROR: invalid-color-type/bit-depth loading-png ; : validate-truecolor-alpha ( loading-png -- loading-png ) { 8 16 } validate-bit-depth ; +: pad-bitmap ( image -- image ) + dup dim>> second 4 divisor? [ + dup [ bytes-per-pixel ] + [ dim>> first * ] + [ dim>> first 4 mod ] tri + '[ _ group [ _ 0 append ] map B{ } concat-as ] change-bitmap + ] unless ; + : loading-png>bitmap ( loading-png -- bytes component-order ) dup color-type>> { { greyscale [ @@ -315,7 +323,7 @@ ERROR: invalid-color-type/bit-depth loading-png ; [ loading-png>bitmap [ >>bitmap ] [ >>component-order ] bi* ] [ [ width>> ] [ height>> ] bi 2array >>dim ] [ png-component >>component-type ] - } cleave ; + } cleave pad-bitmap ; : load-png ( stream -- loading-png ) [ diff --git a/basis/images/processing/processing.factor b/basis/images/processing/processing.factor old mode 100755 new mode 100644 index cd6754550d..b21eb50c62 --- a/basis/images/processing/processing.factor +++ b/basis/images/processing/processing.factor @@ -6,7 +6,7 @@ math.ranges math.vectors sequences sequences.deep fry ; IN: images.processing : coord-matrix ( dim -- m ) - [ [0,b) ] map first2 [ [ 2array ] with map ] curry map ; + [ iota ] map first2 [ [ 2array ] with map ] curry map ; : map^2 ( m quot -- m' ) '[ _ map ] map ; inline : each^2 ( m quot -- m' ) '[ _ each ] each ; inline @@ -16,7 +16,7 @@ IN: images.processing : matrix>image ( m -- image ) over matrix-dim >>dim swap flip flatten - [ 128 * 128 + 0 max 255 min >fixnum ] map + [ 128 * 128 + 0 255 clamp >fixnum ] map >byte-array >>bitmap L >>component-order ubyte-components >>component-type ; :: matrix-zoom ( m f -- m' ) @@ -30,7 +30,7 @@ IN: images.processing :: draw-grey ( value x,y image -- ) x,y image image-offset 3 * { 0 1 2 } [ - + value 128 + >fixnum 0 max 255 min swap image bitmap>> set-nth + + value 128 + >fixnum 0 255 clamp swap image bitmap>> set-nth ] with each ; :: draw-color ( value x,y color-id image -- ) diff --git a/basis/images/tiff/tiff-tests.factor b/basis/images/tiff/tiff-tests.factor old mode 100755 new mode 100644 diff --git a/basis/images/tiff/tiff.factor b/basis/images/tiff/tiff.factor old mode 100755 new mode 100644 diff --git a/basis/inspector/inspector.factor b/basis/inspector/inspector.factor index 82c2487f67..2aa7cd218e 100644 --- a/basis/inspector/inspector.factor +++ b/basis/inspector/inspector.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2005, 2009 Slava Pestov. +! Copyright (C) 2005, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays generic hashtables io kernel assocs math namespaces prettyprint prettyprint.custom prettyprint.sections @@ -23,9 +23,7 @@ GENERIC: add-numbers ( alist -- table' ) M: enum add-numbers ; M: assoc add-numbers - +number-rows+ get [ - dup length [ prefix ] 2map - ] when ; + +number-rows+ get [ [ prefix ] map-index ] when ; TUPLE: slot-name name ; diff --git a/basis/inverse/inverse.factor b/basis/inverse/inverse.factor old mode 100755 new mode 100644 index 1e941afed0..d112e4e6eb --- a/basis/inverse/inverse.factor +++ b/basis/inverse/inverse.factor @@ -68,7 +68,7 @@ UNION: explicit-inverse normal-inverse math-inverse pop-inverse ; : enough? ( stack word -- ? ) dup deferred? [ 2drop f ] [ - [ [ length ] [ 1quotation infer in>> ] bi* >= ] + [ [ length ] [ 1quotation inputs ] bi* >= ] [ 3drop f ] recover ] if ; @@ -141,7 +141,6 @@ MACRO: undo ( quot -- ) [undo] ; \ 2dup [ over =/fail over =/fail ] define-inverse \ 3dup [ pick =/fail pick =/fail pick =/fail ] define-inverse \ pick [ [ pick ] dip =/fail ] define-inverse -\ tuck [ swapd [ =/fail ] keep ] define-inverse \ bi@ 1 [ [undo] '[ _ bi@ ] ] define-pop-inverse \ tri@ 1 [ [undo] '[ _ tri@ ] ] define-pop-inverse @@ -274,10 +273,10 @@ DEFER: __ ] recover ; inline : true-out ( quot effect -- quot' ) - out>> '[ @ _ ndrop t ] ; + out>> length '[ @ _ ndrop t ] ; : false-recover ( effect -- quot ) - in>> [ ndrop f ] curry [ recover-fail ] curry ; + in>> length [ ndrop f ] curry [ recover-fail ] curry ; : [matches?] ( quot -- undoes?-quot ) [undo] dup infer [ true-out ] [ false-recover ] bi curry ; diff --git a/basis/io/backend/unix/macosx/macosx.factor b/basis/io/backend/unix/macosx/macosx.factor index e669875448..0bc2b85b32 100644 --- a/basis/io/backend/unix/macosx/macosx.factor +++ b/basis/io/backend/unix/macosx/macosx.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: io.backend system namespaces io.backend.unix.bsd io.backend.unix.multiplexers io.backend.unix.multiplexers.run-loop ; -IN: io.backend.macosx +IN: io.backend.unix.macosx M: macosx init-io ( -- ) mx set-global ; diff --git a/basis/io/backend/unix/multiplexers/epoll/epoll.factor b/basis/io/backend/unix/multiplexers/epoll/epoll.factor index b9c224c629..6ec8caaad8 100644 --- a/basis/io/backend/unix/multiplexers/epoll/epoll.factor +++ b/basis/io/backend/unix/multiplexers/epoll/epoll.factor @@ -9,10 +9,9 @@ IN: io.backend.unix.multiplexers.epoll TUPLE: epoll-mx < mx events ; -: max-events ( -- n ) - #! We read up to 256 events at a time. This is an arbitrary - #! constant... - 256 ; inline +#! We read up to 256 events at a time. This is an arbitrary +#! constant... +CONSTANT: max-events 256 : ( -- mx ) epoll-mx new-mx @@ -51,8 +50,8 @@ M: epoll-mx remove-output-callbacks ( fd mx -- seq ) [ EPOLLOUT do-epoll-del ] [ call-next-method ] 2bi ] [ 2drop f ] if ; -: wait-event ( mx us -- n ) - [ [ fd>> ] [ events>> ] bi dup length ] [ 1000 /i ] bi* +: wait-event ( mx nanos -- n ) + [ [ fd>> ] [ events>> ] bi dup length ] [ 1000000 /i ] bi* epoll_wait multiplexer-error ; : handle-event ( event mx -- ) @@ -63,5 +62,5 @@ M: epoll-mx remove-output-callbacks ( fd mx -- seq ) : handle-events ( mx n -- ) [ dup events>> ] dip head-slice swap '[ _ handle-event ] each ; -M: epoll-mx wait-for-events ( us mx -- ) +M: epoll-mx wait-for-events ( nanos mx -- ) swap 60000000 or dupd wait-event handle-events ; diff --git a/basis/io/backend/unix/multiplexers/kqueue/kqueue.factor b/basis/io/backend/unix/multiplexers/kqueue/kqueue.factor index c777e57f1d..16d0338da5 100644 --- a/basis/io/backend/unix/multiplexers/kqueue/kqueue.factor +++ b/basis/io/backend/unix/multiplexers/kqueue/kqueue.factor @@ -73,6 +73,6 @@ M: kqueue-mx remove-output-callbacks ( fd mx -- seq ) [ dup events>> ] dip head-slice [ handle-kevent ] with each ; -M: kqueue-mx wait-for-events ( us mx -- ) +M: kqueue-mx wait-for-events ( nanos mx -- ) swap dup [ make-timespec ] when dupd wait-kevent handle-kevents ; diff --git a/basis/io/backend/unix/multiplexers/multiplexers.factor b/basis/io/backend/unix/multiplexers/multiplexers.factor index 73d8a60310..ded028dda4 100644 --- a/basis/io/backend/unix/multiplexers/multiplexers.factor +++ b/basis/io/backend/unix/multiplexers/multiplexers.factor @@ -26,7 +26,7 @@ GENERIC: remove-output-callbacks ( fd mx -- callbacks ) M: mx remove-output-callbacks writes>> delete-at* drop ; -GENERIC: wait-for-events ( ms mx -- ) +GENERIC: wait-for-events ( nanos mx -- ) : input-available ( fd mx -- ) reads>> delete-at* drop [ resume ] each ; diff --git a/basis/io/backend/unix/multiplexers/run-loop/run-loop.factor b/basis/io/backend/unix/multiplexers/run-loop/run-loop.factor index 276949a99f..05328b48dc 100644 --- a/basis/io/backend/unix/multiplexers/run-loop/run-loop.factor +++ b/basis/io/backend/unix/multiplexers/run-loop/run-loop.factor @@ -30,5 +30,5 @@ M: run-loop-mx add-output-callback kqueue-mx>> add-output-callback ; M: run-loop-mx remove-input-callbacks kqueue-mx>> remove-input-callbacks ; M: run-loop-mx remove-output-callbacks kqueue-mx>> remove-output-callbacks ; -M: run-loop-mx wait-for-events ( us mx -- ) +M: run-loop-mx wait-for-events ( nanos mx -- ) swap run-one-iteration [ 0 swap wait-for-events ] [ drop ] if ; diff --git a/basis/io/backend/unix/multiplexers/select/select.factor b/basis/io/backend/unix/multiplexers/select/select.factor index 8022ed34e2..f2d1a3a3b7 100644 --- a/basis/io/backend/unix/multiplexers/select/select.factor +++ b/basis/io/backend/unix/multiplexers/select/select.factor @@ -48,9 +48,9 @@ TUPLE: select-mx < mx read-fdset write-fdset ; [ write-fdset/tasks [ init-fdset ] keep ] tri f ; -M:: select-mx wait-for-events ( us mx -- ) +M:: select-mx wait-for-events ( nanos mx -- ) mx - [ init-fdsets us dup [ make-timeval ] when select multiplexer-error drop ] + [ init-fdsets nanos 1000 /i dup [ make-timeval ] when select multiplexer-error drop ] [ [ read-fdset/tasks ] keep [ input-available ] check-fdset ] [ [ write-fdset/tasks ] keep [ output-available ] check-fdset ] tri ; diff --git a/basis/io/backend/unix/unix.factor b/basis/io/backend/unix/unix.factor index ebb8f1ec05..a8070525c7 100644 --- a/basis/io/backend/unix/unix.factor +++ b/basis/io/backend/unix/unix.factor @@ -5,7 +5,7 @@ kernel.private math io.ports sequences strings sbufs threads unix vectors io.buffers io.backend io.encodings math.parser continuations system libc namespaces make io.timeouts io.encodings.utf8 destructors destructors.private accessors -summary combinators locals unix.time fry +summary combinators locals unix.time unix.types fry io.backend.unix.multiplexers ; QUALIFIED: io IN: io.backend.unix @@ -151,7 +151,7 @@ M: stdin dispose* : wait-for-stdin ( stdin -- n ) [ control>> CHAR: X over io:stream-write1 io:stream-flush ] - [ size>> "ssize_t" heap-size swap io:stream-read *int ] + [ size>> ssize_t heap-size swap io:stream-read *int ] bi ; :: refill-stdin ( buffer stdin size -- ) diff --git a/basis/io/backend/windows/nt/nt.factor b/basis/io/backend/windows/nt/nt.factor old mode 100755 new mode 100644 index 452dc4a409..de29f33ee6 --- a/basis/io/backend/windows/nt/nt.factor +++ b/basis/io/backend/windows/nt/nt.factor @@ -50,21 +50,22 @@ M: winnt add-completion ( win32-handle -- ) } cond ] with-timeout ; -:: wait-for-overlapped ( us -- bytes-transferred overlapped error? ) +:: wait-for-overlapped ( nanos -- bytes-transferred overlapped error? ) master-completion-port get-global - 0 [ ! bytes - f ! key - f [ ! overlapped - us [ 1000 /i ] [ INFINITE ] if* ! timeout - GetQueuedCompletionStatus zero? - ] keep - *void* dup [ OVERLAPPED memory>struct ] when - ] keep *int spin ; + 0 :> bytes + f :> key + f :> overlapped + nanos [ 1,000,000 /i ] [ INFINITE ] if* :> timeout + bytes key overlapped timeout GetQueuedCompletionStatus zero? :> error? + + bytes *int + overlapped *void* dup [ OVERLAPPED memory>struct ] when + error? ; : resume-callback ( result overlapped -- ) >c-ptr pending-overlapped get-global delete-at* drop resume-with ; -: handle-overlapped ( us -- ? ) +: handle-overlapped ( nanos -- ? ) wait-for-overlapped [ [ [ drop GetLastError 1array ] dip resume-callback t @@ -74,7 +75,7 @@ M: winnt add-completion ( win32-handle -- ) M: win32-handle cancel-operation [ check-disposed ] [ handle>> CancelIo drop ] bi ; -M: winnt io-multiplex ( us -- ) +M: winnt io-multiplex ( nanos -- ) handle-overlapped [ 0 io-multiplex ] when ; M: winnt init-io ( -- ) diff --git a/basis/io/backend/windows/nt/privileges/privileges.factor b/basis/io/backend/windows/nt/privileges/privileges.factor old mode 100755 new mode 100644 diff --git a/basis/io/backend/windows/privileges/privileges-tests.factor b/basis/io/backend/windows/privileges/privileges-tests.factor old mode 100755 new mode 100644 diff --git a/basis/io/backend/windows/privileges/privileges.factor b/basis/io/backend/windows/privileges/privileges.factor old mode 100755 new mode 100644 diff --git a/basis/io/backend/windows/windows.factor b/basis/io/backend/windows/windows.factor old mode 100755 new mode 100644 diff --git a/basis/io/buffers/buffers-tests.factor b/basis/io/buffers/buffers-tests.factor index d366df7c54..836b4d0cc8 100644 --- a/basis/io/buffers/buffers-tests.factor +++ b/basis/io/buffers/buffers-tests.factor @@ -8,7 +8,7 @@ strings accessors destructors ; [ length ] dip buffer-reset ; : string>buffer ( string -- buffer ) - dup length tuck buffer-set ; + dup length [ buffer-set ] keep ; : buffer-read-all ( buffer -- byte-array ) [ [ pos>> ] [ ptr>> ] bi ] @@ -58,3 +58,7 @@ strings accessors destructors ; 100 "b" set [ 1000 "b" get n>buffer >string ] must-fail "b" get dispose + +"hello world" string>buffer "b" set +[ "hello" CHAR: \s ] [ " " "b" get buffer-until [ >string ] dip ] unit-test +"b" get dispose diff --git a/basis/io/buffers/buffers.factor b/basis/io/buffers/buffers.factor index f45d3bb062..23358d9a0e 100644 --- a/basis/io/buffers/buffers.factor +++ b/basis/io/buffers/buffers.factor @@ -1,5 +1,5 @@ ! Copyright (C) 2004, 2005 Mackenzie Straight. -! Copyright (C) 2006, 2008 Slava Pestov. +! Copyright (C) 2006, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors alien alien.accessors alien.c-types alien.data alien.syntax kernel libc math sequences byte-arrays @@ -73,7 +73,9 @@ HINTS: >buffer byte-array buffer ; bi ; inline : search-buffer-until ( pos fill ptr separators -- n ) - [ [ swap alien-unsigned-1 ] dip member-eq? ] 2curry find-from drop ; inline + [ iota ] 2dip + [ [ swap alien-unsigned-1 ] dip member-eq? ] 2curry + find-from drop ; inline : finish-buffer-until ( buffer n -- byte-array separator ) [ diff --git a/basis/io/directories/directories.factor b/basis/io/directories/directories.factor old mode 100755 new mode 100644 diff --git a/basis/io/directories/search/search.factor b/basis/io/directories/search/search.factor old mode 100755 new mode 100644 diff --git a/basis/io/directories/windows/windows.factor b/basis/io/directories/windows/windows.factor old mode 100755 new mode 100644 diff --git a/basis/io/encodings/8-bit/8-bit-docs.factor b/basis/io/encodings/8-bit/8-bit-docs.factor index 203d7c187f..b0677e80bd 100644 --- a/basis/io/encodings/8-bit/8-bit-docs.factor +++ b/basis/io/encodings/8-bit/8-bit-docs.factor @@ -5,106 +5,34 @@ strings ; IN: io.encodings.8-bit ARTICLE: "io.encodings.8-bit" "Legacy 8-bit encodings" -"Many encodings are a simple mapping of bytes onto characters. The " { $vocab-link "io.encodings.8-bit" } " vocabulary implements these generically using existing resource files. These encodings should be used with extreme caution, as fully general Unicode encodings like UTF-8 are nearly always more appropriate. The following 8-bit encodings are already defined:" -{ $subsections - latin1 - latin2 - latin3 - latin4 - latin/cyrillic - latin/arabic - latin/greek - latin/hebrew - latin5 - latin6 - latin/thai - latin7 - latin8 - latin9 - latin10 - koi8-r - windows-1252 - ebcdic - mac-roman +"Many encodings are a simple mapping of bytes onto characters. The " { $vocab-link "io.encodings.8-bit" } " vocabulary implements these generically using existing resource files. These encodings should be used with extreme caution, as fully general Unicode encodings like UTF-8 are nearly always more appropriate. The following 8-bit encodings are available:" +{ $list + { $vocab-link "io.encodings.8-bit.ebcdic" } + { $vocab-link "io.encodings.8-bit.latin1" } + { $vocab-link "io.encodings.8-bit.latin2" } + { $vocab-link "io.encodings.8-bit.latin3" } + { $vocab-link "io.encodings.8-bit.latin4" } + { $vocab-link "io.encodings.8-bit.cyrillic" } + { $vocab-link "io.encodings.8-bit.arabic" } + { $vocab-link "io.encodings.8-bit.greek" } + { $vocab-link "io.encodings.8-bit.hebrew" } + { $vocab-link "io.encodings.8-bit.latin5" } + { $vocab-link "io.encodings.8-bit.latin6" } + { $vocab-link "io.encodings.8-bit.thai" } + { $vocab-link "io.encodings.8-bit.latin7" } + { $vocab-link "io.encodings.8-bit.latin8" } + { $vocab-link "io.encodings.8-bit.latin9" } + { $vocab-link "io.encodings.8-bit.koi8-r" } + { $vocab-link "io.encodings.8-bit.mac-roman" } + { $vocab-link "io.encodings.8-bit.windows-1250" } + { $vocab-link "io.encodings.8-bit.windows-1251" } + { $vocab-link "io.encodings.8-bit.windows-1252" } + { $vocab-link "io.encodings.8-bit.windows-1253" } + { $vocab-link "io.encodings.8-bit.windows-1254" } + { $vocab-link "io.encodings.8-bit.windows-1255" } + { $vocab-link "io.encodings.8-bit.windows-1256" } + { $vocab-link "io.encodings.8-bit.windows-1257" } + { $vocab-link "io.encodings.8-bit.windows-1258" } } ; ABOUT: "io.encodings.8-bit" - -HELP: 8-bit -{ $class-description "Describes an 8-bit encoding, including its name (a symbol) and a table used for encoding and decoding." } ; - -HELP: latin1 -{ $description "This is the ISO-8859-1 encoding, also called Latin-1: Western European. It is an 8-bit superset of ASCII which is the default for a mimetype starting with 'text' and provides the characters necessary for most western European languages." } -{ $see-also "encodings-introduction" } ; - -HELP: latin2 -{ $description "This is the ISO-8859-2 encoding, also called Latin-2: Eastern European. It is an 8-bit superset of ASCII and provides the characters necessary for most eastern European languages." } -{ $see-also "encodings-introduction" } ; - -HELP: latin3 -{ $description "This is the ISO-8859-3 encoding, also called Latin-3: South European. It is an 8-bit superset of ASCII and provides the characters necessary for Turkish, Maltese and Esperanto." } -{ $see-also "encodings-introduction" } ; - -HELP: latin4 -{ $description "This is the ISO-8859-4 encoding, also called Latin-4: North European. It is an 8-bit superset of ASCII and provides the characters necessary for Latvian, Lithuanian, Estonian, Greenlandic and Sami." } -{ $see-also "encodings-introduction" } ; - -HELP: latin/cyrillic -{ $description "This is the ISO-8859-5 encoding, also called Latin/Cyrillic. It is an 8-bit superset of ASCII and provides the characters necessary for most languages which use Cyrilic, including Russian, Macedonian, Belarusian, Bulgarian, Serbian, and Ukrainian. KOI8-R is used much more commonly." } -{ $see-also "encodings-introduction" } ; - -HELP: latin/arabic -{ $description "This is the ISO-8859-6 encoding, also called Latin/Arabic. It is an 8-bit superset of ASCII and provides the characters necessary for Arabic, though not other languages which use Arabic script." } -{ $see-also "encodings-introduction" } ; - -HELP: latin/greek -{ $description "This is the ISO-8859-7 encoding, also called Latin/Greek. It is an 8-bit superset of ASCII and provides the characters necessary for Greek written in modern monotonic orthography, or ancient Greek without accent marks." } -{ $see-also "encodings-introduction" } ; - -HELP: latin/hebrew -{ $description "This is the ISO-8859-8 encoding, also called Latin/Hebrew. It is an 8-bit superset of ASCII and provides the characters necessary for modern Hebrew without explicit vowels. Generally, this is interpreted in logical order, making it ISO-8859-8-I, technically." } -{ $see-also "encodings-introduction" } ; - -HELP: latin5 -{ $description "This is the ISO-8859-9 encoding, also called Latin-5: Turkish. It is an 8-bit superset of ASCII and provides the characters necessary for Turkish, similar to Latin-1 but replacing the spots used for Icelandic with characters used in Turkish." } -{ $see-also "encodings-introduction" } ; - -HELP: latin6 -{ $description "This is the ISO-8859-10 encoding, also called Latin-6: Nordic. It is an 8-bit superset of ASCII containing the same characters as Latin-4, but rearranged to be of better use to nordic languages." } -{ $see-also "encodings-introduction" } ; - -HELP: latin/thai -{ $description "This is the ISO-8859-11 encoding, also called Latin/Thai. It is an 8-bit superset of ASCII containing the characters necessary to represent Thai. It is basically identical to TIS-620." } -{ $see-also "encodings-introduction" } ; - -HELP: latin7 -{ $description "This is the ISO-8859-13 encoding, also called Latin-7: Baltic Rim. It is an 8-bit superset of ASCII containing all characters necesary to represent Baltic Rim languages, as previous character sets were incomplete." } -{ $see-also "encodings-introduction" } ; - -HELP: latin8 -{ $description "This is the ISO-8859-14 encoding, also called Latin-8: Celtic. It is an 8-bit superset of ASCII designed for Celtic languages like Gaelic and Breton." } -{ $see-also "encodings-introduction" } ; - -HELP: latin9 -{ $description "This is the ISO-8859-15 encoding, also called Latin-9 and unoffically as Latin-0. It is an 8-bit superset of ASCII designed as a modification of Latin-1, removing little-used characters in favor of the Euro symbol and other characters." } -{ $see-also "encodings-introduction" } ; - -HELP: latin10 -{ $description "This is the ISO-8859-16 encoding, also called Latin-10: South-Eastern European. It is an 8-bit superset of ASCII." } -{ $see-also "encodings-introduction" } ; - -HELP: windows-1252 -{ $description "Windows 1252 is an 8-bit superset of ASCII which is closely related to Latin-1. Control characters in the 0x80 to 0x9F range are replaced with printable characters such as the Euro symbol." } -{ $see-also "encodings-introduction" } ; - -HELP: ebcdic -{ $description "EBCDIC is an 8-bit legacy encoding designed for IBM mainframes like System/360 in the 1960s. It has since fallen into disuse. It contains large unallocated regions, and the version included here (code page 37) contains auxiliary characters in this region for English- and Portugese-speaking countries." } -{ $see-also "encodings-introduction" } ; - -HELP: mac-roman -{ $description "Mac Roman is an 8-bit superset of ASCII which was the standard encoding on Mac OS prior to version 10. It is incompatible with Latin-1 in all but a few places and ASCII, and it is suitable for encoding many Western European languages." } -{ $see-also "encodings-introduction" } ; - -HELP: koi8-r -{ $description "KOI8-R is an 8-bit superset of ASCII which encodes the Cyrillic alphabet, as used in Russian and Bulgarian. Characters are in such an order that, if the eight bit is stripped, text is still interpretable as ASCII. Block-building characters also exist." } -{ $see-also "encodings-introduction" } ; diff --git a/basis/io/encodings/8-bit/8-bit-tests.factor b/basis/io/encodings/8-bit/8-bit-tests.factor index 55b9c44934..5178630f0f 100644 --- a/basis/io/encodings/8-bit/8-bit-tests.factor +++ b/basis/io/encodings/8-bit/8-bit-tests.factor @@ -1,5 +1,6 @@ USING: io.encodings.string io.encodings.8-bit -io.encodings.8-bit.private tools.test strings arrays ; +io.encodings.8-bit.private tools.test strings arrays +io.encodings.8-bit.latin1 io.encodings.8-bit.windows-1252 ; IN: io.encodings.8-bit.tests [ B{ CHAR: f CHAR: o CHAR: o } ] [ "foo" latin1 encode ] unit-test diff --git a/basis/io/encodings/8-bit/8-bit.factor b/basis/io/encodings/8-bit/8-bit.factor index c13bbccd43..7f92028c31 100644 --- a/basis/io/encodings/8-bit/8-bit.factor +++ b/basis/io/encodings/8-bit/8-bit.factor @@ -1,42 +1,19 @@ -! Copyright (C) 2008 Daniel Ehrenberg +! Copyright (C) 2008 Daniel Ehrenberg, Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: math.parser arrays io.encodings sequences kernel assocs hashtables io.encodings.ascii generic parser classes.tuple words words.symbol io io.files splitting namespaces math compiler.units accessors classes.singleton classes.mixin -io.encodings.iana fry simple-flat-file ; +io.encodings.iana fry simple-flat-file lexer ; IN: io.encodings.8-bit 8-bit-encodings get-global at ; : create-encoding ( name -- word ) - "io.encodings.8-bit" create + create-in [ define-singleton-class ] [ 8-bit-encoding add-mixin-instance ] [ ] tri ; +: load-encoding ( name iana-name file-name -- ) + [ create-encoding dup ] + [ register-encoding ] + [ encoding-file flat-file>biassoc 8-bit boa ] tri* + swap 8-bit-encodings get-global set-at ; + PRIVATE> -[ - mappings [ - first3 - [ create-encoding ] - [ dupd register-encoding ] - [ encoding-file flat-file>biassoc 8-bit boa ] - tri* - ] H{ } map>assoc - 8-bit-encodings set-global -] with-compilation-unit +SYNTAX: 8-BIT: scan scan scan load-encoding ; diff --git a/basis/io/encodings/8-bit/CP1251.TXT b/basis/io/encodings/8-bit/CP1251.TXT new file mode 100644 index 0000000000..4d9b3558ac --- /dev/null +++ b/basis/io/encodings/8-bit/CP1251.TXT @@ -0,0 +1,274 @@ +# +# Name: cp1251 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: Shawn.Steele@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1251 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1251 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x0402 #CYRILLIC CAPITAL LETTER DJE +0x81 0x0403 #CYRILLIC CAPITAL LETTER GJE +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0453 #CYRILLIC SMALL LETTER GJE +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x20AC #EURO SIGN +0x89 0x2030 #PER MILLE SIGN +0x8A 0x0409 #CYRILLIC CAPITAL LETTER LJE +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C 0x040A #CYRILLIC CAPITAL LETTER NJE +0x8D 0x040C #CYRILLIC CAPITAL LETTER KJE +0x8E 0x040B #CYRILLIC CAPITAL LETTER TSHE +0x8F 0x040F #CYRILLIC CAPITAL LETTER DZHE +0x90 0x0452 #CYRILLIC SMALL LETTER DJE +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 #UNDEFINED +0x99 0x2122 #TRADE MARK SIGN +0x9A 0x0459 #CYRILLIC SMALL LETTER LJE +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C 0x045A #CYRILLIC SMALL LETTER NJE +0x9D 0x045C #CYRILLIC SMALL LETTER KJE +0x9E 0x045B #CYRILLIC SMALL LETTER TSHE +0x9F 0x045F #CYRILLIC SMALL LETTER DZHE +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x040E #CYRILLIC CAPITAL LETTER SHORT U +0xA2 0x045E #CYRILLIC SMALL LETTER SHORT U +0xA3 0x0408 #CYRILLIC CAPITAL LETTER JE +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x0490 #CYRILLIC CAPITAL LETTER GHE WITH UPTURN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x0401 #CYRILLIC CAPITAL LETTER IO +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x0404 #CYRILLIC CAPITAL LETTER UKRAINIAN IE +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x0407 #CYRILLIC CAPITAL LETTER YI +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x0406 #CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +0xB3 0x0456 #CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +0xB4 0x0491 #CYRILLIC SMALL LETTER GHE WITH UPTURN +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x0451 #CYRILLIC SMALL LETTER IO +0xB9 0x2116 #NUMERO SIGN +0xBA 0x0454 #CYRILLIC SMALL LETTER UKRAINIAN IE +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x0458 #CYRILLIC SMALL LETTER JE +0xBD 0x0405 #CYRILLIC CAPITAL LETTER DZE +0xBE 0x0455 #CYRILLIC SMALL LETTER DZE +0xBF 0x0457 #CYRILLIC SMALL LETTER YI +0xC0 0x0410 #CYRILLIC CAPITAL LETTER A +0xC1 0x0411 #CYRILLIC CAPITAL LETTER BE +0xC2 0x0412 #CYRILLIC CAPITAL LETTER VE +0xC3 0x0413 #CYRILLIC CAPITAL LETTER GHE +0xC4 0x0414 #CYRILLIC CAPITAL LETTER DE +0xC5 0x0415 #CYRILLIC CAPITAL LETTER IE +0xC6 0x0416 #CYRILLIC CAPITAL LETTER ZHE +0xC7 0x0417 #CYRILLIC CAPITAL LETTER ZE +0xC8 0x0418 #CYRILLIC CAPITAL LETTER I +0xC9 0x0419 #CYRILLIC CAPITAL LETTER SHORT I +0xCA 0x041A #CYRILLIC CAPITAL LETTER KA +0xCB 0x041B #CYRILLIC CAPITAL LETTER EL +0xCC 0x041C #CYRILLIC CAPITAL LETTER EM +0xCD 0x041D #CYRILLIC CAPITAL LETTER EN +0xCE 0x041E #CYRILLIC CAPITAL LETTER O +0xCF 0x041F #CYRILLIC CAPITAL LETTER PE +0xD0 0x0420 #CYRILLIC CAPITAL LETTER ER +0xD1 0x0421 #CYRILLIC CAPITAL LETTER ES +0xD2 0x0422 #CYRILLIC CAPITAL LETTER TE +0xD3 0x0423 #CYRILLIC CAPITAL LETTER U +0xD4 0x0424 #CYRILLIC CAPITAL LETTER EF +0xD5 0x0425 #CYRILLIC CAPITAL LETTER HA +0xD6 0x0426 #CYRILLIC CAPITAL LETTER TSE +0xD7 0x0427 #CYRILLIC CAPITAL LETTER CHE +0xD8 0x0428 #CYRILLIC CAPITAL LETTER SHA +0xD9 0x0429 #CYRILLIC CAPITAL LETTER SHCHA +0xDA 0x042A #CYRILLIC CAPITAL LETTER HARD SIGN +0xDB 0x042B #CYRILLIC CAPITAL LETTER YERU +0xDC 0x042C #CYRILLIC CAPITAL LETTER SOFT SIGN +0xDD 0x042D #CYRILLIC CAPITAL LETTER E +0xDE 0x042E #CYRILLIC CAPITAL LETTER YU +0xDF 0x042F #CYRILLIC CAPITAL LETTER YA +0xE0 0x0430 #CYRILLIC SMALL LETTER A +0xE1 0x0431 #CYRILLIC SMALL LETTER BE +0xE2 0x0432 #CYRILLIC SMALL LETTER VE +0xE3 0x0433 #CYRILLIC SMALL LETTER GHE +0xE4 0x0434 #CYRILLIC SMALL LETTER DE +0xE5 0x0435 #CYRILLIC SMALL LETTER IE +0xE6 0x0436 #CYRILLIC SMALL LETTER ZHE +0xE7 0x0437 #CYRILLIC SMALL LETTER ZE +0xE8 0x0438 #CYRILLIC SMALL LETTER I +0xE9 0x0439 #CYRILLIC SMALL LETTER SHORT I +0xEA 0x043A #CYRILLIC SMALL LETTER KA +0xEB 0x043B #CYRILLIC SMALL LETTER EL +0xEC 0x043C #CYRILLIC SMALL LETTER EM +0xED 0x043D #CYRILLIC SMALL LETTER EN +0xEE 0x043E #CYRILLIC SMALL LETTER O +0xEF 0x043F #CYRILLIC SMALL LETTER PE +0xF0 0x0440 #CYRILLIC SMALL LETTER ER +0xF1 0x0441 #CYRILLIC SMALL LETTER ES +0xF2 0x0442 #CYRILLIC SMALL LETTER TE +0xF3 0x0443 #CYRILLIC SMALL LETTER U +0xF4 0x0444 #CYRILLIC SMALL LETTER EF +0xF5 0x0445 #CYRILLIC SMALL LETTER HA +0xF6 0x0446 #CYRILLIC SMALL LETTER TSE +0xF7 0x0447 #CYRILLIC SMALL LETTER CHE +0xF8 0x0448 #CYRILLIC SMALL LETTER SHA +0xF9 0x0449 #CYRILLIC SMALL LETTER SHCHA +0xFA 0x044A #CYRILLIC SMALL LETTER HARD SIGN +0xFB 0x044B #CYRILLIC SMALL LETTER YERU +0xFC 0x044C #CYRILLIC SMALL LETTER SOFT SIGN +0xFD 0x044D #CYRILLIC SMALL LETTER E +0xFE 0x044E #CYRILLIC SMALL LETTER YU +0xFF 0x044F #CYRILLIC SMALL LETTER YA diff --git a/basis/io/encodings/8-bit/CP1253.TXT b/basis/io/encodings/8-bit/CP1253.TXT new file mode 100644 index 0000000000..20a55b04df --- /dev/null +++ b/basis/io/encodings/8-bit/CP1253.TXT @@ -0,0 +1,274 @@ +# +# Name: cp1253 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: Shawn.Steele@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1253 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1253 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 #UNDEFINED +0x89 0x2030 #PER MILLE SIGN +0x8A #UNDEFINED +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C #UNDEFINED +0x8D #UNDEFINED +0x8E #UNDEFINED +0x8F #UNDEFINED +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 #UNDEFINED +0x99 0x2122 #TRADE MARK SIGN +0x9A #UNDEFINED +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C #UNDEFINED +0x9D #UNDEFINED +0x9E #UNDEFINED +0x9F #UNDEFINED +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x0385 #GREEK DIALYTIKA TONOS +0xA2 0x0386 #GREEK CAPITAL LETTER ALPHA WITH TONOS +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA #UNDEFINED +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x2015 #HORIZONTAL BAR +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x0384 #GREEK TONOS +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x0388 #GREEK CAPITAL LETTER EPSILON WITH TONOS +0xB9 0x0389 #GREEK CAPITAL LETTER ETA WITH TONOS +0xBA 0x038A #GREEK CAPITAL LETTER IOTA WITH TONOS +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x038C #GREEK CAPITAL LETTER OMICRON WITH TONOS +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x038E #GREEK CAPITAL LETTER UPSILON WITH TONOS +0xBF 0x038F #GREEK CAPITAL LETTER OMEGA WITH TONOS +0xC0 0x0390 #GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +0xC1 0x0391 #GREEK CAPITAL LETTER ALPHA +0xC2 0x0392 #GREEK CAPITAL LETTER BETA +0xC3 0x0393 #GREEK CAPITAL LETTER GAMMA +0xC4 0x0394 #GREEK CAPITAL LETTER DELTA +0xC5 0x0395 #GREEK CAPITAL LETTER EPSILON +0xC6 0x0396 #GREEK CAPITAL LETTER ZETA +0xC7 0x0397 #GREEK CAPITAL LETTER ETA +0xC8 0x0398 #GREEK CAPITAL LETTER THETA +0xC9 0x0399 #GREEK CAPITAL LETTER IOTA +0xCA 0x039A #GREEK CAPITAL LETTER KAPPA +0xCB 0x039B #GREEK CAPITAL LETTER LAMDA +0xCC 0x039C #GREEK CAPITAL LETTER MU +0xCD 0x039D #GREEK CAPITAL LETTER NU +0xCE 0x039E #GREEK CAPITAL LETTER XI +0xCF 0x039F #GREEK CAPITAL LETTER OMICRON +0xD0 0x03A0 #GREEK CAPITAL LETTER PI +0xD1 0x03A1 #GREEK CAPITAL LETTER RHO +0xD2 #UNDEFINED +0xD3 0x03A3 #GREEK CAPITAL LETTER SIGMA +0xD4 0x03A4 #GREEK CAPITAL LETTER TAU +0xD5 0x03A5 #GREEK CAPITAL LETTER UPSILON +0xD6 0x03A6 #GREEK CAPITAL LETTER PHI +0xD7 0x03A7 #GREEK CAPITAL LETTER CHI +0xD8 0x03A8 #GREEK CAPITAL LETTER PSI +0xD9 0x03A9 #GREEK CAPITAL LETTER OMEGA +0xDA 0x03AA #GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +0xDB 0x03AB #GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +0xDC 0x03AC #GREEK SMALL LETTER ALPHA WITH TONOS +0xDD 0x03AD #GREEK SMALL LETTER EPSILON WITH TONOS +0xDE 0x03AE #GREEK SMALL LETTER ETA WITH TONOS +0xDF 0x03AF #GREEK SMALL LETTER IOTA WITH TONOS +0xE0 0x03B0 #GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +0xE1 0x03B1 #GREEK SMALL LETTER ALPHA +0xE2 0x03B2 #GREEK SMALL LETTER BETA +0xE3 0x03B3 #GREEK SMALL LETTER GAMMA +0xE4 0x03B4 #GREEK SMALL LETTER DELTA +0xE5 0x03B5 #GREEK SMALL LETTER EPSILON +0xE6 0x03B6 #GREEK SMALL LETTER ZETA +0xE7 0x03B7 #GREEK SMALL LETTER ETA +0xE8 0x03B8 #GREEK SMALL LETTER THETA +0xE9 0x03B9 #GREEK SMALL LETTER IOTA +0xEA 0x03BA #GREEK SMALL LETTER KAPPA +0xEB 0x03BB #GREEK SMALL LETTER LAMDA +0xEC 0x03BC #GREEK SMALL LETTER MU +0xED 0x03BD #GREEK SMALL LETTER NU +0xEE 0x03BE #GREEK SMALL LETTER XI +0xEF 0x03BF #GREEK SMALL LETTER OMICRON +0xF0 0x03C0 #GREEK SMALL LETTER PI +0xF1 0x03C1 #GREEK SMALL LETTER RHO +0xF2 0x03C2 #GREEK SMALL LETTER FINAL SIGMA +0xF3 0x03C3 #GREEK SMALL LETTER SIGMA +0xF4 0x03C4 #GREEK SMALL LETTER TAU +0xF5 0x03C5 #GREEK SMALL LETTER UPSILON +0xF6 0x03C6 #GREEK SMALL LETTER PHI +0xF7 0x03C7 #GREEK SMALL LETTER CHI +0xF8 0x03C8 #GREEK SMALL LETTER PSI +0xF9 0x03C9 #GREEK SMALL LETTER OMEGA +0xFA 0x03CA #GREEK SMALL LETTER IOTA WITH DIALYTIKA +0xFB 0x03CB #GREEK SMALL LETTER UPSILON WITH DIALYTIKA +0xFC 0x03CC #GREEK SMALL LETTER OMICRON WITH TONOS +0xFD 0x03CD #GREEK SMALL LETTER UPSILON WITH TONOS +0xFE 0x03CE #GREEK SMALL LETTER OMEGA WITH TONOS +0xFF #UNDEFINED diff --git a/basis/io/encodings/8-bit/CP1254.TXT b/basis/io/encodings/8-bit/CP1254.TXT new file mode 100644 index 0000000000..987ed98f75 --- /dev/null +++ b/basis/io/encodings/8-bit/CP1254.TXT @@ -0,0 +1,274 @@ +# +# Name: cp1254 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: Shawn.Steele@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1254 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1254 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT +0x89 0x2030 #PER MILLE SIGN +0x8A 0x0160 #LATIN CAPITAL LETTER S WITH CARON +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C 0x0152 #LATIN CAPITAL LIGATURE OE +0x8D #UNDEFINED +0x8E #UNDEFINED +0x8F #UNDEFINED +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 0x02DC #SMALL TILDE +0x99 0x2122 #TRADE MARK SIGN +0x9A 0x0161 #LATIN SMALL LETTER S WITH CARON +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C 0x0153 #LATIN SMALL LIGATURE OE +0x9D #UNDEFINED +0x9E #UNDEFINED +0x9F 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x00A1 #INVERTED EXCLAMATION MARK +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x00AA #FEMININE ORDINAL INDICATOR +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00AF #MACRON +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00B8 #CEDILLA +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x00BA #MASCULINE ORDINAL INDICATOR +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x00BF #INVERTED QUESTION MARK +0xC0 0x00C0 #LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 #LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x00C3 #LATIN CAPITAL LETTER A WITH TILDE +0xC4 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 #LATIN CAPITAL LETTER AE +0xC7 0x00C7 #LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 #LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA #LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB #LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x00CC #LATIN CAPITAL LETTER I WITH GRAVE +0xCD 0x00CD #LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE #LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF #LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x011E #LATIN CAPITAL LETTER G WITH BREVE +0xD1 0x00D1 #LATIN CAPITAL LETTER N WITH TILDE +0xD2 0x00D2 #LATIN CAPITAL LETTER O WITH GRAVE +0xD3 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x00D5 #LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 #MULTIPLICATION SIGN +0xD8 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x00D9 #LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA #LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB #LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x0130 #LATIN CAPITAL LETTER I WITH DOT ABOVE +0xDE 0x015E #LATIN CAPITAL LETTER S WITH CEDILLA +0xDF 0x00DF #LATIN SMALL LETTER SHARP S +0xE0 0x00E0 #LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 #LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x00E3 #LATIN SMALL LETTER A WITH TILDE +0xE4 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 #LATIN SMALL LETTER AE +0xE7 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 #LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x00EC #LATIN SMALL LETTER I WITH GRAVE +0xED 0x00ED #LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x011F #LATIN SMALL LETTER G WITH BREVE +0xF1 0x00F1 #LATIN SMALL LETTER N WITH TILDE +0xF2 0x00F2 #LATIN SMALL LETTER O WITH GRAVE +0xF3 0x00F3 #LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x00F5 #LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 #DIVISION SIGN +0xF8 0x00F8 #LATIN SMALL LETTER O WITH STROKE +0xF9 0x00F9 #LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA #LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x0131 #LATIN SMALL LETTER DOTLESS I +0xFE 0x015F #LATIN SMALL LETTER S WITH CEDILLA +0xFF 0x00FF #LATIN SMALL LETTER Y WITH DIAERESIS diff --git a/basis/io/encodings/8-bit/CP1255.TXT b/basis/io/encodings/8-bit/CP1255.TXT new file mode 100644 index 0000000000..585f993753 --- /dev/null +++ b/basis/io/encodings/8-bit/CP1255.TXT @@ -0,0 +1,274 @@ +# +# Name: cp1255 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 1/7/2000 +# +# Contact: Shawn.Steele@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1255 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1255 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT +0x89 0x2030 #PER MILLE SIGN +0x8A #UNDEFINED +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C #UNDEFINED +0x8D #UNDEFINED +0x8E #UNDEFINED +0x8F #UNDEFINED +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 0x02DC #SMALL TILDE +0x99 0x2122 #TRADE MARK SIGN +0x9A #UNDEFINED +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C #UNDEFINED +0x9D #UNDEFINED +0x9E #UNDEFINED +0x9F #UNDEFINED +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x00A1 #INVERTED EXCLAMATION MARK +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x20AA #NEW SHEQEL SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x00D7 #MULTIPLICATION SIGN +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00AF #MACRON +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00B8 #CEDILLA +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x00F7 #DIVISION SIGN +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x00BF #INVERTED QUESTION MARK +0xC0 0x05B0 #HEBREW POINT SHEVA +0xC1 0x05B1 #HEBREW POINT HATAF SEGOL +0xC2 0x05B2 #HEBREW POINT HATAF PATAH +0xC3 0x05B3 #HEBREW POINT HATAF QAMATS +0xC4 0x05B4 #HEBREW POINT HIRIQ +0xC5 0x05B5 #HEBREW POINT TSERE +0xC6 0x05B6 #HEBREW POINT SEGOL +0xC7 0x05B7 #HEBREW POINT PATAH +0xC8 0x05B8 #HEBREW POINT QAMATS +0xC9 0x05B9 #HEBREW POINT HOLAM +0xCA #UNDEFINED +0xCB 0x05BB #HEBREW POINT QUBUTS +0xCC 0x05BC #HEBREW POINT DAGESH OR MAPIQ +0xCD 0x05BD #HEBREW POINT METEG +0xCE 0x05BE #HEBREW PUNCTUATION MAQAF +0xCF 0x05BF #HEBREW POINT RAFE +0xD0 0x05C0 #HEBREW PUNCTUATION PASEQ +0xD1 0x05C1 #HEBREW POINT SHIN DOT +0xD2 0x05C2 #HEBREW POINT SIN DOT +0xD3 0x05C3 #HEBREW PUNCTUATION SOF PASUQ +0xD4 0x05F0 #HEBREW LIGATURE YIDDISH DOUBLE VAV +0xD5 0x05F1 #HEBREW LIGATURE YIDDISH VAV YOD +0xD6 0x05F2 #HEBREW LIGATURE YIDDISH DOUBLE YOD +0xD7 0x05F3 #HEBREW PUNCTUATION GERESH +0xD8 0x05F4 #HEBREW PUNCTUATION GERSHAYIM +0xD9 #UNDEFINED +0xDA #UNDEFINED +0xDB #UNDEFINED +0xDC #UNDEFINED +0xDD #UNDEFINED +0xDE #UNDEFINED +0xDF #UNDEFINED +0xE0 0x05D0 #HEBREW LETTER ALEF +0xE1 0x05D1 #HEBREW LETTER BET +0xE2 0x05D2 #HEBREW LETTER GIMEL +0xE3 0x05D3 #HEBREW LETTER DALET +0xE4 0x05D4 #HEBREW LETTER HE +0xE5 0x05D5 #HEBREW LETTER VAV +0xE6 0x05D6 #HEBREW LETTER ZAYIN +0xE7 0x05D7 #HEBREW LETTER HET +0xE8 0x05D8 #HEBREW LETTER TET +0xE9 0x05D9 #HEBREW LETTER YOD +0xEA 0x05DA #HEBREW LETTER FINAL KAF +0xEB 0x05DB #HEBREW LETTER KAF +0xEC 0x05DC #HEBREW LETTER LAMED +0xED 0x05DD #HEBREW LETTER FINAL MEM +0xEE 0x05DE #HEBREW LETTER MEM +0xEF 0x05DF #HEBREW LETTER FINAL NUN +0xF0 0x05E0 #HEBREW LETTER NUN +0xF1 0x05E1 #HEBREW LETTER SAMEKH +0xF2 0x05E2 #HEBREW LETTER AYIN +0xF3 0x05E3 #HEBREW LETTER FINAL PE +0xF4 0x05E4 #HEBREW LETTER PE +0xF5 0x05E5 #HEBREW LETTER FINAL TSADI +0xF6 0x05E6 #HEBREW LETTER TSADI +0xF7 0x05E7 #HEBREW LETTER QOF +0xF8 0x05E8 #HEBREW LETTER RESH +0xF9 0x05E9 #HEBREW LETTER SHIN +0xFA 0x05EA #HEBREW LETTER TAV +0xFB #UNDEFINED +0xFC #UNDEFINED +0xFD 0x200E #LEFT-TO-RIGHT MARK +0xFE 0x200F #RIGHT-TO-LEFT MARK +0xFF #UNDEFINED diff --git a/basis/io/encodings/8-bit/CP1256.TXT b/basis/io/encodings/8-bit/CP1256.TXT new file mode 100644 index 0000000000..244dcce01f --- /dev/null +++ b/basis/io/encodings/8-bit/CP1256.TXT @@ -0,0 +1,274 @@ +# +# Name: cp1256 to Unicode table +# Unicode version: 2.1 +# Table version: 2.01 +# Table format: Format A +# Date: 01/5/99 +# +# Contact: Shawn.Steele@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1256 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1256 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 0x067E #ARABIC LETTER PEH +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT +0x89 0x2030 #PER MILLE SIGN +0x8A 0x0679 #ARABIC LETTER TTEH +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C 0x0152 #LATIN CAPITAL LIGATURE OE +0x8D 0x0686 #ARABIC LETTER TCHEH +0x8E 0x0698 #ARABIC LETTER JEH +0x8F 0x0688 #ARABIC LETTER DDAL +0x90 0x06AF #ARABIC LETTER GAF +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 0x06A9 #ARABIC LETTER KEHEH +0x99 0x2122 #TRADE MARK SIGN +0x9A 0x0691 #ARABIC LETTER RREH +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C 0x0153 #LATIN SMALL LIGATURE OE +0x9D 0x200C #ZERO WIDTH NON-JOINER +0x9E 0x200D #ZERO WIDTH JOINER +0x9F 0x06BA #ARABIC LETTER NOON GHUNNA +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x060C #ARABIC COMMA +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x06BE #ARABIC LETTER HEH DOACHASHMEE +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00AF #MACRON +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00B8 #CEDILLA +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x061B #ARABIC SEMICOLON +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x061F #ARABIC QUESTION MARK +0xC0 0x06C1 #ARABIC LETTER HEH GOAL +0xC1 0x0621 #ARABIC LETTER HAMZA +0xC2 0x0622 #ARABIC LETTER ALEF WITH MADDA ABOVE +0xC3 0x0623 #ARABIC LETTER ALEF WITH HAMZA ABOVE +0xC4 0x0624 #ARABIC LETTER WAW WITH HAMZA ABOVE +0xC5 0x0625 #ARABIC LETTER ALEF WITH HAMZA BELOW +0xC6 0x0626 #ARABIC LETTER YEH WITH HAMZA ABOVE +0xC7 0x0627 #ARABIC LETTER ALEF +0xC8 0x0628 #ARABIC LETTER BEH +0xC9 0x0629 #ARABIC LETTER TEH MARBUTA +0xCA 0x062A #ARABIC LETTER TEH +0xCB 0x062B #ARABIC LETTER THEH +0xCC 0x062C #ARABIC LETTER JEEM +0xCD 0x062D #ARABIC LETTER HAH +0xCE 0x062E #ARABIC LETTER KHAH +0xCF 0x062F #ARABIC LETTER DAL +0xD0 0x0630 #ARABIC LETTER THAL +0xD1 0x0631 #ARABIC LETTER REH +0xD2 0x0632 #ARABIC LETTER ZAIN +0xD3 0x0633 #ARABIC LETTER SEEN +0xD4 0x0634 #ARABIC LETTER SHEEN +0xD5 0x0635 #ARABIC LETTER SAD +0xD6 0x0636 #ARABIC LETTER DAD +0xD7 0x00D7 #MULTIPLICATION SIGN +0xD8 0x0637 #ARABIC LETTER TAH +0xD9 0x0638 #ARABIC LETTER ZAH +0xDA 0x0639 #ARABIC LETTER AIN +0xDB 0x063A #ARABIC LETTER GHAIN +0xDC 0x0640 #ARABIC TATWEEL +0xDD 0x0641 #ARABIC LETTER FEH +0xDE 0x0642 #ARABIC LETTER QAF +0xDF 0x0643 #ARABIC LETTER KAF +0xE0 0x00E0 #LATIN SMALL LETTER A WITH GRAVE +0xE1 0x0644 #ARABIC LETTER LAM +0xE2 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x0645 #ARABIC LETTER MEEM +0xE4 0x0646 #ARABIC LETTER NOON +0xE5 0x0647 #ARABIC LETTER HEH +0xE6 0x0648 #ARABIC LETTER WAW +0xE7 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 #LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x0649 #ARABIC LETTER ALEF MAKSURA +0xED 0x064A #ARABIC LETTER YEH +0xEE 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x064B #ARABIC FATHATAN +0xF1 0x064C #ARABIC DAMMATAN +0xF2 0x064D #ARABIC KASRATAN +0xF3 0x064E #ARABIC FATHA +0xF4 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x064F #ARABIC DAMMA +0xF6 0x0650 #ARABIC KASRA +0xF7 0x00F7 #DIVISION SIGN +0xF8 0x0651 #ARABIC SHADDA +0xF9 0x00F9 #LATIN SMALL LETTER U WITH GRAVE +0xFA 0x0652 #ARABIC SUKUN +0xFB 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x200E #LEFT-TO-RIGHT MARK +0xFE 0x200F #RIGHT-TO-LEFT MARK +0xFF 0x06D2 #ARABIC LETTER YEH BARREE diff --git a/basis/io/encodings/8-bit/CP1257.TXT b/basis/io/encodings/8-bit/CP1257.TXT new file mode 100644 index 0000000000..0dc475e022 --- /dev/null +++ b/basis/io/encodings/8-bit/CP1257.TXT @@ -0,0 +1,274 @@ +# +# Name: cp1257 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: Shawn.Steele@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1257 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1257 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 #UNDEFINED +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 #UNDEFINED +0x89 0x2030 #PER MILLE SIGN +0x8A #UNDEFINED +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C #UNDEFINED +0x8D 0x00A8 #DIAERESIS +0x8E 0x02C7 #CARON +0x8F 0x00B8 #CEDILLA +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 #UNDEFINED +0x99 0x2122 #TRADE MARK SIGN +0x9A #UNDEFINED +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C #UNDEFINED +0x9D 0x00AF #MACRON +0x9E 0x02DB #OGONEK +0x9F #UNDEFINED +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 #UNDEFINED +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 #UNDEFINED +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x0156 #LATIN CAPITAL LETTER R WITH CEDILLA +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00C6 #LATIN CAPITAL LETTER AE +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00F8 #LATIN SMALL LETTER O WITH STROKE +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x0157 #LATIN SMALL LETTER R WITH CEDILLA +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x00E6 #LATIN SMALL LETTER AE +0xC0 0x0104 #LATIN CAPITAL LETTER A WITH OGONEK +0xC1 0x012E #LATIN CAPITAL LETTER I WITH OGONEK +0xC2 0x0100 #LATIN CAPITAL LETTER A WITH MACRON +0xC3 0x0106 #LATIN CAPITAL LETTER C WITH ACUTE +0xC4 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x0118 #LATIN CAPITAL LETTER E WITH OGONEK +0xC7 0x0112 #LATIN CAPITAL LETTER E WITH MACRON +0xC8 0x010C #LATIN CAPITAL LETTER C WITH CARON +0xC9 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x0179 #LATIN CAPITAL LETTER Z WITH ACUTE +0xCB 0x0116 #LATIN CAPITAL LETTER E WITH DOT ABOVE +0xCC 0x0122 #LATIN CAPITAL LETTER G WITH CEDILLA +0xCD 0x0136 #LATIN CAPITAL LETTER K WITH CEDILLA +0xCE 0x012A #LATIN CAPITAL LETTER I WITH MACRON +0xCF 0x013B #LATIN CAPITAL LETTER L WITH CEDILLA +0xD0 0x0160 #LATIN CAPITAL LETTER S WITH CARON +0xD1 0x0143 #LATIN CAPITAL LETTER N WITH ACUTE +0xD2 0x0145 #LATIN CAPITAL LETTER N WITH CEDILLA +0xD3 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x014C #LATIN CAPITAL LETTER O WITH MACRON +0xD5 0x00D5 #LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 #MULTIPLICATION SIGN +0xD8 0x0172 #LATIN CAPITAL LETTER U WITH OGONEK +0xD9 0x0141 #LATIN CAPITAL LETTER L WITH STROKE +0xDA 0x015A #LATIN CAPITAL LETTER S WITH ACUTE +0xDB 0x016A #LATIN CAPITAL LETTER U WITH MACRON +0xDC 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x017B #LATIN CAPITAL LETTER Z WITH DOT ABOVE +0xDE 0x017D #LATIN CAPITAL LETTER Z WITH CARON +0xDF 0x00DF #LATIN SMALL LETTER SHARP S +0xE0 0x0105 #LATIN SMALL LETTER A WITH OGONEK +0xE1 0x012F #LATIN SMALL LETTER I WITH OGONEK +0xE2 0x0101 #LATIN SMALL LETTER A WITH MACRON +0xE3 0x0107 #LATIN SMALL LETTER C WITH ACUTE +0xE4 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x0119 #LATIN SMALL LETTER E WITH OGONEK +0xE7 0x0113 #LATIN SMALL LETTER E WITH MACRON +0xE8 0x010D #LATIN SMALL LETTER C WITH CARON +0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0xEA 0x017A #LATIN SMALL LETTER Z WITH ACUTE +0xEB 0x0117 #LATIN SMALL LETTER E WITH DOT ABOVE +0xEC 0x0123 #LATIN SMALL LETTER G WITH CEDILLA +0xED 0x0137 #LATIN SMALL LETTER K WITH CEDILLA +0xEE 0x012B #LATIN SMALL LETTER I WITH MACRON +0xEF 0x013C #LATIN SMALL LETTER L WITH CEDILLA +0xF0 0x0161 #LATIN SMALL LETTER S WITH CARON +0xF1 0x0144 #LATIN SMALL LETTER N WITH ACUTE +0xF2 0x0146 #LATIN SMALL LETTER N WITH CEDILLA +0xF3 0x00F3 #LATIN SMALL LETTER O WITH ACUTE +0xF4 0x014D #LATIN SMALL LETTER O WITH MACRON +0xF5 0x00F5 #LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 #DIVISION SIGN +0xF8 0x0173 #LATIN SMALL LETTER U WITH OGONEK +0xF9 0x0142 #LATIN SMALL LETTER L WITH STROKE +0xFA 0x015B #LATIN SMALL LETTER S WITH ACUTE +0xFB 0x016B #LATIN SMALL LETTER U WITH MACRON +0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x017C #LATIN SMALL LETTER Z WITH DOT ABOVE +0xFE 0x017E #LATIN SMALL LETTER Z WITH CARON +0xFF 0x02D9 #DOT ABOVE diff --git a/basis/io/encodings/8-bit/CP1258.TXT b/basis/io/encodings/8-bit/CP1258.TXT new file mode 100644 index 0000000000..f402b34b48 --- /dev/null +++ b/basis/io/encodings/8-bit/CP1258.TXT @@ -0,0 +1,274 @@ +# +# Name: cp1258 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: Shawn.Steele@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1258 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1258 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT +0x89 0x2030 #PER MILLE SIGN +0x8A #UNDEFINED +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C 0x0152 #LATIN CAPITAL LIGATURE OE +0x8D #UNDEFINED +0x8E #UNDEFINED +0x8F #UNDEFINED +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 0x02DC #SMALL TILDE +0x99 0x2122 #TRADE MARK SIGN +0x9A #UNDEFINED +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C 0x0153 #LATIN SMALL LIGATURE OE +0x9D #UNDEFINED +0x9E #UNDEFINED +0x9F 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x00A1 #INVERTED EXCLAMATION MARK +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x00AA #FEMININE ORDINAL INDICATOR +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00AF #MACRON +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00B8 #CEDILLA +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x00BA #MASCULINE ORDINAL INDICATOR +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x00BF #INVERTED QUESTION MARK +0xC0 0x00C0 #LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 #LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x0102 #LATIN CAPITAL LETTER A WITH BREVE +0xC4 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 #LATIN CAPITAL LETTER AE +0xC7 0x00C7 #LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 #LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA #LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB #LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x0300 #COMBINING GRAVE ACCENT +0xCD 0x00CD #LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE #LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF #LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x0110 #LATIN CAPITAL LETTER D WITH STROKE +0xD1 0x00D1 #LATIN CAPITAL LETTER N WITH TILDE +0xD2 0x0309 #COMBINING HOOK ABOVE +0xD3 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x01A0 #LATIN CAPITAL LETTER O WITH HORN +0xD6 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 #MULTIPLICATION SIGN +0xD8 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x00D9 #LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA #LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB #LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x01AF #LATIN CAPITAL LETTER U WITH HORN +0xDE 0x0303 #COMBINING TILDE +0xDF 0x00DF #LATIN SMALL LETTER SHARP S +0xE0 0x00E0 #LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 #LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x0103 #LATIN SMALL LETTER A WITH BREVE +0xE4 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 #LATIN SMALL LETTER AE +0xE7 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 #LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x0301 #COMBINING ACUTE ACCENT +0xED 0x00ED #LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x0111 #LATIN SMALL LETTER D WITH STROKE +0xF1 0x00F1 #LATIN SMALL LETTER N WITH TILDE +0xF2 0x0323 #COMBINING DOT BELOW +0xF3 0x00F3 #LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x01A1 #LATIN SMALL LETTER O WITH HORN +0xF6 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 #DIVISION SIGN +0xF8 0x00F8 #LATIN SMALL LETTER O WITH STROKE +0xF9 0x00F9 #LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA #LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x01B0 #LATIN SMALL LETTER U WITH HORN +0xFE 0x20AB #DONG SIGN +0xFF 0x00FF #LATIN SMALL LETTER Y WITH DIAERESIS diff --git a/basis/io/encodings/8-bit/arabic/arabic-docs.factor b/basis/io/encodings/8-bit/arabic/arabic-docs.factor new file mode 100644 index 0000000000..5c86326121 --- /dev/null +++ b/basis/io/encodings/8-bit/arabic/arabic-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.arabic + +HELP: latin/arabic +{ $var-description "This is the ISO-8859-6 encoding, also called Latin/Arabic. It is an 8-bit superset of ASCII and provides the characters necessary for Arabic, though not other languages which use Arabic script." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.arabic" "Arabic encoding" +"The " { $vocab-link "io.encodings.8-bit.arabic" } " vocabulary provides the " { $link latin/arabic } " encoding." ; + +ABOUT: "io.encodings.8-bit.arabic" diff --git a/basis/io/encodings/8-bit/arabic/arabic.factor b/basis/io/encodings/8-bit/arabic/arabic.factor new file mode 100644 index 0000000000..5a80921ab3 --- /dev/null +++ b/basis/io/encodings/8-bit/arabic/arabic.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.arabic + +8-BIT: latin/arabic ISO_8859-6:1987 8859-6 diff --git a/basis/io/encodings/8-bit/arabic/authors.txt b/basis/io/encodings/8-bit/arabic/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/arabic/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/cyrillic/authors.txt b/basis/io/encodings/8-bit/cyrillic/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/cyrillic/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/cyrillic/cyrillic-docs.factor b/basis/io/encodings/8-bit/cyrillic/cyrillic-docs.factor new file mode 100644 index 0000000000..741f1de1f6 --- /dev/null +++ b/basis/io/encodings/8-bit/cyrillic/cyrillic-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.cyrillic + +HELP: latin/cyrillic +{ $var-description "This is the ISO-8859-5 encoding, also called Latin/Cyrillic. It is an 8-bit superset of ASCII and provides the characters necessary for most languages which use Cyrilic, including Russian, Macedonian, Belarusian, Bulgarian, Serbian, and Ukrainian. KOI8-R is used much more commonly." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.cyrillic" "Cyrillic encoding" +"The " { $vocab-link "io.encodings.8-bit.cyrillic" } " vocabulary provides the " { $link latin/cyrillic } " encoding." ; + +ABOUT: "io.encodings.8-bit.cyrillic" diff --git a/basis/io/encodings/8-bit/cyrillic/cyrillic.factor b/basis/io/encodings/8-bit/cyrillic/cyrillic.factor new file mode 100644 index 0000000000..13cfbc07da --- /dev/null +++ b/basis/io/encodings/8-bit/cyrillic/cyrillic.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.cyrillic + +8-BIT: latin/cyrillic ISO_8859-5:1988 8859-5 diff --git a/basis/io/encodings/8-bit/ebcdic/authors.txt b/basis/io/encodings/8-bit/ebcdic/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/ebcdic/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/ebcdic/ebcdic-docs.factor b/basis/io/encodings/8-bit/ebcdic/ebcdic-docs.factor new file mode 100644 index 0000000000..09646fddc3 --- /dev/null +++ b/basis/io/encodings/8-bit/ebcdic/ebcdic-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.ebcdic + +HELP: ebcdic +{ $var-description "EBCDIC is an 8-bit legacy encoding designed for IBM mainframes like System/360 in the 1960s. It has since fallen into disuse. It contains large unallocated regions, and the version included here (code page 37) contains auxiliary characters in this region for English- and Portugese-speaking countries." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.ebcdic" "EBCDIC encoding" +"The " { $vocab-link "io.encodings.8-bit.ebcdic" } " vocabulary provides the " { $link ebcdic } " encoding." ; + +ABOUT: "io.encodings.8-bit.ebcdic" diff --git a/basis/io/encodings/8-bit/ebcdic/ebcdic.factor b/basis/io/encodings/8-bit/ebcdic/ebcdic.factor new file mode 100644 index 0000000000..fd8f29c40c --- /dev/null +++ b/basis/io/encodings/8-bit/ebcdic/ebcdic.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.ebcdic + +8-BIT: ebcdic IBM037 CP037 diff --git a/basis/io/encodings/8-bit/greek/authors.txt b/basis/io/encodings/8-bit/greek/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/greek/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/greek/greek-docs.factor b/basis/io/encodings/8-bit/greek/greek-docs.factor new file mode 100644 index 0000000000..b7d658ac70 --- /dev/null +++ b/basis/io/encodings/8-bit/greek/greek-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.greek + +HELP: latin/greek +{ $description "This is the ISO-8859-7 encoding, also called Latin/Greek. It is an 8-bit superset of ASCII and provides the characters necessary for Greek written in modern monotonic orthography, or ancient Greek without accent marks." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.greek" "Greek encoding" +"The " { $vocab-link "io.encodings.8-bit.greek" } " vocabulary provides the " { $link latin/greek } " encoding." ; + +ABOUT: "io.encodings.8-bit.greek" diff --git a/basis/io/encodings/8-bit/greek/greek.factor b/basis/io/encodings/8-bit/greek/greek.factor new file mode 100644 index 0000000000..98eb09ad6d --- /dev/null +++ b/basis/io/encodings/8-bit/greek/greek.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.greek + +8-BIT: latin/greek ISO_8859-7:1987 8859-7 diff --git a/basis/io/encodings/8-bit/hebrew/authors.txt b/basis/io/encodings/8-bit/hebrew/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/hebrew/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/hebrew/hebrew-docs.factor b/basis/io/encodings/8-bit/hebrew/hebrew-docs.factor new file mode 100644 index 0000000000..43433e2c91 --- /dev/null +++ b/basis/io/encodings/8-bit/hebrew/hebrew-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.hebrew + +HELP: latin/hebrew +{ $var-description "This is the ISO-8859-8 encoding, also called Latin/Hebrew. It is an 8-bit superset of ASCII and provides the characters necessary for modern Hebrew without explicit vowels. Generally, this is interpreted in logical order, making it ISO-8859-8-I, technically." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.hebrew" "Hebrew encoding" +"The " { $vocab-link "io.encodings.8-bit.hebrew" } " vocabulary provides the " { $link latin/hebrew } " encoding." ; + +ABOUT: "io.encodings.8-bit.hebrew" diff --git a/basis/io/encodings/8-bit/hebrew/hebrew.factor b/basis/io/encodings/8-bit/hebrew/hebrew.factor new file mode 100644 index 0000000000..6619f64fd6 --- /dev/null +++ b/basis/io/encodings/8-bit/hebrew/hebrew.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.hebrew + +8-BIT: latin/hebrew ISO_8859-8:1988 8859-8 diff --git a/basis/io/encodings/8-bit/koi8-r/authors.txt b/basis/io/encodings/8-bit/koi8-r/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/koi8-r/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/koi8-r/koi8-r-docs.factor b/basis/io/encodings/8-bit/koi8-r/koi8-r-docs.factor new file mode 100644 index 0000000000..94e2652e2a --- /dev/null +++ b/basis/io/encodings/8-bit/koi8-r/koi8-r-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.koi8-r + +HELP: koi8-r +{ $var-description "KOI8-R is an 8-bit superset of ASCII which encodes the Cyrillic alphabet, as used in Russian and Bulgarian. Characters are in such an order that, if the eight bit is stripped, text is still interpretable as ASCII. Block-building characters also exist." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.koi8-r" "KOI8-R encoding" +"The " { $vocab-link "io.encodings.8-bit.koi8-r" } " vocabulary provides the " { $link koi8-r } " encoding." ; + +ABOUT: "io.encodings.8-bit.koi8-r" diff --git a/basis/io/encodings/8-bit/koi8-r/koi8-r.factor b/basis/io/encodings/8-bit/koi8-r/koi8-r.factor new file mode 100644 index 0000000000..6203fbd897 --- /dev/null +++ b/basis/io/encodings/8-bit/koi8-r/koi8-r.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.koi8-r + +8-BIT: koi8-r KOI8-R KOI8-R diff --git a/basis/io/encodings/8-bit/latin1/authors.txt b/basis/io/encodings/8-bit/latin1/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/latin1/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/latin1/latin1-docs.factor b/basis/io/encodings/8-bit/latin1/latin1-docs.factor new file mode 100644 index 0000000000..90bc0125a9 --- /dev/null +++ b/basis/io/encodings/8-bit/latin1/latin1-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.latin1 + +HELP: latin1 +{ $var-description "This is the ISO-8859-1 encoding, also called Latin-1: Western European. It is an 8-bit superset of ASCII which is the default for a mimetype starting with 'text' and provides the characters necessary for most western European languages." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.latin1" "Latin1 encoding" +"The " { $vocab-link "io.encodings.8-bit.latin1" } " vocabulary provides the " { $link latin1 } " encoding." ; + +ABOUT: "io.encodings.8-bit.latin1" diff --git a/basis/io/encodings/8-bit/latin1/latin1.factor b/basis/io/encodings/8-bit/latin1/latin1.factor new file mode 100644 index 0000000000..17a2941f74 --- /dev/null +++ b/basis/io/encodings/8-bit/latin1/latin1.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.latin1 + +8-BIT: latin1 ISO_8859-1:1987 8859-1 diff --git a/basis/io/encodings/8-bit/latin10/authors.txt b/basis/io/encodings/8-bit/latin10/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/latin10/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/latin10/latin10-docs.factor b/basis/io/encodings/8-bit/latin10/latin10-docs.factor new file mode 100644 index 0000000000..382b083a26 --- /dev/null +++ b/basis/io/encodings/8-bit/latin10/latin10-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.latin10 + +HELP: latin10 +{ $var-description "This is the ISO-8859-16 encoding, also called Latin-10: South-Eastern European. It is an 8-bit superset of ASCII." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.latin10" "Latin10 encoding" +"The " { $vocab-link "io.encodings.8-bit.latin10" } " vocabulary provides the " { $link latin10 } " encoding." ; + +ABOUT: "io.encodings.8-bit.latin10" diff --git a/basis/io/encodings/8-bit/latin10/latin10.factor b/basis/io/encodings/8-bit/latin10/latin10.factor new file mode 100644 index 0000000000..86831d4116 --- /dev/null +++ b/basis/io/encodings/8-bit/latin10/latin10.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.latin10 + +8-BIT: latin10 ISO-8859-16 8859-16 diff --git a/basis/io/encodings/8-bit/latin2/authors.txt b/basis/io/encodings/8-bit/latin2/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/latin2/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/latin2/latin2-docs.factor b/basis/io/encodings/8-bit/latin2/latin2-docs.factor new file mode 100644 index 0000000000..1da488fe6c --- /dev/null +++ b/basis/io/encodings/8-bit/latin2/latin2-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.latin2 + +HELP: latin2 +{ $var-description "This is the ISO-8859-2 encoding, also called Latin-2: Eastern European. It is an 8-bit superset of ASCII and provides the characters necessary for most eastern European languages." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.latin2" "Latin2 encoding" +"The " { $vocab-link "io.encodings.8-bit.latin2" } " vocabulary provides the " { $link latin2 } " encoding." ; + +ABOUT: "io.encodings.8-bit.latin2" diff --git a/basis/io/encodings/8-bit/latin2/latin2.factor b/basis/io/encodings/8-bit/latin2/latin2.factor new file mode 100644 index 0000000000..52ecc6460d --- /dev/null +++ b/basis/io/encodings/8-bit/latin2/latin2.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.latin2 + +8-BIT: latin2 ISO_8859-2:1987 8859-2 diff --git a/basis/io/encodings/8-bit/latin3/authors.txt b/basis/io/encodings/8-bit/latin3/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/latin3/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/latin3/latin3-docs.factor b/basis/io/encodings/8-bit/latin3/latin3-docs.factor new file mode 100644 index 0000000000..8cb719b890 --- /dev/null +++ b/basis/io/encodings/8-bit/latin3/latin3-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.latin3 + +HELP: latin3 +{ $var-description "This is the ISO-8859-3 encoding, also called Latin-3: South European. It is an 8-bit superset of ASCII and provides the characters necessary for Turkish, Maltese and Esperanto." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.latin3" "Latin3 encoding" +"The " { $vocab-link "io.encodings.8-bit.latin3" } " vocabulary provides the " { $link latin3 } " encoding." ; + +ABOUT: "io.encodings.8-bit.latin3" diff --git a/basis/io/encodings/8-bit/latin3/latin3.factor b/basis/io/encodings/8-bit/latin3/latin3.factor new file mode 100644 index 0000000000..a9a6333b02 --- /dev/null +++ b/basis/io/encodings/8-bit/latin3/latin3.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.latin3 + +8-BIT: latin3 ISO_8859-3:1988 8859-3 diff --git a/basis/io/encodings/8-bit/latin4/authors.txt b/basis/io/encodings/8-bit/latin4/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/latin4/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/latin4/latin4-docs.factor b/basis/io/encodings/8-bit/latin4/latin4-docs.factor new file mode 100644 index 0000000000..cfb53d23b6 --- /dev/null +++ b/basis/io/encodings/8-bit/latin4/latin4-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.latin4 + +HELP: latin4 +{ $description "This is the ISO-8859-4 encoding, also called Latin-4: North European. It is an 8-bit superset of ASCII and provides the characters necessary for Latvian, Lithuanian, Estonian, Greenlandic and Sami." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.latin4" "Latin4 encoding" +"The " { $vocab-link "io.encodings.8-bit.latin4" } " vocabulary provides the " { $link latin4 } " encoding." ; + +ABOUT: "io.encodings.8-bit.latin4" diff --git a/basis/io/encodings/8-bit/latin4/latin4.factor b/basis/io/encodings/8-bit/latin4/latin4.factor new file mode 100644 index 0000000000..34a68a8810 --- /dev/null +++ b/basis/io/encodings/8-bit/latin4/latin4.factor @@ -0,0 +1,7 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.latin4 + +8-BIT: latin4 ISO_8859-4:1988 8859-4 + diff --git a/basis/io/encodings/8-bit/latin5/authors.txt b/basis/io/encodings/8-bit/latin5/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/latin5/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/latin5/latin5-docs.factor b/basis/io/encodings/8-bit/latin5/latin5-docs.factor new file mode 100644 index 0000000000..60feed181c --- /dev/null +++ b/basis/io/encodings/8-bit/latin5/latin5-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.latin5 + +HELP: latin5 +{ $var-description "This is the ISO-8859-9 encoding, also called Latin-5: Turkish. It is an 8-bit superset of ASCII and provides the characters necessary for Turkish, similar to Latin-1 but replacing the spots used for Icelandic with characters used in Turkish." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.latin5" "Latin5 encoding" +"The " { $vocab-link "io.encodings.8-bit.latin5" } " vocabulary provides the " { $link latin5 } " encoding." ; + +ABOUT: "io.encodings.8-bit.latin5" diff --git a/basis/io/encodings/8-bit/latin5/latin5.factor b/basis/io/encodings/8-bit/latin5/latin5.factor new file mode 100644 index 0000000000..502c10fb2f --- /dev/null +++ b/basis/io/encodings/8-bit/latin5/latin5.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.latin5 + +8-BIT: latin5 ISO_8859-9:1989 8859-9 diff --git a/basis/io/encodings/8-bit/latin6/authors.txt b/basis/io/encodings/8-bit/latin6/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/latin6/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/latin6/latin6-docs.factor b/basis/io/encodings/8-bit/latin6/latin6-docs.factor new file mode 100644 index 0000000000..f1866c3ec1 --- /dev/null +++ b/basis/io/encodings/8-bit/latin6/latin6-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.latin6 + +HELP: latin6 +{ $var-description "This is the ISO-8859-10 encoding, also called Latin-6: Nordic. It is an 8-bit superset of ASCII containing the same characters as Latin-4, but rearranged to be of better use to nordic languages." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.latin6" "Latin6 encoding" +"The " { $vocab-link "io.encodings.8-bit.latin6" } " vocabulary provides the " { $link latin6 } " encoding." ; + +ABOUT: "io.encodings.8-bit.latin6" diff --git a/basis/io/encodings/8-bit/latin6/latin6.factor b/basis/io/encodings/8-bit/latin6/latin6.factor new file mode 100644 index 0000000000..5e71f75a2c --- /dev/null +++ b/basis/io/encodings/8-bit/latin6/latin6.factor @@ -0,0 +1,7 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.latin6 + +8-BIT: latin6 ISO-8859-10 8859-10 + diff --git a/basis/io/encodings/8-bit/latin7/authors.txt b/basis/io/encodings/8-bit/latin7/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/latin7/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/latin7/latin7-docs.factor b/basis/io/encodings/8-bit/latin7/latin7-docs.factor new file mode 100644 index 0000000000..ebd5eb6d97 --- /dev/null +++ b/basis/io/encodings/8-bit/latin7/latin7-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.latin7 + +HELP: latin7 +{ $var-description "This is the ISO-8859-13 encoding, also called Latin-7: Baltic Rim. It is an 8-bit superset of ASCII containing all characters necessary to represent Baltic Rim languages, as previous character sets were incomplete." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.latin7" "Latin7 encoding" +"The " { $vocab-link "io.encodings.8-bit.latin7" } " vocabulary provides the " { $link latin7 } " encoding." ; + +ABOUT: "io.encodings.8-bit.latin7" diff --git a/basis/io/encodings/8-bit/latin7/latin7.factor b/basis/io/encodings/8-bit/latin7/latin7.factor new file mode 100644 index 0000000000..862daaea08 --- /dev/null +++ b/basis/io/encodings/8-bit/latin7/latin7.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.latin7 + +8-BIT: latin7 ISO-8859-13 8859-13 diff --git a/basis/io/encodings/8-bit/latin8/authors.txt b/basis/io/encodings/8-bit/latin8/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/latin8/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/latin8/latin8-docs.factor b/basis/io/encodings/8-bit/latin8/latin8-docs.factor new file mode 100644 index 0000000000..5dc2f1e45d --- /dev/null +++ b/basis/io/encodings/8-bit/latin8/latin8-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.latin8 + +HELP: latin8 +{ $var-description "This is the ISO-8859-14 encoding, also called Latin-8: Celtic. It is an 8-bit superset of ASCII designed for Celtic languages like Gaelic and Breton." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.latin8" "Latin8 encoding" +"The " { $vocab-link "io.encodings.8-bit.latin8" } " vocabulary provides the " { $link latin8 } " encoding." ; + +ABOUT: "io.encodings.8-bit.latin8" diff --git a/basis/io/encodings/8-bit/latin8/latin8.factor b/basis/io/encodings/8-bit/latin8/latin8.factor new file mode 100644 index 0000000000..e925737e41 --- /dev/null +++ b/basis/io/encodings/8-bit/latin8/latin8.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.latin8 + +8-BIT: latin8 ISO-8859-14 8859-14 diff --git a/basis/io/encodings/8-bit/latin9/authors.txt b/basis/io/encodings/8-bit/latin9/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/latin9/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/latin9/latin9-docs.factor b/basis/io/encodings/8-bit/latin9/latin9-docs.factor new file mode 100644 index 0000000000..2416db382f --- /dev/null +++ b/basis/io/encodings/8-bit/latin9/latin9-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.latin9 + +HELP: latin9 +{ $var-description "This is the ISO-8859-15 encoding, also called Latin-9 and unoffically as Latin-0. It is an 8-bit superset of ASCII designed as a modification of Latin-1, removing little-used characters in favor of the Euro symbol and other characters." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.latin9" "Latin9 encoding" +"The " { $vocab-link "io.encodings.8-bit.latin9" } " vocabulary provides the " { $link latin9 } " encoding." ; + +ABOUT: "io.encodings.8-bit.latin9" diff --git a/basis/io/encodings/8-bit/latin9/latin9.factor b/basis/io/encodings/8-bit/latin9/latin9.factor new file mode 100644 index 0000000000..b55ecb30ee --- /dev/null +++ b/basis/io/encodings/8-bit/latin9/latin9.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.latin9 + +8-BIT: latin9 ISO-8859-15 8859-15 diff --git a/basis/io/encodings/8-bit/mac-roman/authors.txt b/basis/io/encodings/8-bit/mac-roman/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/mac-roman/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/mac-roman/mac-roman-docs.factor b/basis/io/encodings/8-bit/mac-roman/mac-roman-docs.factor new file mode 100644 index 0000000000..3fd00fa8a3 --- /dev/null +++ b/basis/io/encodings/8-bit/mac-roman/mac-roman-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.mac-roman + +HELP: mac-roman +{ $var-description "Mac Roman is an 8-bit superset of ASCII which was the standard encoding on Mac OS prior to version 10. It is incompatible with Latin-1 in all but a few places and ASCII, and it is suitable for encoding many Western European languages." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.mac-roman" "Mac Roman encoding" +"The " { $vocab-link "io.encodings.8-bit.mac-roman" } " vocabulary provides the " { $link mac-roman } " encoding." ; + +ABOUT: "io.encodings.8-bit.mac-roman" diff --git a/basis/io/encodings/8-bit/mac-roman/mac-roman.factor b/basis/io/encodings/8-bit/mac-roman/mac-roman.factor new file mode 100644 index 0000000000..0b707656e6 --- /dev/null +++ b/basis/io/encodings/8-bit/mac-roman/mac-roman.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.mac-roman + +8-BIT: mac-roman macintosh ROMAN diff --git a/basis/io/encodings/8-bit/thai/authors.txt b/basis/io/encodings/8-bit/thai/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/thai/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/thai/thai-docs.factor b/basis/io/encodings/8-bit/thai/thai-docs.factor new file mode 100644 index 0000000000..5d2640b6fd --- /dev/null +++ b/basis/io/encodings/8-bit/thai/thai-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.thai + +HELP: latin/thai +{ $var-description "This is the ISO-8859-11 encoding, also called Latin/Thai. It is an 8-bit superset of ASCII containing the characters necessary to represent Thai. It is basically identical to TIS-620." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.thai" "Thai encoding" +"The " { $vocab-link "io.encodings.8-bit.thai" } " vocabulary provides the " { $link latin/thai } " encoding." ; + +ABOUT: "io.encodings.8-bit.thai" diff --git a/basis/io/encodings/8-bit/thai/thai.factor b/basis/io/encodings/8-bit/thai/thai.factor new file mode 100644 index 0000000000..8d119f6309 --- /dev/null +++ b/basis/io/encodings/8-bit/thai/thai.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.thai + +8-BIT: latin/thai TIS-620 8859-11 diff --git a/basis/io/encodings/8-bit/windows-1250/authors.txt b/basis/io/encodings/8-bit/windows-1250/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1250/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/windows-1250/windows-1250.factor b/basis/io/encodings/8-bit/windows-1250/windows-1250.factor new file mode 100644 index 0000000000..745ebe4ade --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1250/windows-1250.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.windows-1250 + +8-BIT: windows-1250 windows-1250 CP1250 diff --git a/basis/io/encodings/8-bit/windows-1251/authors.txt b/basis/io/encodings/8-bit/windows-1251/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1251/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/windows-1251/windows-1251.factor b/basis/io/encodings/8-bit/windows-1251/windows-1251.factor new file mode 100644 index 0000000000..3c50d3c733 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1251/windows-1251.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.windows-1251 + +8-BIT: windows-1251 windows-1251 CP1251 diff --git a/basis/io/encodings/8-bit/windows-1252/authors.txt b/basis/io/encodings/8-bit/windows-1252/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1252/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/windows-1252/windows-1252-docs.factor b/basis/io/encodings/8-bit/windows-1252/windows-1252-docs.factor new file mode 100644 index 0000000000..cd9461e19d --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1252/windows-1252-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: io.encodings.8-bit.windows-1252 + +HELP: windows-1252 +{ $var-description "Windows 1252 is an 8-bit superset of ASCII which is closely related to Latin-1. Control characters in the 0x80 to 0x9F range are replaced with printable characters such as the Euro symbol." } +{ $see-also "encodings-introduction" } ; + +ARTICLE: "io.encodings.8-bit.windows-1252" "Windows 1252 encoding" +"The " { $vocab-link "io.encodings.8-bit.windows-1252" } " vocabulary provides the " { $link windows-1252 } " encoding." ; + +ABOUT: "io.encodings.8-bit.windows-1252" diff --git a/basis/io/encodings/8-bit/windows-1252/windows-1252.factor b/basis/io/encodings/8-bit/windows-1252/windows-1252.factor new file mode 100644 index 0000000000..ddcc4df7e2 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1252/windows-1252.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.windows-1252 + +8-BIT: windows-1252 windows-1252 CP1252 diff --git a/basis/io/encodings/8-bit/windows-1253/authors.txt b/basis/io/encodings/8-bit/windows-1253/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1253/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/windows-1253/windows-1253.factor b/basis/io/encodings/8-bit/windows-1253/windows-1253.factor new file mode 100644 index 0000000000..ba335be72e --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1253/windows-1253.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.windows-1253 + +8-BIT: windows-1253 windows-1253 CP1253 diff --git a/basis/io/encodings/8-bit/windows-1254/authors.txt b/basis/io/encodings/8-bit/windows-1254/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1254/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/windows-1254/windows-1254.factor b/basis/io/encodings/8-bit/windows-1254/windows-1254.factor new file mode 100644 index 0000000000..982d21a259 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1254/windows-1254.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.windows-1254 + +8-BIT: windows-1254 windows-1254 CP1254 diff --git a/basis/io/encodings/8-bit/windows-1255/authors.txt b/basis/io/encodings/8-bit/windows-1255/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1255/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/windows-1255/windows-1255.factor b/basis/io/encodings/8-bit/windows-1255/windows-1255.factor new file mode 100644 index 0000000000..952e5fe556 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1255/windows-1255.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.windows-1255 + +8-BIT: windows-1255 windows-1255 CP1255 diff --git a/basis/io/encodings/8-bit/windows-1256/authors.txt b/basis/io/encodings/8-bit/windows-1256/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1256/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/windows-1256/windows-1256.factor b/basis/io/encodings/8-bit/windows-1256/windows-1256.factor new file mode 100644 index 0000000000..303d25c461 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1256/windows-1256.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.windows-1256 + +8-BIT: windows-1256 windows-1256 CP1256 diff --git a/basis/io/encodings/8-bit/windows-1257/authors.txt b/basis/io/encodings/8-bit/windows-1257/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1257/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/windows-1257/windows-1257.factor b/basis/io/encodings/8-bit/windows-1257/windows-1257.factor new file mode 100644 index 0000000000..80b21e8d94 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1257/windows-1257.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.windows-1257 + +8-BIT: windows-1257 windows-1257 CP1257 diff --git a/basis/io/encodings/8-bit/windows-1258/authors.txt b/basis/io/encodings/8-bit/windows-1258/authors.txt new file mode 100644 index 0000000000..b4bd0e7b35 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1258/authors.txt @@ -0,0 +1 @@ +Doug Coleman \ No newline at end of file diff --git a/basis/io/encodings/8-bit/windows-1258/windows-1258.factor b/basis/io/encodings/8-bit/windows-1258/windows-1258.factor new file mode 100644 index 0000000000..1c7bf63540 --- /dev/null +++ b/basis/io/encodings/8-bit/windows-1258/windows-1258.factor @@ -0,0 +1,6 @@ +! Copyright (C) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.8-bit ; +IN: io.encodings.8-bit.windows-1258 + +8-BIT: windows-1258 windows-1258 CP1258 diff --git a/basis/io/encodings/iana/iana.factor b/basis/io/encodings/iana/iana.factor index 594e245a9c..a2a919da0d 100644 --- a/basis/io/encodings/iana/iana.factor +++ b/basis/io/encodings/iana/iana.factor @@ -57,4 +57,4 @@ e>n-table [ initial-e>n ] initialize ascii "ANSI_X3.4-1968" register-encoding utf16be "UTF-16BE" register-encoding utf16le "UTF-16LE" register-encoding -utf16 "UTF-16" register-encoding \ No newline at end of file +utf16 "UTF-16" register-encoding diff --git a/basis/io/encodings/iso2022/iso2022.factor b/basis/io/encodings/iso2022/iso2022.factor index 1726426777..7d4d7f1215 100644 --- a/basis/io/encodings/iso2022/iso2022.factor +++ b/basis/io/encodings/iso2022/iso2022.factor @@ -18,7 +18,7 @@ VALUE: jis212 "vocab:io/encodings/iso2022/212.txt" flat-file>biassoc to: jis212 VALUE: ascii -128 unique >biassoc to: ascii +128 iota unique >biassoc to: ascii TUPLE: iso2022-state type ; diff --git a/basis/io/files/info/unix/macosx/macosx.factor b/basis/io/files/info/unix/macosx/macosx.factor old mode 100755 new mode 100644 diff --git a/basis/io/files/info/unix/netbsd/netbsd.factor b/basis/io/files/info/unix/netbsd/netbsd.factor old mode 100755 new mode 100644 diff --git a/basis/io/files/info/unix/openbsd/openbsd.factor b/basis/io/files/info/unix/openbsd/openbsd.factor old mode 100755 new mode 100644 diff --git a/basis/io/files/info/unix/unix-docs.factor b/basis/io/files/info/unix/unix-docs.factor index 62837dae7e..7b98788226 100644 --- a/basis/io/files/info/unix/unix-docs.factor +++ b/basis/io/files/info/unix/unix-docs.factor @@ -4,6 +4,18 @@ USING: classes help.markup help.syntax io.streams.string strings math calendar io.files.info io.files.info.unix ; IN: io.files.unix +HELP: add-file-permissions +{ $values + { "path" "a pathname string" } + { "n" integer } } +{ $description "Ensures that the bits from " { $snippet "n" } " are set in the Unix file permissions for a given file." } ; + +HELP: remove-file-permissions +{ $values + { "path" "a pathname string" } + { "n" integer } } +{ $description "Ensures that the bits from " { $snippet "n" } " are cleared in the Unix file permissions for a given file." } ; + HELP: file-group-id { $values { "path" "a pathname string" } @@ -231,8 +243,12 @@ ARTICLE: "unix-file-permissions" "Unix file permissions" other-write? other-execute? } -"Writing all file permissions:" -{ $subsections set-file-permissions } +"Changing file permissions:" +{ $subsections + add-file-permissions + remove-file-permissions + set-file-permissions +} "Writing individual file permissions:" { $subsections set-uid diff --git a/basis/io/files/info/unix/unix.factor b/basis/io/files/info/unix/unix.factor index 0b52237a6d..eedf8de47a 100644 --- a/basis/io/files/info/unix/unix.factor +++ b/basis/io/files/info/unix/unix.factor @@ -5,7 +5,7 @@ sequences combinators combinators.short-circuit alien.c-types vocabs.loader calendar calendar.unix io.files.info io.files.types io.backend io.directories unix unix.stat unix.time unix.users unix.groups classes.struct -specialized-arrays ; +specialized-arrays literals ; SPECIALIZED-ARRAY: timeval IN: io.files.info.unix @@ -134,6 +134,9 @@ CONSTANT: OTHER-ALL OCT: 0000007 CONSTANT: OTHER-READ OCT: 0000004 CONSTANT: OTHER-WRITE OCT: 0000002 CONSTANT: OTHER-EXECUTE OCT: 0000001 +CONSTANT: ALL-READ OCT: 0000444 +CONSTANT: ALL-WRITE OCT: 0000222 +CONSTANT: ALL-EXECUTE OCT: 0000111 : uid? ( obj -- ? ) UID file-mode? ; : gid? ( obj -- ? ) GID file-mode? ; @@ -176,6 +179,12 @@ CONSTANT: OTHER-EXECUTE OCT: 0000001 : file-permissions ( path -- n ) normalize-path file-info permissions>> ; +: add-file-permissions ( path n -- ) + over file-permissions bitor set-file-permissions ; + +: remove-file-permissions ( path n -- ) + over file-permissions [ bitnot ] dip bitand set-file-permissions ; + M: unix copy-file-and-info ( from to -- ) [ copy-file ] [ swap file-permissions set-file-permissions ] 2bi ; diff --git a/basis/io/files/info/windows/windows-tests.factor b/basis/io/files/info/windows/windows-tests.factor old mode 100755 new mode 100644 diff --git a/basis/io/files/info/windows/windows.factor b/basis/io/files/info/windows/windows.factor old mode 100755 new mode 100644 index 5ae21fcfee..799b6dc4b2 --- a/basis/io/files/info/windows/windows.factor +++ b/basis/io/files/info/windows/windows.factor @@ -2,10 +2,11 @@ ! See http://factorcode.org/license.txt for BSD license. USING: byte-arrays math io.backend io.files.info io.files.windows io.files.windows.nt kernel windows.kernel32 -windows.time windows accessors alien.c-types combinators -generalizations system alien.strings io.encodings.utf16n -sequences splitting windows.errors fry continuations destructors -calendar ascii combinators.short-circuit locals classes.struct +windows.time windows.types windows accessors alien.c-types +combinators generalizations system alien.strings +io.encodings.utf16n sequences splitting windows.errors fry +continuations destructors calendar ascii +combinators.short-circuit locals classes.struct specialized-arrays alien.data ; SPECIALIZED-ARRAY: ushort IN: io.files.info.windows @@ -20,7 +21,7 @@ IN: io.files.info.windows TUPLE: windows-file-info < file-info attributes ; : get-compressed-file-size ( path -- n ) - "DWORD" [ GetCompressedFileSize ] keep + DWORD [ GetCompressedFileSize ] keep over INVALID_FILE_SIZE = [ win32-error-string throw ] [ @@ -100,9 +101,9 @@ M: windows link-info ( path -- info ) : volume-information ( normalized-path -- volume-name volume-serial max-component flags type ) MAX_PATH 1 + [ ] keep - "DWORD" - "DWORD" - "DWORD" + DWORD + DWORD + DWORD MAX_PATH 1 + [ ] keep [ GetVolumeInformation win32-error=0/f ] 7 nkeep drop 5 nrot drop @@ -110,9 +111,9 @@ M: windows link-info ( path -- info ) utf16n alien>string ; : file-system-space ( normalized-path -- available-space total-space free-space ) - "ULARGE_INTEGER" - "ULARGE_INTEGER" - "ULARGE_INTEGER" + ULARGE_INTEGER + ULARGE_INTEGER + ULARGE_INTEGER [ GetDiskFreeSpaceEx win32-error=0/f ] 3keep ; : calculate-file-system-info ( file-system-info -- file-system-info' ) @@ -151,13 +152,17 @@ PRIVATE> M: winnt file-system-info ( path -- file-system-info ) normalize-path root-directory (file-system-info) ; -: volume>paths ( string -- array ) - 16384 tuck dup length - 0 dup [ GetVolumePathNamesForVolumeName 0 = ] dip swap [ - win32-error-string throw +:: volume>paths ( string -- array ) + 16384 :> names-buf-length + names-buf-length :> names + 0 :> names-length + + string names names-buf-length names-length GetVolumePathNamesForVolumeName :> ret + ret 0 = [ + ret win32-error-string throw ] [ - *uint "ushort" heap-size * head - utf16n alien>string CHAR: \0 split + names names-length *uint ushort heap-size * head + utf16n alien>string { CHAR: \0 } split ] if ; : find-first-volume ( -- string handle ) @@ -166,13 +171,16 @@ M: winnt file-system-info ( path -- file-system-info ) FindFirstVolume dup win32-error=0/f [ utf16n alien>string ] dip ; -: find-next-volume ( handle -- string/f ) - MAX_PATH 1 + [ tuck ] keep - FindNextVolume 0 = [ +:: find-next-volume ( handle -- string/f ) + MAX_PATH 1 + :> buf-length + buf-length :> buf + + handle buf buf-length FindNextVolume :> ret + ret 0 = [ GetLastError ERROR_NO_MORE_FILES = - [ drop f ] [ win32-error-string throw ] if + [ f ] [ win32-error-string throw ] if ] [ - utf16n alien>string + buf utf16n alien>string ] if ; : find-volumes ( -- array ) diff --git a/basis/io/files/links/unix/unix-tests.factor b/basis/io/files/links/unix/unix-tests.factor index ef7d778abe..23de95f519 100644 --- a/basis/io/files/links/unix/unix-tests.factor +++ b/basis/io/files/links/unix/unix-tests.factor @@ -4,7 +4,7 @@ io.pathnames namespaces ; IN: io.files.links.unix.tests : make-test-links ( n path -- ) - [ '[ [ 1 + ] keep [ number>string _ prepend ] bi@ make-link ] each ] + [ '[ [ 1 + ] keep [ number>string _ prepend ] bi@ make-link ] each-integer ] [ [ number>string ] dip prepend touch-file ] 2bi ; inline [ t ] [ diff --git a/basis/io/files/unique/unique.factor b/basis/io/files/unique/unique.factor index f167b1e99b..07f7b25140 100644 --- a/basis/io/files/unique/unique.factor +++ b/basis/io/files/unique/unique.factor @@ -35,8 +35,8 @@ SYMBOL: unique-retries : random-name ( -- string ) unique-length get [ random-ch ] "" replicate-as ; -: retry ( quot: ( -- ? ) n -- ) - swap [ drop ] prepose attempt-all ; inline +: retry ( quot: ( -- ? ) n -- ) + iota swap [ drop ] prepose attempt-all ; inline : (make-unique-file) ( path prefix suffix -- path ) '[ diff --git a/basis/io/files/windows/nt/nt.factor b/basis/io/files/windows/nt/nt.factor old mode 100755 new mode 100644 diff --git a/basis/io/files/windows/windows.factor b/basis/io/files/windows/windows.factor old mode 100755 new mode 100644 index ca5c9b3c4a..c4c848cb64 --- a/basis/io/files/windows/windows.factor +++ b/basis/io/files/windows/windows.factor @@ -3,10 +3,10 @@ USING: alien.c-types io.binary io.backend io.files io.files.types io.buffers io.encodings.utf16n io.ports io.backend.windows kernel math splitting fry alien.strings -windows windows.kernel32 windows.time calendar combinators -math.functions sequences namespaces make words system -destructors accessors math.bitwise continuations windows.errors -arrays byte-arrays generalizations alien.data ; +windows windows.kernel32 windows.time windows.types calendar +combinators math.functions sequences namespaces make words +system destructors accessors math.bitwise continuations +windows.errors arrays byte-arrays generalizations alien.data ; IN: io.files.windows : open-file ( path access-mode create-mode flags -- handle ) @@ -64,7 +64,7 @@ C: FileArgs [ handle>> handle>> ] [ buffer>> ] [ buffer>> buffer-length ] - [ drop "DWORD" ] + [ drop DWORD ] [ FileArgs-overlapped ] } cleave ; diff --git a/basis/io/launcher/launcher.factor b/basis/io/launcher/launcher.factor old mode 100755 new mode 100644 index 34325780c0..cb20f78a33 --- a/basis/io/launcher/launcher.factor +++ b/basis/io/launcher/launcher.factor @@ -75,15 +75,13 @@ SYMBOL: wait-flag [ H{ } clone processes set-global start-wait-thread -] "io.launcher" add-init-hook +] "io.launcher" add-startup-hook : process-started ( process handle -- ) >>handle V{ } clone swap processes get set-at wait-flag get-global raise-flag ; -M: process hashcode* handle>> hashcode* ; - : pass-environment? ( process -- ? ) dup environment>> assoc-empty? not swap environment-mode>> +replace-environment+ eq? or ; diff --git a/basis/io/launcher/unix/unix-tests.factor b/basis/io/launcher/unix/unix-tests.factor index 7fa7f4b2c6..4304f5f62a 100644 --- a/basis/io/launcher/unix/unix-tests.factor +++ b/basis/io/launcher/unix/unix-tests.factor @@ -3,7 +3,7 @@ USING: io.files io.files.temp io.directories io.pathnames tools.test io.launcher arrays io namespaces continuations math io.encodings.binary io.encodings.ascii accessors kernel sequences io.encodings.utf8 destructors io.streams.duplex locals -concurrency.promises threads unix.process ; +concurrency.promises threads unix.process calendar ; [ ] [ [ "launcher-test-1" temp-file delete-file ] ignore-errors @@ -128,12 +128,13 @@ concurrency.promises threads unix.process ; [let :> p :> s + [ "sleep 1000" run-detached [ p fulfill ] [ wait-for-process s fulfill ] bi ] in-thread - p ?promise handle>> 9 kill drop + p 1 seconds ?promise-timeout handle>> 9 kill drop s ?promise 0 = ] ] unit-test diff --git a/basis/io/launcher/windows/nt/nt-tests.factor b/basis/io/launcher/windows/nt/nt-tests.factor old mode 100755 new mode 100644 diff --git a/basis/io/launcher/windows/nt/nt.factor b/basis/io/launcher/windows/nt/nt.factor old mode 100755 new mode 100644 diff --git a/basis/io/launcher/windows/windows.factor b/basis/io/launcher/windows/windows.factor old mode 100755 new mode 100644 index 6cae50bd9e..8a800115f6 --- a/basis/io/launcher/windows/windows.factor +++ b/basis/io/launcher/windows/windows.factor @@ -132,7 +132,7 @@ M: windows run-process* ( process -- handle ) current-directory get absolute-path cd dup make-CreateProcess-args - tuck fill-redirection + [ fill-redirection ] keep dup call-CreateProcess lpProcessInformation>> ] with-destructors ; diff --git a/basis/io/mmap/mmap-docs.factor b/basis/io/mmap/mmap-docs.factor index 33ba6850a5..3eabfc4e7f 100644 --- a/basis/io/mmap/mmap-docs.factor +++ b/basis/io/mmap/mmap-docs.factor @@ -87,7 +87,6 @@ ARTICLE: "io.mmap.examples" "Memory-mapped file examples" "Normalize a file containing packed quadrupes of floats:" { $code "USING: kernel io.mmap math.vectors math.vectors.simd" "sequences specialized-arrays ;" - "SIMD: float" "SPECIALIZED-ARRAY: float-4" "" "\"mydata.dat\" float-4 [" diff --git a/basis/io/monitors/windows/nt/nt.factor b/basis/io/monitors/windows/nt/nt.factor old mode 100755 new mode 100644 diff --git a/basis/io/pipes/windows/nt/nt.factor b/basis/io/pipes/windows/nt/nt.factor index cec03cf6d3..7fce8b4de2 100644 --- a/basis/io/pipes/windows/nt/nt.factor +++ b/basis/io/pipes/windows/nt/nt.factor @@ -35,7 +35,7 @@ IN: io.pipes.windows.nt "-" % 32 random-bits # "-" % - micros # + nano-count # ] "" make ; M: winnt (pipe) ( -- pipe ) diff --git a/basis/io/ports/ports.factor b/basis/io/ports/ports.factor index 3ea4c105f5..727d69adf8 100644 --- a/basis/io/ports/ports.factor +++ b/basis/io/ports/ports.factor @@ -27,7 +27,7 @@ TUPLE: buffered-port < port { buffer buffer } ; TUPLE: input-port < buffered-port ; -M: input-port stream-element-type drop +byte+ ; +M: input-port stream-element-type drop +byte+ ; inline : ( handle -- input-port ) input-port ; @@ -104,7 +104,7 @@ TUPLE: output-port < buffered-port ; [ nip ] [ buffer>> buffer-capacity <= ] 2bi [ drop ] [ stream-flush ] if ; inline -M: output-port stream-element-type stream>> stream-element-type ; +M: output-port stream-element-type stream>> stream-element-type ; inline M: output-port stream-write1 dup check-disposed diff --git a/basis/io/servers/connection/connection.factor b/basis/io/servers/connection/connection.factor index 345b739b61..fdd42352da 100644 --- a/basis/io/servers/connection/connection.factor +++ b/basis/io/servers/connection/connection.factor @@ -96,7 +96,7 @@ M: threaded-server handle-client* handler>> call( -- ) ; [ [ accept-connection ] with-semaphore ] [ accept-connection ] if* - ] [ accept-loop ] bi ; inline recursive + ] [ accept-loop ] bi ; : started-accept-loop ( threaded-server -- ) threaded-server get diff --git a/basis/io/servers/packet/packet.factor b/basis/io/servers/packet/packet.factor deleted file mode 100644 index 2a346b4d13..0000000000 --- a/basis/io/servers/packet/packet.factor +++ /dev/null @@ -1,23 +0,0 @@ -USING: concurrency.combinators destructors fry -io.sockets kernel logging ; -IN: io.servers.packet - - [ datagram-loop ] with-disposal ; inline - -\ spawn-datagrams NOTICE add-input-logging - -PRIVATE> - -: with-datagrams ( seq service quot -- ) - '[ [ [ _ ] dip spawn-datagrams ] parallel-each ] with-logging ; inline diff --git a/basis/io/servers/packet/summary.txt b/basis/io/servers/packet/summary.txt deleted file mode 100644 index 29247a2937..0000000000 --- a/basis/io/servers/packet/summary.txt +++ /dev/null @@ -1 +0,0 @@ -Multi-threaded UDP/IP servers diff --git a/basis/io/servers/packet/tags.txt b/basis/io/servers/packet/tags.txt deleted file mode 100644 index 992ae12982..0000000000 --- a/basis/io/servers/packet/tags.txt +++ /dev/null @@ -1 +0,0 @@ -network diff --git a/basis/io/sockets/secure/openssl/openssl.factor b/basis/io/sockets/secure/openssl/openssl.factor index 12f907acb5..b3cf28a497 100644 --- a/basis/io/sockets/secure/openssl/openssl.factor +++ b/basis/io/sockets/secure/openssl/openssl.factor @@ -5,7 +5,7 @@ math.order combinators init alien alien.c-types alien.data alien.strings libc continuations destructors summary splitting assocs random math.parser locals unicode.case openssl openssl.libcrypto openssl.libssl io.backend io.ports io.pathnames -io.encodings.8-bit io.timeouts io.sockets.secure ; +io.encodings.8-bit.latin1 io.timeouts io.sockets.secure ; IN: io.sockets.secure.openssl GENERIC: ssl-method ( symbol -- method ) diff --git a/basis/io/sockets/sockets-docs.factor b/basis/io/sockets/sockets-docs.factor index fb8332dffb..8cc6ef731d 100644 --- a/basis/io/sockets/sockets-docs.factor +++ b/basis/io/sockets/sockets-docs.factor @@ -155,7 +155,7 @@ HELP: with-client HELP: { $values { "addrspec" "an address specifier" } { "encoding" "an encoding descriptor" } { "server" "a handle" } } { $description - "Begins listening for network connections to a local address. Server objects responds to two words:" + "Begins listening for network connections to a local address. Server objects respond to two words:" { $list { { $link dispose } " - stops listening on the port and frees all associated resources" } { { $link accept } " - blocks until there is a connection, and returns a stream of the encoding passed to the constructor" } diff --git a/basis/io/sockets/sockets-tests.factor b/basis/io/sockets/sockets-tests.factor old mode 100755 new mode 100644 diff --git a/basis/io/sockets/sockets.factor b/basis/io/sockets/sockets.factor old mode 100755 new mode 100644 diff --git a/basis/io/sockets/unix/unix.factor b/basis/io/sockets/unix/unix.factor old mode 100755 new mode 100644 index 6bf62a034e..cdf7e54408 --- a/basis/io/sockets/unix/unix.factor +++ b/basis/io/sockets/unix/unix.factor @@ -17,7 +17,7 @@ IN: io.sockets.unix 0 socket dup io-error init-fd |dispose ; : set-socket-option ( fd level opt -- ) - [ handle-fd ] 2dip 1 "int" heap-size setsockopt io-error ; + [ handle-fd ] 2dip 1 dup byte-length setsockopt io-error ; M: unix addrinfo-error ( n -- ) [ gai_strerror throw ] unless-zero ; @@ -117,7 +117,7 @@ SYMBOL: receive-buffer CONSTANT: packet-size 65536 -[ packet-size malloc receive-buffer set-global ] "io.sockets.unix" add-init-hook +[ packet-size malloc &free receive-buffer set-global ] "io.sockets.unix" add-startup-hook :: do-receive ( port -- packet sockaddr ) port addr>> empty-sockaddr/size :> ( sockaddr len ) diff --git a/basis/io/sockets/windows/nt/nt.factor b/basis/io/sockets/windows/nt/nt.factor old mode 100755 new mode 100644 index 7cc21c9611..0dd85954ac --- a/basis/io/sockets/windows/nt/nt.factor +++ b/basis/io/sockets/windows/nt/nt.factor @@ -3,7 +3,8 @@ continuations destructors io.ports io.timeouts io.sockets io.sockets.private io namespaces io.streams.duplex io.backend.windows io.sockets.windows io.backend.windows.nt windows.winsock kernel libc math sequences threads system -combinators accessors classes.struct windows.kernel32 ; +combinators accessors classes.struct windows.kernel32 +windows.types ; IN: io.sockets.windows.nt : malloc-int ( n -- alien ) @@ -16,10 +17,10 @@ M: winnt WSASocket-flags ( -- DWORD ) SIO_GET_EXTENSION_FUNCTION_POINTER WSAID_CONNECTEX GUID heap-size - "void*" + void* [ - "void*" heap-size - "DWORD" + void* heap-size + DWORD f f WSAIoctl SOCKET_ERROR = [ diff --git a/basis/io/sockets/windows/windows.factor b/basis/io/sockets/windows/windows.factor old mode 100755 new mode 100644 diff --git a/basis/io/streams/limited/limited-docs.factor b/basis/io/streams/limited/limited-docs.factor old mode 100755 new mode 100644 diff --git a/basis/io/streams/limited/limited-tests.factor b/basis/io/streams/limited/limited-tests.factor index 022d20eb5e..047cd117a0 100644 --- a/basis/io/streams/limited/limited-tests.factor +++ b/basis/io/streams/limited/limited-tests.factor @@ -1,8 +1,9 @@ USING: accessors continuations destructors io io.encodings -io.encodings.8-bit io.encodings.ascii io.encodings.binary +io.encodings.ascii io.encodings.binary io.encodings.string io.encodings.utf8 io.files io.pipes io.streams.byte-array io.streams.limited io.streams.string -kernel namespaces strings tools.test system ; +kernel namespaces strings tools.test system +io.encodings.8-bit.latin1 ; IN: io.streams.limited.tests [ ] [ diff --git a/basis/io/streams/limited/limited.factor b/basis/io/streams/limited/limited.factor old mode 100755 new mode 100644 diff --git a/basis/io/styles/styles-docs.factor b/basis/io/styles/styles-docs.factor old mode 100755 new mode 100644 diff --git a/basis/io/thread/thread.factor b/basis/io/thread/thread.factor index 88db135f44..994dcd9c50 100644 --- a/basis/io/thread/thread.factor +++ b/basis/io/thread/thread.factor @@ -17,4 +17,4 @@ SYMBOL: io-thread-running? [ t io-thread-running? set-global start-io-thread -] "io.thread" add-init-hook +] "io.thread" add-startup-hook diff --git a/basis/io/timeouts/timeouts.factor b/basis/io/timeouts/timeouts.factor old mode 100755 new mode 100644 diff --git a/basis/iokit/hid/hid.factor b/basis/iokit/hid/hid.factor index b3894d7b49..ca339a78ef 100644 --- a/basis/iokit/hid/hid.factor +++ b/basis/iokit/hid/hid.factor @@ -1,7 +1,7 @@ USING: iokit alien alien.syntax alien.c-types kernel system core-foundation core-foundation.arrays core-foundation.data core-foundation.dictionaries core-foundation.run-loop -core-foundation.strings core-foundation.time ; +core-foundation.strings core-foundation.time unix.types ; IN: iokit.hid CONSTANT: kIOHIDDeviceKey "IOHIDDevice" diff --git a/basis/iokit/iokit.factor b/basis/iokit/iokit.factor old mode 100755 new mode 100644 index 529db6bf78..2b31e5c8a8 --- a/basis/iokit/iokit.factor +++ b/basis/iokit/iokit.factor @@ -1,6 +1,6 @@ USING: alien.syntax alien.c-types core-foundation core-foundation.bundles core-foundation.dictionaries system -combinators kernel sequences io accessors ; +combinators kernel sequences io accessors unix.types ; IN: iokit << @@ -99,19 +99,6 @@ CONSTANT: kOSBuildVersionKey "OS Build Version" CONSTANT: kNilOptions 0 -TYPEDEF: uint mach_port_t -TYPEDEF: int kern_return_t -TYPEDEF: int boolean_t -TYPEDEF: mach_port_t io_object_t -TYPEDEF: io_object_t io_iterator_t -TYPEDEF: io_object_t io_registry_entry_t -TYPEDEF: io_object_t io_service_t -TYPEDEF: char[128] io_name_t -TYPEDEF: char[512] io_string_t -TYPEDEF: kern_return_t IOReturn - -TYPEDEF: uint IOOptionBits - CONSTANT: MACH_PORT_NULL 0 CONSTANT: KERN_SUCCESS 0 diff --git a/basis/json/reader/reader-tests.factor b/basis/json/reader/reader-tests.factor index 79a0e4b5af..390fce1f94 100644 --- a/basis/json/reader/reader-tests.factor +++ b/basis/json/reader/reader-tests.factor @@ -1,4 +1,4 @@ -USING: arrays json.reader kernel strings tools.test +USING: assocs arrays json.reader kernel strings tools.test hashtables json ; IN: json.reader.tests @@ -58,3 +58,6 @@ IN: json.reader.tests { 0 } [ " 0" json> ] unit-test { 0 } [ "0 " json> ] unit-test { 0 } [ " 0 " json> ] unit-test + +! empty objects are allowed as values in objects +{ H{ { "foo" H{ } } } } [ "{ \"foo\" : {}}" json> ] unit-test diff --git a/basis/json/reader/reader.factor b/basis/json/reader/reader.factor index bdfeaa3e51..082bbd8446 100644 --- a/basis/json/reader/reader.factor +++ b/basis/json/reader/reader.factor @@ -15,7 +15,7 @@ IN: json.reader ] dip ; DEFER: j-string - + : convert-string ( str -- str ) read1 { @@ -30,17 +30,17 @@ DEFER: j-string dup [ 1string append j-string append ] [ drop ] if ; - + : j-string ( -- str ) "\\\"" read-until CHAR: \" = [ convert-string ] unless ; - + : second-last ( seq -- second-last ) [ length 2 - ] keep nth ; inline : third-last ( seq -- third-last ) [ length 3 - ] keep nth ; inline - + : last2 ( seq -- second-last last ) [ second-last ] [ last ] bi ; inline @@ -68,12 +68,12 @@ DEFER: j-string dup pop >array over push ; : (close-hash) ( accum -- accum' ) - dup length 3 >= [ v-over-push ] when - dup dup [ pop ] dip pop swap + dup [ length 3 >= ] [ last V{ } = not ] bi@ and [ v-over-push ] when + dup dup [ pop ] bi@ swap zip H{ } assoc-clone-like over push ; - + : scan ( accum char -- accum ) - ! 2dup . . ! Great for debug... + ! 2dup 1string swap . . ! Great for debug... [ { { CHAR: \" [ j-string over push ] } @@ -91,13 +91,13 @@ DEFER: j-string { CHAR: f [ 4 read drop f over push ] } { CHAR: n [ 3 read drop json-null over push ] } [ value [ over push ] dip [ scan ] when* ] - } case + } case ] when* ; : (json-parser>) ( string -- object ) [ V{ } clone [ read1 dup ] [ scan ] while drop first ] with-string-reader ; - + PRIVATE> - + : json> ( string -- object ) (json-parser>) ; diff --git a/basis/lcs/diff2html/diff2html-tests.factor b/basis/lcs/diff2html/diff2html-tests.factor index 0c2ed34f45..2ee662c0ac 100644 --- a/basis/lcs/diff2html/diff2html-tests.factor +++ b/basis/lcs/diff2html/diff2html-tests.factor @@ -3,4 +3,4 @@ USING: lcs.diff2html lcs kernel tools.test strings sequences xml.writer ; IN: lcs.diff2html.tests -[ ] [ "hello" "heyo" [ 1string ] { } map-as diff htmlize-diff xml>string drop ] unit-test +[ ] [ "hello" "heyo" [ [ 1string ] { } map-as ] bi@ diff htmlize-diff xml>string drop ] unit-test diff --git a/basis/lcs/diff2html/diff2html.factor b/basis/lcs/diff2html/diff2html.factor index ca9e48eb05..545610a0ea 100644 --- a/basis/lcs/diff2html/diff2html.factor +++ b/basis/lcs/diff2html/diff2html.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: lcs xml.syntax xml.writer kernel strings ; FROM: accessors => item>> ; diff --git a/basis/lcs/lcs.factor b/basis/lcs/lcs.factor index 38920f5764..5861d90dc3 100644 --- a/basis/lcs/lcs.factor +++ b/basis/lcs/lcs.factor @@ -19,15 +19,15 @@ IN: lcs i 1 + j 1 + matrix nth set-nth ; inline : lcs-initialize ( |str1| |str2| -- matrix ) - [ drop 0 ] with map ; + iota [ drop 0 ] with map ; : levenshtein-initialize ( |str1| |str2| -- matrix ) - [ [ + ] curry map ] with map ; + [ iota ] bi@ [ [ + ] curry map ] with map ; :: run-lcs ( old new init step -- matrix ) old length 1 + new length 1 + init call :> matrix - old length [| i | - new length + old length iota [| i | + new length iota [| j | i j matrix old new step loop-step ] each ] each matrix ; inline PRIVATE> diff --git a/basis/lists/lazy/lazy-tests.factor b/basis/lists/lazy/lazy-tests.factor index 8fb638b856..39f92158a6 100644 --- a/basis/lists/lazy/lazy-tests.factor +++ b/basis/lists/lazy/lazy-tests.factor @@ -35,5 +35,7 @@ IN: lists.lazy.tests [ [ drop ] leach ] must-infer [ lnth ] must-infer +[ { 1 2 3 } ] [ { 1 2 3 4 5 } >list [ 2 > ] luntil list>array ] unit-test + [ ] [ "resource:license.txt" utf8 llines list>array drop ] unit-test [ ] [ "resource:license.txt" utf8 lcontents list>array drop ] unit-test diff --git a/basis/lists/lazy/lazy.factor b/basis/lists/lazy/lazy.factor index 7b386e9c81..122a2205dd 100644 --- a/basis/lists/lazy/lazy.factor +++ b/basis/lists/lazy/lazy.factor @@ -111,14 +111,15 @@ C: lazy-until over nil? [ drop ] [ ] if ; M: lazy-until car ( lazy-until -- car ) - cons>> car ; + cons>> car ; M: lazy-until cdr ( lazy-until -- cdr ) - [ cons>> unswons ] keep quot>> tuck call( elt -- ? ) - [ 2drop nil ] [ luntil ] if ; + [ [ cons>> cdr ] [ quot>> ] bi ] + [ [ cons>> car ] [ quot>> ] bi call( elt -- ? ) ] bi + [ 2drop nil ] [ luntil ] if ; M: lazy-until nil? ( lazy-until -- ? ) - drop f ; + drop f ; TUPLE: lazy-while cons quot ; @@ -128,13 +129,13 @@ C: lazy-while over nil? [ drop ] [ ] if ; M: lazy-while car ( lazy-while -- car ) - cons>> car ; + cons>> car ; M: lazy-while cdr ( lazy-while -- cdr ) - [ cons>> cdr ] keep quot>> lwhile ; + [ cons>> cdr ] keep quot>> lwhile ; M: lazy-while nil? ( lazy-while -- ? ) - [ car ] keep quot>> call( elt -- ? ) not ; + [ car ] keep quot>> call( elt -- ? ) not ; TUPLE: lazy-filter cons quot ; diff --git a/basis/lists/lists-docs.factor b/basis/lists/lists-docs.factor index 7fba57a4bb..53fde94687 100644 --- a/basis/lists/lists-docs.factor +++ b/basis/lists/lists-docs.factor @@ -44,7 +44,6 @@ ARTICLE: { "lists" "combinators" } "Combinators for lists" foldl foldr lmap>array - traverse } ; ARTICLE: { "lists" "manipulation" } "Manipulating lists" @@ -151,12 +150,6 @@ HELP: list>array { $values { "list" list } { "array" array } } { $description "Convert a list into an array." } ; -HELP: traverse -{ $values { "list" list } { "pred" { $quotation "( list/elt -- ? )" } } - { "quot" { $quotation "( list/elt -- result)" } } { "result" "a new cons object" } } -{ $description "Recursively traverses the list object, replacing any elements (which can themselves be sublists) that pred" - " returns true for with the result of applying quot to." } ; - HELP: list { $class-description "The class of lists. All lists are expected to conform to " { $link { "lists" "protocol" } } "." } ; diff --git a/basis/lists/lists.factor b/basis/lists/lists.factor index ddf1ab9109..f3475f960b 100644 --- a/basis/lists/lists.factor +++ b/basis/lists/lists.factor @@ -93,11 +93,5 @@ PRIVATE> : list>array ( list -- array ) [ ] lmap>array ; -:: traverse ( list pred quot: ( list/elt -- result ) -- result ) - list [| elt | - elt dup pred call [ quot call ] when - dup list? [ pred quot traverse ] when - ] lmap ; inline recursive - INSTANCE: cons list INSTANCE: +nil+ list diff --git a/basis/literals/literals-tests.factor b/basis/literals/literals-tests.factor old mode 100755 new mode 100644 diff --git a/basis/literals/literals.factor b/basis/literals/literals.factor old mode 100755 new mode 100644 diff --git a/basis/locals/fry/fry.factor b/basis/locals/fry/fry.factor index ff6a491a79..a2a1a6c178 100644 --- a/basis/locals/fry/fry.factor +++ b/basis/locals/fry/fry.factor @@ -1,18 +1,21 @@ ! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos. ! See http://factorcode.org/license.txt for BSD license. USING: accessors fry fry.private generalizations kernel -locals.types make sequences ; +locals.types sequences ; IN: locals.fry ! Support for mixing locals with fry M: let count-inputs body>> count-inputs ; - M: lambda count-inputs body>> count-inputs ; -M: lambda deep-fry - clone [ shallow-fry swap ] change-body - [ [ vars>> length ] keep '[ _ _ mnswap @ ] , ] [ drop [ncurry] % ] 2bi ; +M: lambda fry + clone [ [ count-inputs ] [ fry ] bi ] change-body + [ [ vars>> length ] keep '[ _ _ mnswap _ call ] ] + [ drop [ncurry] curry [ call ] compose ] 2bi ; -M: let deep-fry - clone [ fry '[ @ call ] ] change-body , ; +M: let fry + clone [ fry ] change-body ; + +INSTANCE: lambda fried +INSTANCE: let fried diff --git a/basis/locals/locals-tests.factor b/basis/locals/locals-tests.factor index 581ed5de33..7aa8032cdd 100644 --- a/basis/locals/locals-tests.factor +++ b/basis/locals/locals-tests.factor @@ -389,7 +389,7 @@ M:: integer lambda-method-forget-test ( a -- b ) a ; eval( -- ) call ] [ error>> >r/r>-in-fry-error? ] must-fail-with -:: (funny-macro-test) ( obj quot -- ? ) obj { quot } 1&& ; inline +:: (funny-macro-test) ( obj quot -- ? ) obj { [ quot call ] } 1&& ; inline : funny-macro-test ( n -- ? ) [ odd? ] (funny-macro-test) ; \ funny-macro-test def>> must-infer diff --git a/basis/locals/macros/macros.factor b/basis/locals/macros/macros.factor index e64693f2a3..1f9525e5eb 100644 --- a/basis/locals/macros/macros.factor +++ b/basis/locals/macros/macros.factor @@ -14,4 +14,4 @@ M: let expand-macros* expand-macros literal ; M: lambda condomize? drop t ; -M: lambda condomize '[ @ ] ; +M: lambda condomize [ call ] curry ; diff --git a/basis/locals/rewrite/point-free/point-free.factor b/basis/locals/rewrite/point-free/point-free.factor old mode 100755 new mode 100644 diff --git a/basis/locals/rewrite/sugar/sugar.factor b/basis/locals/rewrite/sugar/sugar.factor old mode 100755 new mode 100644 diff --git a/basis/logging/server/server.factor b/basis/logging/server/server.factor index 848ad5d40e..f5539b2813 100644 --- a/basis/logging/server/server.factor +++ b/basis/logging/server/server.factor @@ -106,4 +106,4 @@ CONSTANT: keep-logs 10 [ H{ } clone log-files set-global log-server -] "logging" add-init-hook +] "logging" add-startup-hook diff --git a/basis/macros/expander/expander.factor b/basis/macros/expander/expander.factor index 25f754e92a..3dab0c3cdb 100644 --- a/basis/macros/expander/expander.factor +++ b/basis/macros/expander/expander.factor @@ -49,7 +49,7 @@ M: wrapper expand-macros* wrapped>> literal ; stack get pop end [ [ expand-macros ] [ ] map-as '[ _ dip ] % ] [ - length [ ] keep + length iota [ ] keep [ '[ _ ndrop _ nnip call ] [ ] like ] 2map , \ dispatch , ] bi ; diff --git a/basis/macros/macros-docs.factor b/basis/macros/macros-docs.factor old mode 100755 new mode 100644 diff --git a/basis/macros/macros.factor b/basis/macros/macros.factor index 0e5ef30f51..0186f6181f 100644 --- a/basis/macros/macros.factor +++ b/basis/macros/macros.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2007, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: parser kernel sequences words effects combinators assocs -definitions quotations namespaces memoize accessors ; +definitions quotations namespaces memoize accessors +compiler.units ; IN: macros : n*V+V ( alpha x y -- alpha*x+y ) clone n*V+V! ; inline : n*V ( alpha x -- alpha*x ) clone n*V! ; inline -: V+ ( x y -- x+y ) - 1.0 -rot n*V+V ; inline -: V- ( x y -- x-y ) - -1.0 spin n*V+V ; inline +:: V+ ( x y -- x+y ) + 1.0 x y n*V+V ; inline +:: V- ( x y -- x-y ) + -1.0 y x n*V+V ; inline : Vneg ( x -- -x ) -1.0 swap n*V ; inline @@ -117,7 +117,7 @@ M: blas-vector-base equal? M: blas-vector-base length length>> ; -M: blas-vector-base virtual-seq +M: blas-vector-base virtual-exemplar (blas-direct-array) ; M: blas-vector-base virtual@ [ inc>> * ] [ nip (blas-direct-array) ] 2bi ; diff --git a/basis/math/combinatorics/combinatorics-docs.factor b/basis/math/combinatorics/combinatorics-docs.factor index 10584f2004..ec3cd6ee76 100644 --- a/basis/math/combinatorics/combinatorics-docs.factor +++ b/basis/math/combinatorics/combinatorics-docs.factor @@ -31,7 +31,7 @@ HELP: permutation { $notes "Permutations are 0-based and a bounds error will be thrown if " { $snippet "n" } " is larger than " { $snippet "seq length factorial 1 -" } "." } { $examples { $example "USING: math.combinatorics prettyprint ;" - "1 3 permutation ." "{ 0 2 1 }" } + "1 { 0 1 2 } permutation ." "{ 0 2 1 }" } { $example "USING: math.combinatorics prettyprint ;" "5 { \"apple\" \"banana\" \"orange\" } permutation ." "{ \"orange\" \"banana\" \"apple\" }" } } ; @@ -41,7 +41,7 @@ HELP: all-permutations { $description "Outputs a sequence containing all permutations of " { $snippet "seq" } " in lexicographical order." } { $examples { $example "USING: math.combinatorics prettyprint ;" - "3 all-permutations ." "{ { 0 1 2 } { 0 2 1 } { 1 0 2 } { 1 2 0 } { 2 0 1 } { 2 1 0 } }" } + "{ 0 1 2 } all-permutations ." "{ { 0 1 2 } { 0 2 1 } { 1 0 2 } { 1 2 0 } { 2 0 1 } { 2 1 0 } }" } } ; HELP: each-permutation diff --git a/basis/math/combinatorics/combinatorics-tests.factor b/basis/math/combinatorics/combinatorics-tests.factor index ca6ec9cb53..bbf5a1cb85 100644 --- a/basis/math/combinatorics/combinatorics-tests.factor +++ b/basis/math/combinatorics/combinatorics-tests.factor @@ -56,7 +56,7 @@ IN: math.combinatorics.tests [ 0 ] [ 9 5 iota 3 dual-index ] unit-test [ 179 ] [ 72 10 iota 5 dual-index ] unit-test -[ { 5 3 2 1 } ] [ 7 4 8 combinadic ] unit-test +[ { 5 3 2 1 } ] [ 7 iota 4 8 combinadic ] unit-test [ { 4 3 2 1 0 } ] [ 10 iota 5 0 combinadic ] unit-test [ { 8 6 3 1 0 } ] [ 10 iota 5 72 combinadic ] unit-test [ { 9 8 7 6 5 } ] [ 10 iota 5 251 combinadic ] unit-test diff --git a/basis/math/combinatorics/combinatorics.factor b/basis/math/combinatorics/combinatorics.factor index bc09f9fe0f..7c68aede09 100644 --- a/basis/math/combinatorics/combinatorics.factor +++ b/basis/math/combinatorics/combinatorics.factor @@ -1,7 +1,7 @@ -! Copyright (c) 2007-2009 Slava Pestov, Doug Coleman, Aaron Schaefer. +! Copyright (c) 2007-2010 Slava Pestov, Doug Coleman, Aaron Schaefer. ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs binary-search fry kernel locals math math.order - math.ranges mirrors namespaces sequences sorting ; + math.ranges namespaces sequences sorting ; IN: math.combinatorics : factorial ( n -- n! ) - 1 [ 1 + * ] reduce ; + iota 1 [ 1 + * ] reduce ; : nPk ( n k -- nPk ) 2dup possible? [ dupd - [a,b) product ] [ 2drop 0 ] if ; @@ -46,11 +46,11 @@ PRIVATE> [ permutation-indices ] keep nths ; : all-permutations ( seq -- seq ) - [ length factorial ] keep + [ length factorial iota ] keep '[ _ permutation ] map ; : each-permutation ( seq quot -- ) - [ [ length factorial ] keep ] dip + [ [ length factorial iota ] keep ] dip '[ _ permutation @ ] each ; inline : reduce-permutations ( seq identity quot -- result ) @@ -77,7 +77,7 @@ C: combo dup 0 = [ drop 1 - nip ] [ - [ [0,b) ] 2dip '[ _ nCk _ >=< ] search nip + [ iota ] 2dip '[ _ nCk _ >=< ] search nip ] if ; :: next-values ( a b x -- a' b' x' v ) @@ -96,30 +96,33 @@ C: combo initial-values [ over 0 > ] [ next-values ] produce [ 3drop ] dip ; -: combination-indices ( m combo -- seq ) - [ tuck dual-index combinadic ] keep - seq>> length 1 - swap [ - ] with map ; +:: combination-indices ( m combo -- seq ) + combo m combo dual-index combinadic + combo seq>> length 1 - swap [ - ] with map ; : apply-combination ( m combo -- seq ) [ combination-indices ] keep seq>> nths ; +: combinations-quot ( seq k quot -- seq quot ) + [ [ choose iota ] keep ] dip + '[ _ apply-combination @ ] ; inline + PRIVATE> +: each-combination ( seq k quot -- ) + combinations-quot each ; inline + +: map-combinations ( seq k quot -- ) + combinations-quot map ; inline + +: map>assoc-combinations ( seq k quot exemplar -- ) + [ combinations-quot ] dip map>assoc ; inline + : combination ( m seq k -- seq ) apply-combination ; : all-combinations ( seq k -- seq ) - [ choose [0,b) ] keep - '[ _ apply-combination ] map ; - -: each-combination ( seq k quot -- ) - [ [ choose [0,b) ] keep ] dip - '[ _ apply-combination @ ] each ; inline - -: map-combinations ( seq k quot -- ) - [ [ choose [0,b) ] keep ] dip - '[ _ apply-combination @ ] map ; inline + [ ] combinations-quot map ; : reduce-combinations ( seq k identity quot -- result ) [ -rot ] dip each-combination ; inline - diff --git a/basis/math/complex/complex-tests.factor b/basis/math/complex/complex-tests.factor index 4b0481eca1..f85ec49f81 100644 --- a/basis/math/complex/complex-tests.factor +++ b/basis/math/complex/complex-tests.factor @@ -70,4 +70,7 @@ IN: math.complex.tests [ ] [ C{ 1 4 } coth drop ] unit-test [ ] [ C{ 1 4 } cot drop ] unit-test +[ t ] [ 0.0 pi rect> exp C{ -1 0 } 1.0e-7 ~ ] unit-test +[ t ] [ 0 pi rect> exp C{ -1 0 } 1.0e-7 ~ ] unit-test + [ "C{ 1/2 2/3 }" ] [ C{ 1/2 2/3 } unparse ] unit-test diff --git a/basis/math/floats/env/x86/32/32.factor b/basis/math/floats/env/x86/32/32.factor new file mode 100644 index 0000000000..ea3bee424f --- /dev/null +++ b/basis/math/floats/env/x86/32/32.factor @@ -0,0 +1,29 @@ +USING: alien alien.c-types cpu.x86.assembler +cpu.x86.assembler.operands math.floats.env.x86 system ; +IN: math.floats.env.x86.32 + +M: x86.32 get-sse-env + void { void* } "cdecl" [ + EAX ESP [] MOV + EAX [] STMXCSR + ] alien-assembly ; + +M: x86.32 set-sse-env + void { void* } "cdecl" [ + EAX ESP [] MOV + EAX [] LDMXCSR + ] alien-assembly ; + +M: x86.32 get-x87-env + void { void* } "cdecl" [ + EAX ESP [] MOV + EAX [] FNSTSW + EAX 2 [+] FNSTCW + ] alien-assembly ; + +M: x86.32 set-x87-env + void { void* } "cdecl" [ + EAX ESP [] MOV + FNCLEX + EAX 2 [+] FLDCW + ] alien-assembly ; diff --git a/extra/drills/deployed/tags.txt b/basis/math/floats/env/x86/32/tags.txt similarity index 100% rename from extra/drills/deployed/tags.txt rename to basis/math/floats/env/x86/32/tags.txt diff --git a/basis/math/floats/env/x86/64/64.factor b/basis/math/floats/env/x86/64/64.factor new file mode 100644 index 0000000000..b6f8ee151f --- /dev/null +++ b/basis/math/floats/env/x86/64/64.factor @@ -0,0 +1,25 @@ +USING: alien alien.c-types cpu.architecture cpu.x86.assembler +cpu.x86.assembler.operands math.floats.env.x86 sequences system ; +IN: math.floats.env.x86.64 + +M: x86.64 get-sse-env + void { void* } "cdecl" [ + int-regs param-regs first [] STMXCSR + ] alien-assembly ; + +M: x86.64 set-sse-env + void { void* } "cdecl" [ + int-regs param-regs first [] LDMXCSR + ] alien-assembly ; + +M: x86.64 get-x87-env + void { void* } "cdecl" [ + int-regs param-regs first [] FNSTSW + int-regs param-regs first 2 [+] FNSTCW + ] alien-assembly ; + +M: x86.64 set-x87-env + void { void* } "cdecl" [ + FNCLEX + int-regs param-regs first 2 [+] FLDCW + ] alien-assembly ; diff --git a/extra/drills/tags.txt b/basis/math/floats/env/x86/64/tags.txt similarity index 100% rename from extra/drills/tags.txt rename to basis/math/floats/env/x86/64/tags.txt diff --git a/basis/math/floats/env/x86/x86.factor b/basis/math/floats/env/x86/x86.factor index 2b73628b4c..89dd402378 100644 --- a/basis/math/floats/env/x86/x86.factor +++ b/basis/math/floats/env/x86/x86.factor @@ -1,7 +1,7 @@ -USING: accessors alien.c-types alien.syntax arrays assocs -biassocs classes.struct combinators cpu.x86.features kernel -literals math math.bitwise math.floats.env -math.floats.env.private system ; +USING: accessors alien.c-types arrays assocs biassocs +classes.struct combinators cpu.x86.features kernel literals +math math.bitwise math.floats.env math.floats.env.private +system vocabs.loader ; IN: math.floats.env.x86 STRUCT: sse-env @@ -11,24 +11,23 @@ STRUCT: x87-env { status ushort } { control ushort } ; -! defined in the vm, cpu-x86*.S -FUNCTION: void get_sse_env ( sse-env* env ) ; -FUNCTION: void set_sse_env ( sse-env* env ) ; +HOOK: get-sse-env cpu ( sse-env -- ) +HOOK: set-sse-env cpu ( sse-env -- ) -FUNCTION: void get_x87_env ( x87-env* env ) ; -FUNCTION: void set_x87_env ( x87-env* env ) ; +HOOK: get-x87-env cpu ( x87-env -- ) +HOOK: set-x87-env cpu ( x87-env -- ) : ( -- sse-env ) - sse-env (struct) [ get_sse_env ] keep ; + sse-env (struct) [ get-sse-env ] keep ; M: sse-env (set-fp-env-register) - set_sse_env ; + set-sse-env ; : ( -- x87-env ) - x87-env (struct) [ get_x87_env ] keep ; + x87-env (struct) [ get-x87-env ] keep ; M: x87-env (set-fp-env-register) - set_x87_env ; + set-x87-env ; M: x86 (fp-env-registers) sse2? [ 2array ] [ 1array ] if ; @@ -128,3 +127,7 @@ M: x87-env (get-denormal-mode) ( register -- mode ) M: x87-env (set-denormal-mode) ( register mode -- register' ) drop ; +cpu { + { x86.32 [ "math.floats.env.x86.32" ] } + { x86.64 [ "math.floats.env.x86.64" ] } +} case require diff --git a/basis/math/functions/functions.factor b/basis/math/functions/functions.factor index d91b4b6b92..a1466dd22c 100644 --- a/basis/math/functions/functions.factor +++ b/basis/math/functions/functions.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2004, 2008 Slava Pestov. +! Copyright (C) 2004, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: math kernel math.constants math.private math.bits math.libm combinators math.order sequences ; @@ -62,7 +62,7 @@ M: float exp fexp ; inline M: real exp >float exp ; inline -M: complex exp >rect swap fexp swap polar> ; inline +M: complex exp >rect swap exp swap polar> ; inline > first over from>> first tuck - random + + [ ] [ from>> first ] [ to>> first ] tri over - random + 2dup swap interval-contains? [ nip ] [ @@ -291,7 +291,7 @@ IN: math.intervals.tests ] if ; unary-ops [ - [ [ t ] ] dip '[ 8000 iota [ drop _ unary-test ] all? ] unit-test + [ [ t ] ] dip '[ 8000 [ drop _ unary-test ] all-integers? ] unit-test ] each : binary-ops ( -- alist ) diff --git a/basis/math/intervals/intervals.factor b/basis/math/intervals/intervals.factor old mode 100755 new mode 100644 diff --git a/basis/math/matrices/elimination/elimination.factor b/basis/math/matrices/elimination/elimination.factor old mode 100755 new mode 100644 index 8411447aac..c8d5bb7338 --- a/basis/math/matrices/elimination/elimination.factor +++ b/basis/math/matrices/elimination/elimination.factor @@ -1,7 +1,7 @@ -! Copyright (C) 2006, 2008 Slava Pestov. +! Copyright (C) 2006, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel math math.vectors math.matrices namespaces -sequences ; +USING: kernel locals math math.vectors math.matrices +namespaces sequences fry sorting ; IN: math.matrices.elimination SYMBOL: matrix @@ -42,7 +42,7 @@ SYMBOL: matrix [ [ clear-scale ] 2keep [ n*v ] dip v+ ] change-row ; : rows-from ( row# -- slice ) - rows dup ; + rows dup iota ; : clear-col ( col# row# rows -- ) [ nth-row ] dip [ [ 2dup ] dip (clear-col) ] each 2drop ; @@ -79,18 +79,17 @@ SYMBOL: matrix : reduced ( matrix' -- matrix'' ) [ - rows [ + rows iota [ dup nth-row leading drop - dup [ swap dup clear-col ] [ 2drop ] if + dup [ swap dup iota clear-col ] [ 2drop ] if ] each ] with-matrix ; -: basis-vector ( row col# -- ) - [ clone ] dip - [ swap nth neg recip ] 2keep - [ 0 spin set-nth ] 2keep - [ n*v ] dip - matrix get set-nth ; +:: basis-vector ( row col# -- ) + row clone :> row' + col# row' nth neg recip :> a + 0 col# row' set-nth + a row n*v col# matrix get set-nth ; : nullspace ( matrix -- seq ) echelon reduced dup empty? [ diff --git a/basis/math/matrices/matrices.factor b/basis/math/matrices/matrices.factor index 75b9be5cae..bf14d7ba13 100644 --- a/basis/math/matrices/matrices.factor +++ b/basis/math/matrices/matrices.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2005, 2009 Slava Pestov. +! Copyright (C) 2005, 2010 Slava Pestov, Joe Groff. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays columns kernel locals math math.bits math.functions math.order math.vectors sequences @@ -11,7 +11,7 @@ IN: math.matrices : identity-matrix ( n -- matrix ) #! Make a nxn identity matrix. - dup [ [ = 1 0 ? ] with map ] curry map ; + iota dup [ [ = 1 0 ? ] with map ] curry map ; :: rotation-matrix3 ( axis theta -- matrix ) theta cos :> c diff --git a/basis/math/polynomials/polynomials.factor b/basis/math/polynomials/polynomials.factor index 0de18b6feb..99d77d0ce2 100644 --- a/basis/math/polynomials/polynomials.factor +++ b/basis/math/polynomials/polynomials.factor @@ -32,7 +32,7 @@ PRIVATE> 2dup [ length ] bi@ + 1 - 2pad-tail [ >vector ] bi@ ; : p* ( p q -- r ) - 2unempty pextend-conv dup length + 2unempty pextend-conv dup length iota [ over length pick pick [ * ] 2map sum ] map 2nip reverse ; : p-sq ( p -- p^2 ) diff --git a/basis/math/primes/factors/factors.factor b/basis/math/primes/factors/factors.factor index c71fa18ab2..7cdfd552a1 100644 --- a/basis/math/primes/factors/factors.factor +++ b/basis/math/primes/factors/factors.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2007-2009 Samuel Tardieu. ! See http://factorcode.org/license.txt for BSD license. USING: arrays combinators kernel make math math.functions -math.primes math.ranges sequences sequences.product sorting ; +math.primes math.ranges sequences sequences.product sorting +io math.parser ; IN: math.primes.factors group-factors [ first2 [0,b] [ ^ ] with map ] map [ product ] product-map natural-sort ] if ; + +: unix-factor ( string -- ) + dup string>number [ + [ ": " append write ] + [ factors [ number>string ] map " " join print ] bi* + ] [ + "factor: `" "' is not a valid positive integer" surround print + ] if* ; + +: run-unix-factor ( -- ) + [ readln [ unix-factor t ] [ f ] if* ] loop ; + +MAIN: run-unix-factor diff --git a/basis/math/primes/miller-rabin/miller-rabin-tests.factor b/basis/math/primes/miller-rabin/miller-rabin-tests.factor index d201abfef8..f803b7db01 100644 --- a/basis/math/primes/miller-rabin/miller-rabin-tests.factor +++ b/basis/math/primes/miller-rabin/miller-rabin-tests.factor @@ -8,4 +8,4 @@ IN: math.primes.miller-rabin.tests [ t ] [ 37 miller-rabin ] unit-test [ t ] [ 2135623355842621559 miller-rabin ] unit-test -[ f ] [ 1000 [ drop 15 miller-rabin ] any? ] unit-test +[ f ] [ 1000 iota [ drop 15 miller-rabin ] any? ] unit-test diff --git a/basis/math/primes/miller-rabin/miller-rabin.factor b/basis/math/primes/miller-rabin/miller-rabin.factor old mode 100755 new mode 100644 index 04b1330cc2..ac5c2df705 --- a/basis/math/primes/miller-rabin/miller-rabin.factor +++ b/basis/math/primes/miller-rabin/miller-rabin.factor @@ -10,7 +10,7 @@ IN: math.primes.miller-rabin n 1 - :> n-1 n-1 factor-2s :> ( r s ) 0 :> a! - trials [ + trials iota [ drop 2 n 2 - [a,b] random a! a s n ^mod 1 = [ diff --git a/basis/math/quaternions/quaternions.factor b/basis/math/quaternions/quaternions.factor old mode 100755 new mode 100644 diff --git a/basis/math/ratios/ratios-tests.factor b/basis/math/ratios/ratios-tests.factor index 8124fcdd24..153d650914 100644 --- a/basis/math/ratios/ratios-tests.factor +++ b/basis/math/ratios/ratios-tests.factor @@ -84,8 +84,8 @@ unit-test [ 1.0 ] [ 0.5 1/2 + ] unit-test [ 1.0 ] [ 1/2 0.5 + ] unit-test -[ 1/268435456 ] [ -1 -268435456 >fixnum / ] unit-test -[ 268435456 ] [ -268435456 >fixnum -1 / ] unit-test +[ 1/134217728 ] [ -1 -134217728 >fixnum / ] unit-test +[ 134217728 ] [ -134217728 >fixnum -1 / ] unit-test [ 5 ] [ "10/2" string>number ] diff --git a/basis/math/statistics/statistics-docs.factor b/basis/math/statistics/statistics-docs.factor index 3b6e7d62ba..bbfc787c0f 100644 --- a/basis/math/statistics/statistics-docs.factor +++ b/basis/math/statistics/statistics-docs.factor @@ -38,7 +38,7 @@ HELP: range HELP: minmax { $values { "seq" sequence } { "min" real } { "max" real } } -{ $description "Finds the minimum and maximum elements of " { $snippet "seq" } " in one pass." } +{ $description "Finds the minimum and maximum elements of " { $snippet "seq" } " in one pass. Throws an error on an empty sequence." } { $examples { $example "USING: arrays math.statistics prettyprint ;" "{ 1 2 3 } minmax 2array ." @@ -98,6 +98,19 @@ HELP: histogram* } { $description "Takes an existing hashtable and uses " { $link histogram } " to continue counting the number of occurences of each element." } ; +HELP: sorted-histogram +{ $values + { "seq" sequence } + { "alist" "an array of key/value pairs" } +} +{ $description "Outputs a " { $link histogram } " of a sequence sorted by number of occurences from lowest to highest." } +{ $examples + { $example "USING: prettyprint math.statistics ;" + """"abababbbbbbc" sorted-histogram .""" + "{ { 99 1 } { 97 3 } { 98 8 } }" + } +} ; + HELP: sequence>assoc { $values { "seq" sequence } { "quot" quotation } { "exemplar" "an exemplar assoc" } @@ -145,6 +158,7 @@ ARTICLE: "histogram" "Computing histograms" { $subsections histogram histogram* + sorted-histogram } "Combinators for implementing histogram:" { $subsections diff --git a/basis/math/statistics/statistics.factor b/basis/math/statistics/statistics.factor index 9c72b848ca..c6a600a303 100644 --- a/basis/math/statistics/statistics.factor +++ b/basis/math/statistics/statistics.factor @@ -79,6 +79,9 @@ PRIVATE> : histogram ( seq -- hashtable ) [ inc-at ] sequence>hashtable ; +: sorted-histogram ( seq -- alist ) + histogram >alist sort-values ; + : collect-values ( seq quot: ( obj hashtable -- ) -- hash ) '[ [ dup @ ] dip push-at ] sequence>hashtable ; inline @@ -86,9 +89,14 @@ PRIVATE> histogram >alist [ ] [ [ [ second ] bi@ > ] 2keep ? ] map-reduce first ; +ERROR: empty-sequence ; + : minmax ( seq -- min max ) - #! find the min and max of a seq in one pass - [ 1/0. -1/0. ] dip [ [ min ] [ max ] bi-curry bi* ] each ; + [ + empty-sequence + ] [ + [ first dup ] keep [ [ min ] [ max ] bi-curry bi* ] each + ] if-empty ; : range ( seq -- x ) minmax swap - ; diff --git a/basis/math/vectors/conversion/backend/backend.factor b/basis/math/vectors/conversion/backend/backend.factor deleted file mode 100644 index d47fab1b0e..0000000000 --- a/basis/math/vectors/conversion/backend/backend.factor +++ /dev/null @@ -1,21 +0,0 @@ -! (c)Joe Groff bsd license -USING: accessors alien.c-types arrays assocs classes combinators -cords fry kernel math math.vectors sequences ; -IN: math.vectors.conversion.backend - -: saturate-map-as ( v quot result -- w ) - [ element-type '[ @ _ c-type-clamp ] ] keep map-as ; inline - -: (v>float) ( i to-type -- f ) - [ >float ] swap new map-as ; -: (v>integer) ( f to-type -- i ) - [ >integer ] swap new map-as ; -: (vpack-signed) ( a b to-type -- ab ) - [ cord-append [ ] ] dip new saturate-map-as ; -: (vpack-unsigned) ( a b to-type -- ab ) - [ cord-append [ ] ] dip new saturate-map-as ; -: (vunpack-head) ( ab to-type -- a ) - [ dup length 2 /i head-slice ] dip new like ; -: (vunpack-tail) ( ab to-type -- b ) - [ dup length 2 /i tail-slice ] dip new like ; - diff --git a/basis/math/vectors/conversion/conversion-docs.factor b/basis/math/vectors/conversion/conversion-docs.factor index 9fe5ac4c17..7f2a349c52 100644 --- a/basis/math/vectors/conversion/conversion-docs.factor +++ b/basis/math/vectors/conversion/conversion-docs.factor @@ -22,7 +22,7 @@ HELP: vconvert } { $description "Converts SIMD vectors of " { $snippet "from-type" } " to " { $snippet "to-type" } ". The number of inputs and outputs depends on the relationship of the two types:" { $list -{ "If " { $snippet "to-type" } " is a floating-point vector type with the same byte length and element count as the integer vector type " { $snippet "from-type" } " (for example, from " { $snippet "int-8" } " to " { $snippet "float-8" } " or from " { $snippet "longlong-2" } " to " { $snippet "double-2" } "), " { $snippet "vconvert" } " takes one vector of " { $snippet "from-type" } " and converts its elements to floating-point, outputting one vector of " { $snippet "to-type" } "." } +{ "If " { $snippet "to-type" } " is a floating-point vector type with the same byte length and element count as the integer vector type " { $snippet "from-type" } " (for example, from " { $snippet "int-4" } " to " { $snippet "float-4" } " or from " { $snippet "longlong-2" } " to " { $snippet "double-2" } "), " { $snippet "vconvert" } " takes one vector of " { $snippet "from-type" } " and converts its elements to floating-point, outputting one vector of " { $snippet "to-type" } "." } { "Likewise, if " { $snippet "to-type" } " is an integer vector type with the same byte length and element count as the floating-point vector type " { $snippet "from-type" } ", " { $snippet "vconvert" } " takes one vector of " { $snippet "from-type" } " and truncates its elements to integers, outputting one vector of " { $snippet "to-type" } "." } { "If " { $snippet "to-type" } " is a vector type with the same byte length as and twice the element count of the vector type " { $snippet "from-type" } " (for example, from " { $snippet "int-4" } " to " { $snippet "ushort-8" } ", from " { $snippet "double-2" } " to " { $snippet "float-4" } ", or from " { $snippet "short-8" } " to " { $snippet "char-16" } "), " { $snippet "vconvert" } " takes two vectors of " { $snippet "from-type" } " and packs them into one vector of " { $snippet "to-type" } ", saturating values too large or small to be representable as elements of " { $snippet "to-type" } "." } { "If " { $snippet "to-type" } " is a vector type with the same byte length as and half the element count of the vector type " { $snippet "from-type" } " (for example, from " { $snippet "ushort-8" } " to " { $snippet "int-4" } ", from " { $snippet "float-4" } " to " { $snippet "double-2" } ", or from " { $snippet "char-16" } " to " { $snippet "short-8" } "), " { $snippet "vconvert" } " takes one vector of " { $snippet "from-type" } " and unpacks it into two vectors of " { $snippet "to-type" } "." } @@ -39,26 +39,23 @@ HELP: vconvert "Conversion between integer and float vectors:" { $example """USING: alien.c-types math.vectors.conversion math.vectors.simd prettyprint ; -SIMDS: int float longlong double ; -int-8{ 0 1 2 3 4 5 6 7 } int-8 float-8 vconvert . +int-4{ 0 1 2 3 } int-4 float-4 vconvert . double-2{ 1.25 3.75 } double-2 longlong-2 vconvert .""" -"""float-8{ 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 } +"""float-4{ 0.0 1.0 2.0 3.0 } longlong-2{ 1 3 }""" } "Packing conversions:" { $example """USING: alien.c-types math.vectors.conversion math.vectors.simd prettyprint ; -SIMDS: ushort int float double ; int-4{ -8 70000 6000 50 } int-4{ 4 3 2 -1 } int-4 ushort-8 vconvert . -double-4{ 0.0 1.5 1.0e100 2.0 } -double-4{ -1.0e100 0.0 1.0 2.0 } double-4 float-8 vconvert .""" +double-2{ 0.0 1.0e100 } +double-2{ -1.0e100 0.0 } double-2 float-4 vconvert .""" """ushort-8{ 0 65535 6000 50 4 3 2 0 } -float-8{ 0.0 1.5 1/0. 2.0 -1/0. 0.0 1.0 2.0 }""" } +float-4{ 0.0 1/0. -1/0. 0.0 }""" } "Unpacking conversions:" { $example """USING: alien.c-types kernel math.vectors.conversion math.vectors.simd prettyprint ; -SIMDS: uchar short ; uchar-16{ 8 70 60 50 4 30 200 1 9 10 110 102 133 143 115 0 } uchar-16 short-8 vconvert [ . ] bi@""" diff --git a/basis/math/vectors/conversion/conversion-tests.factor b/basis/math/vectors/conversion/conversion-tests.factor index 0f48b47756..c91bdb369e 100644 --- a/basis/math/vectors/conversion/conversion-tests.factor +++ b/basis/math/vectors/conversion/conversion-tests.factor @@ -3,16 +3,6 @@ USING: accessors arrays compiler continuations generalizations kernel kernel.private locals math.vectors.conversion math.vectors.simd sequences stack-checker tools.test ; FROM: alien.c-types => char uchar short ushort int uint longlong ulonglong float double ; -SIMD: uchar -SIMD: char -SIMD: ushort -SIMD: short -SIMD: uint -SIMD: int -SIMD: ulonglong -SIMD: longlong -SIMD: float -SIMD: double IN: math.vectors.conversion.tests ERROR: optimized-vconvert-inconsistent @@ -59,12 +49,12 @@ MACRO:: test-vconvert ( from-type to-type -- ) [ double-2{ -5.0 1.0 } ] [ longlong-2{ -5 1 } longlong-2 double-2 test-vconvert ] unit-test -[ longlong-4{ -5 1 2 6 } ] -[ double-4{ -5.0 1.0 2.3 6.7 } double-4 longlong-4 test-vconvert ] unit-test +[ longlong-2{ -5 1 } ] +[ double-2{ -5.0 1.0 } double-2 longlong-2 test-vconvert ] unit-test ! TODO we should be able to do double->int pack -! [ int-8{ -5 1 2 6 12 34 -56 78 } ] -[ double-4{ -5.0 1.0 2.0 6.0 } double-4{ 12.0 34.0 -56.0 78.0 } double-4 int-8 test-vconvert ] +! [ int-4{ -5 1 12 34 } ] +[ double-2{ -5.0 1.0 } double-2{ 12.0 34.0 } double-2 int-4 test-vconvert ] [ error>> bad-vconvert? ] must-fail-with [ float-4{ -1.25 2.0 3.0 -4.0 } ] @@ -76,10 +66,10 @@ MACRO:: test-vconvert ( from-type to-type -- ) [ short-8{ -1 2 3 -32768 5 32767 -7 32767 } ] [ int-4{ -1 2 3 -40000 } int-4{ 5 60000 -7 80000 } int-4 short-8 test-vconvert ] unit-test -[ short-16{ -1 2 3 -32768 3 2 1 0 5 32767 -7 32767 7 6 5 4 } ] +[ short-8{ -1 2 3 -32768 5 32767 -7 32767 } ] [ - int-8{ -1 2 3 -40000 3 2 1 0 } - int-8{ 5 60000 -7 80000 7 6 5 4 } int-8 short-16 test-vconvert + int-4{ -1 2 3 -40000 } + int-4{ 5 60000 -7 80000 } int-4 short-8 test-vconvert ] unit-test [ ushort-8{ 0 2 3 0 5 60000 0 65535 } ] @@ -97,15 +87,6 @@ MACRO:: test-vconvert ( from-type to-type -- ) uchar-16 ushort-8 test-vconvert ] unit-test -! TODO we should be able to do 256->128 pack -! [ float-4{ -1.25 2.0 3.0 -4.0 } ] -[ double-4{ -1.25 2.0 3.0 -4.0 } double-4 float-4 test-vconvert ] -[ error>> bad-vconvert? ] must-fail-with - -! [ int-4{ -1 2 3 -4 } ] -[ longlong-4{ -1 2 3 -4 } longlong-4 int-4 test-vconvert ] -[ error>> bad-vconvert? ] must-fail-with - [ double-2{ -1.25 2.0 } double-2{ 3.0 -4.0 } ] [ float-4{ -1.25 2.0 3.0 -4.0 } float-4 double-2 test-vconvert ] unit-test @@ -121,8 +102,8 @@ MACRO:: test-vconvert ( from-type to-type -- ) [ ulonglong-2{ 1 2 } ulonglong-2{ 3 4 } ] [ uint-4{ 1 2 3 4 } uint-4 ulonglong-2 test-vconvert ] unit-test -[ longlong-4{ 1 2 3 4 } longlong-4{ 3 4 5 6 } ] -[ uint-8{ 1 2 3 4 3 4 5 6 } uint-8 longlong-4 test-vconvert ] unit-test +[ longlong-2{ 1 2 } longlong-2{ 3 4 } ] +[ uint-4{ 1 2 3 4 } uint-4 longlong-2 test-vconvert ] unit-test [ int-4{ 1 2 -3 -4 } int-4{ 5 -6 7 -8 } ] [ short-8{ 1 2 -3 -4 5 -6 7 -8 } short-8 int-4 test-vconvert ] unit-test @@ -130,13 +111,8 @@ MACRO:: test-vconvert ( from-type to-type -- ) [ uint-4{ 1 2 3 4 } uint-4{ 5 6 7 8 } ] [ ushort-8{ 1 2 3 4 5 6 7 8 } ushort-8 uint-4 test-vconvert ] unit-test -[ longlong-4{ 1 2 3 4 } longlong-4{ 3 4 5 6 } ] -[ uint-8{ 1 2 3 4 3 4 5 6 } uint-8 longlong-4 test-vconvert ] unit-test - -! TODO we should be able to do 128->256 unpack -! [ longlong-4{ 1 2 3 4 } ] -[ uint-4{ 1 2 3 4 } uint-4 longlong-4 test-vconvert ] -[ error>> bad-vconvert? ] must-fail-with +[ longlong-2{ 1 2 } longlong-2{ 3 4 } ] +[ uint-4{ 1 2 3 4 } uint-4 longlong-2 test-vconvert ] unit-test ! TODO we should be able to do multi-tier pack/unpack ! [ longlong-2{ 1 2 } longlong-2{ 3 4 } longlong-2{ 5 6 } longlong-2{ 7 8 } ] diff --git a/basis/math/vectors/conversion/conversion.factor b/basis/math/vectors/conversion/conversion.factor index fd58b11dc8..6148962ee0 100644 --- a/basis/math/vectors/conversion/conversion.factor +++ b/basis/math/vectors/conversion/conversion.factor @@ -1,8 +1,10 @@ ! (c)Joe Groff bsd license USING: accessors alien.c-types arrays assocs classes combinators -combinators.short-circuit cords fry kernel locals math -math.vectors math.vectors.conversion.backend sequences ; -FROM: alien.c-types => char uchar short ushort int uint longlong ulonglong float double ; +combinators.short-circuit fry kernel locals math +math.vectors math.vectors.simd math.vectors.simd.intrinsics sequences ; +FROM: alien.c-types => + char uchar short ushort int uint longlong ulonglong + float double ; IN: math.vectors.conversion ERROR: bad-vconvert from-type to-type ; @@ -30,11 +32,11 @@ ERROR: bad-vconvert-input value expected-type ; } { [ from-element float-type? ] - [ [ to-type (v>integer) ] ] + [ from-type new simd-rep '[ underlying>> _ (simd-v>integer) to-type boa ] ] } { [ to-element float-type? ] - [ [ to-type (v>float) ] ] + [ from-type new simd-rep '[ underlying>> _ (simd-v>float) to-type boa ] ] } } cond [ from-type check-vconvert-type ] prepose ; @@ -47,10 +49,18 @@ ERROR: bad-vconvert-input value expected-type ; } 0|| [ from-type to-type bad-vconvert ] when ; :: [[vpack-unsigned]] ( from-type to-type -- quot ) - [ [ from-type check-vconvert-type ] bi@ to-type (vpack-unsigned) ] ; + from-type new simd-rep + '[ + [ from-type check-vconvert-type underlying>> ] bi@ + _ (simd-vpack-unsigned) to-type boa + ] ; :: [[vpack-signed]] ( from-type to-type -- quot ) - [ [ from-type check-vconvert-type ] bi@ to-type (vpack-signed) ] ; + from-type new simd-rep + '[ + [ from-type check-vconvert-type underlying>> ] bi@ + _ (simd-vpack-signed) to-type boa + ] ; :: [vpack] ( from-element to-element from-size to-size from-type to-type -- quot ) from-size to-size /i log2 :> steps @@ -68,9 +78,11 @@ ERROR: bad-vconvert-input value expected-type ; } 0|| [ from-type to-type bad-vconvert ] when ; :: [[vunpack]] ( from-type to-type -- quot ) - [ - from-type check-vconvert-type - [ to-type (vunpack-head) ] [ to-type (vunpack-tail) ] bi + from-type new simd-rep + '[ + from-type check-vconvert-type underlying>> _ + [ (simd-vunpack-head) to-type boa ] + [ (simd-vunpack-tail) to-type boa ] 2bi ] ; :: [vunpack] ( from-element to-element from-size to-size from-type to-type -- quot ) @@ -81,8 +93,8 @@ ERROR: bad-vconvert-input value expected-type ; PRIVATE> MACRO:: vconvert ( from-type to-type -- ) - from-type new [ element-type ] [ byte-length ] bi :> ( from-element from-length ) - to-type new [ element-type ] [ byte-length ] bi :> ( to-element to-length ) + from-type new [ simd-element-type ] [ byte-length ] bi :> ( from-element from-length ) + to-type new [ simd-element-type ] [ byte-length ] bi :> ( to-element to-length ) from-element heap-size :> from-size to-element heap-size :> to-size diff --git a/basis/math/vectors/simd/cords/cords.factor b/basis/math/vectors/simd/cords/cords.factor new file mode 100644 index 0000000000..815b34a90d --- /dev/null +++ b/basis/math/vectors/simd/cords/cords.factor @@ -0,0 +1,87 @@ +USING: accessors alien.c-types arrays byte-arrays +cpu.architecture effects functors generalizations kernel lexer +math math.vectors.simd math.vectors.simd.intrinsics parser +prettyprint.custom quotations sequences sequences.cords words ; +IN: math.vectors.simd.cords + +<< +A/2 IS >${A/2} +A/2-boa IS ${A/2}-boa +A/2-with IS ${A/2}-with +A/2-cast IS ${A/2}-cast + +>A DEFINES >${A} +A-boa DEFINES ${A}-boa +A-with DEFINES ${A}-with +A-cast DEFINES ${A}-cast +A{ DEFINES ${A}{ + +N [ A-rep rep-length ] +BOA-EFFECT [ N 2 * "n" { "v" } ] + +WHERE + +: >A ( seq -- A ) + [ N head >A/2 ] + [ N tail >A/2 ] bi cord-append ; + +\ A-boa +{ N ndip A/2-boa cord-append } { A/2-boa } >quotation prefix >quotation +BOA-EFFECT define-inline + +: A-with ( n -- v ) + [ A/2-with ] [ A/2-with ] bi cord-append ; + +: A-cast ( v -- v' ) + [ A/2-cast ] cord-map ; + +M: A >pprint-sequence ; +M: A pprint* pprint-object ; + +M: A pprint-delims drop \ A{ \ } ; +SYNTAX: A{ \ } [ >A ] parse-literal ; + + + byte-array >>class + A >>boxed-class + [ + [ A-rep alien-vector A/2 boa ] + [ 16 + A-rep alien-vector A/2 boa ] 2bi cord-append + ] >>getter + [ + [ [ head>> underlying>> ] 2dip A-rep set-alien-vector ] + [ [ tail>> underlying>> ] 2dip 16 + A-rep set-alien-vector ] 3bi + ] >>setter + 32 >>size + 16 >>align + A-rep >>rep +\ A typedef + +;FUNCTOR + +: define-simd-128-cord ( A/2 T -- ) + [ define-specialized-cord ] + [ create-in (define-simd-128-cord) ] 2bi ; + +SYNTAX: SIMD-128-CORD: + scan-word scan define-simd-128-cord ; + +PRIVATE> +>> + +SIMD-128-CORD: char-16 char-32 +SIMD-128-CORD: uchar-16 uchar-32 +SIMD-128-CORD: short-8 short-16 +SIMD-128-CORD: ushort-8 ushort-16 +SIMD-128-CORD: int-4 int-8 +SIMD-128-CORD: uint-4 uint-8 +SIMD-128-CORD: longlong-2 longlong-4 +SIMD-128-CORD: ulonglong-2 ulonglong-4 +SIMD-128-CORD: float-4 float-8 +SIMD-128-CORD: double-2 double-4 + diff --git a/basis/math/vectors/simd/functor/functor.factor b/basis/math/vectors/simd/functor/functor.factor deleted file mode 100644 index 44907df68e..0000000000 --- a/basis/math/vectors/simd/functor/functor.factor +++ /dev/null @@ -1,522 +0,0 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs byte-arrays classes classes.algebra effects fry -functors generalizations kernel literals locals math math.functions -math.vectors math.vectors.private math.vectors.simd.intrinsics -math.vectors.conversion.backend -math.vectors.specialization parser prettyprint.custom sequences -sequences.private strings words definitions macros cpu.architecture -namespaces arrays quotations combinators combinators.short-circuit sets -layouts ; -QUALIFIED-WITH: alien.c-types c -QUALIFIED: math.private -IN: math.vectors.simd.functor - -ERROR: bad-length got expected ; - -: vector-true-value ( class -- value ) - { - { [ dup integer class<= ] [ drop -1 ] } - { [ dup float class<= ] [ drop -1 bits>double ] } - } cond ; foldable - -: vector-false-value ( class -- value ) - { - { [ dup integer class<= ] [ drop 0 ] } - { [ dup float class<= ] [ drop 0.0 ] } - } cond ; foldable - -: boolean>element ( bool/elt class -- elt ) - swap { - { t [ vector-true-value ] } - { f [ vector-false-value ] } - [ nip ] - } case ; inline - -MACRO: simd-boa ( rep class -- simd-array ) - [ rep-components ] [ new ] bi* '[ _ _ nsequence ] ; - -: can-be-unboxed? ( type -- ? ) - { - { c:float [ \ math.private:float+ "intrinsic" word-prop ] } - { c:double [ \ math.private:float+ "intrinsic" word-prop ] } - [ c:heap-size cell < ] - } case ; - -: simd-boa-fast? ( rep -- ? ) - [ dup rep-gather-word supported-simd-op? ] - [ rep-component-type can-be-unboxed? ] - bi and ; - -:: define-boa-custom-inlining ( word rep class -- ) - word [ - drop - rep simd-boa-fast? [ - [ rep (simd-boa) class boa ] - ] [ word def>> ] if - ] "custom-inlining" set-word-prop ; - -: simd-with ( rep class x -- simd-array ) - [ rep-components ] [ new ] [ '[ _ ] ] tri* swap replicate-as ; inline - -: simd-with/nth-fast? ( rep -- ? ) - [ \ (simd-vshuffle-elements) supported-simd-op? ] - [ rep-component-type can-be-unboxed? ] - bi and ; - -:: define-with-custom-inlining ( word rep class -- ) - word [ - drop - rep simd-with/nth-fast? [ - [ rep rep-coerce rep (simd-with) class boa ] - ] [ word def>> ] if - ] "custom-inlining" set-word-prop ; - -: simd-nth-fast ( rep -- quot ) - [ rep-components ] keep - '[ swap _ '[ _ _ (simd-select) ] 2array ] map-index - '[ swap >fixnum _ case ] ; - -: simd-nth-slow ( rep -- quot ) - rep-component-type dup c:c-type-getter-boxer c:array-accessor ; - -MACRO: simd-nth ( rep -- x ) - dup simd-with/nth-fast? [ simd-nth-fast ] [ simd-nth-slow ] if ; - -: boa-effect ( rep n -- effect ) - [ rep-components ] dip * - [ CHAR: a + 1string ] map - { "simd-vector" } ; - -: supported-simd-ops ( assoc rep -- assoc' ) - [ simd-ops get ] dip - '[ nip _ swap supported-simd-op? ] assoc-filter - '[ drop _ key? ] assoc-filter ; - -ERROR: bad-schema op schema ; - -:: op-wrapper ( op specials schemas -- wrapper ) - op { - [ specials at ] - [ word-schema schemas at ] - [ dup word-schema bad-schema ] - } 1|| ; - -: low-level-ops ( simd-ops specials schemas -- alist ) - '[ 1quotation over _ _ op-wrapper [ ] 2sequence ] assoc-map ; - -:: high-level-ops ( ctor elt-class -- assoc ) - ! Some SIMD operations are defined in terms of others. - { - { vbroadcast [ swap nth ctor execute ] } - { n+v [ [ ctor execute ] dip v+ ] } - { v+n [ ctor execute v+ ] } - { n-v [ [ ctor execute ] dip v- ] } - { v-n [ ctor execute v- ] } - { n*v [ [ ctor execute ] dip v* ] } - { v*n [ ctor execute v* ] } - { n/v [ [ ctor execute ] dip v/ ] } - { v/n [ ctor execute v/ ] } - { norm-sq [ dup v. assert-positive ] } - { norm [ norm-sq sqrt ] } - { normalize [ dup norm v/n ] } - } - ! To compute dot product and distance with integer vectors, we - ! have to do things less efficiently, with integer overflow checks, - ! in the general case. - elt-class float = [ { distance [ v- norm ] } suffix ] when ; - -TUPLE: simd class elt-class ops special-wrappers schema-wrappers ctor rep ; - -: define-simd ( simd -- ) - dup rep>> rep-component-type c:c-type-boxed-class >>elt-class - { - [ class>> ] - [ elt-class>> ] - [ [ ops>> ] [ special-wrappers>> ] [ schema-wrappers>> ] tri low-level-ops ] - [ rep>> supported-simd-ops ] - [ [ ctor>> ] [ elt-class>> ] bi high-level-ops assoc-union ] - } cleave - specialize-vector-words ; - -:: define-simd-128-type ( class rep -- ) - c: - byte-array >>class - class >>boxed-class - [ rep alien-vector class boa ] >>getter - [ [ underlying>> ] 2dip rep set-alien-vector ] >>setter - 16 >>size - 16 >>align - rep >>rep - class c:typedef ; - -: (define-simd-128) ( simd -- ) - simd-ops get >>ops - [ define-simd ] - [ [ class>> ] [ rep>> ] bi define-simd-128-type ] bi ; - -FUNCTOR: define-simd-128 ( T -- ) - -N [ 16 T c:heap-size /i ] - -A DEFINES-CLASS ${T}-${N} -A-boa DEFINES ${A}-boa -A-with DEFINES ${A}-with -A-cast DEFINES ${A}-cast ->A DEFINES >${A} -A{ DEFINES ${A}{ - -SET-NTH [ T dup c:c-setter c:array-accessor ] - -A-rep [ A name>> "-rep" append "cpu.architecture" lookup ] -A-vv->v-op DEFINES-PRIVATE ${A}-vv->v-op -A-vn->v-op DEFINES-PRIVATE ${A}-vn->v-op -A-vv->n-op DEFINES-PRIVATE ${A}-vv->n-op -A-v->v-op DEFINES-PRIVATE ${A}-v->v-op -A-v->n-op DEFINES-PRIVATE ${A}-v->n-op -A-v-conversion-op DEFINES-PRIVATE ${A}-v-conversion-op -A-vv-conversion-op DEFINES-PRIVATE ${A}-vv-conversion-op - -A-element-class [ A-rep rep-component-type c:c-type-boxed-class ] - -WHERE - -TUPLE: A -{ underlying byte-array read-only initial: $[ 16 ] } ; - -INSTANCE: A simd-128 - -M: A clone underlying>> clone \ A boa ; inline - -M: A length drop N ; inline - -M: A equal? - over \ A instance? [ v= vall? ] [ 2drop f ] if ; - -M: A nth-unsafe underlying>> A-rep simd-nth ; inline - -M: A set-nth-unsafe - [ A-element-class boolean>element ] 2dip - underlying>> SET-NTH call ; inline - -: >A ( seq -- simd-array ) \ A new clone-like ; - -M: A like drop dup \ A instance? [ >A ] unless ; inline - -M: A new-underlying drop \ A boa ; inline - -M: A new-sequence - drop dup N = - [ drop 16 \ A boa ] - [ N bad-length ] - if ; inline - -M: A c:byte-length underlying>> length ; inline - -M: A element-type drop A-rep rep-component-type ; - -M: A pprint-delims drop \ A{ \ } ; - -M: A >pprint-sequence ; - -M: A pprint* pprint-object ; - -SYNTAX: A{ \ } [ >A ] parse-literal ; - -: A-with ( x -- simd-array ) [ A-rep A ] dip simd-with ; - -\ A-with \ A-rep \ A define-with-custom-inlining - -\ A-boa [ \ A-rep \ A simd-boa ] \ A-rep 1 boa-effect define-declared - -\ A-rep rep-gather-word [ - \ A-boa \ A-rep \ A define-boa-custom-inlining -] when - -: A-cast ( simd-array -- simd-array' ) - underlying>> \ A boa ; inline - -INSTANCE: A sequence - -v-op ( v1 v2 quot -- v3 ) - [ [ underlying>> ] bi@ A-rep ] dip call \ A boa ; inline - -: A-vn->v-op ( v1 v2 quot -- v3 ) - [ [ underlying>> ] dip A-rep ] dip call \ A boa ; inline - -: A-vv->n-op ( v1 v2 quot -- n ) - [ [ underlying>> ] bi@ A-rep ] dip call ; inline - -: A-v->v-op ( v1 quot -- v2 ) - [ underlying>> A-rep ] dip call \ A boa ; inline - -: A-v->n-op ( v quot -- n ) - [ underlying>> A-rep ] dip call ; inline - -: A-v-conversion-op ( v1 to-type quot -- v2 ) - swap [ underlying>> A-rep ] [ call ] [ '[ _ boa ] call( u -- v ) ] tri* ; inline - -: A-vv-conversion-op ( v1 v2 to-type quot -- v2 ) - swap { - [ underlying>> ] - [ underlying>> A-rep ] - [ call ] - [ '[ _ boa ] call( u -- v ) ] - } spread ; inline - -simd new - \ A >>class - \ A-with >>ctor - \ A-rep >>rep - { - { (v>float) A-v-conversion-op } - { (v>integer) A-v-conversion-op } - { (vpack-signed) A-vv-conversion-op } - { (vpack-unsigned) A-vv-conversion-op } - { (vunpack-head) A-v-conversion-op } - { (vunpack-tail) A-v-conversion-op } - } >>special-wrappers - { - { { +vector+ +vector+ -> +vector+ } A-vv->v-op } - { { +vector+ +any-vector+ -> +vector+ } A-vv->v-op } - { { +vector+ +scalar+ -> +vector+ } A-vn->v-op } - { { +vector+ +literal+ -> +vector+ } A-vn->v-op } - { { +vector+ +vector+ -> +scalar+ } A-vv->n-op } - { { +vector+ +vector+ -> +boolean+ } A-vv->n-op } - { { +vector+ -> +vector+ } A-v->v-op } - { { +vector+ -> +scalar+ } A-v->n-op } - { { +vector+ -> +boolean+ } A-v->n-op } - { { +vector+ -> +nonnegative+ } A-v->n-op } - } >>schema-wrappers -(define-simd-128) - -PRIVATE> - -;FUNCTOR - -! Synthesize 256-bit vectors from a pair of 128-bit vectors -SLOT: underlying1 -SLOT: underlying2 - -:: define-simd-256-type ( class rep -- ) - c: - class >>class - class >>boxed-class - [ - [ rep alien-vector ] - [ 16 + >fixnum rep alien-vector ] 2bi - class boa - ] >>getter - [ - [ [ underlying1>> ] 2dip rep set-alien-vector ] - [ [ underlying2>> ] 2dip 16 + >fixnum rep set-alien-vector ] - 3bi - ] >>setter - 32 >>size - 16 >>align - rep >>rep - class c:typedef ; - -: (define-simd-256) ( simd -- ) - simd-ops get { vshuffle-elements vshuffle-bytes hlshift hrshift } unique assoc-diff >>ops - [ define-simd ] - [ [ class>> ] [ rep>> ] bi define-simd-256-type ] bi ; - -FUNCTOR: define-simd-256 ( T -- ) - -N [ 32 T c:heap-size /i ] - -N/2 [ N 2 /i ] -A/2 IS ${T}-${N/2} -A/2-boa IS ${A/2}-boa -A/2-with IS ${A/2}-with - -A DEFINES-CLASS ${T}-${N} -A-boa DEFINES ${A}-boa -A-with DEFINES ${A}-with -A-cast DEFINES ${A}-cast ->A DEFINES >${A} -A{ DEFINES ${A}{ - -A-deref DEFINES-PRIVATE ${A}-deref - -A-rep [ A/2 name>> "-rep" append "cpu.architecture" lookup ] -A-vv->v-op DEFINES-PRIVATE ${A}-vv->v-op -A-vn->v-op DEFINES-PRIVATE ${A}-vn->v-op -A-v->v-op DEFINES-PRIVATE ${A}-v->v-op -A-v.-op DEFINES-PRIVATE ${A}-v.-op -(A-v->n-op) DEFINES-PRIVATE (${A}-v->v-op) -A-sum-op DEFINES-PRIVATE ${A}-sum-op -A-vany-op DEFINES-PRIVATE ${A}-vany-op -A-vall-op DEFINES-PRIVATE ${A}-vall-op -A-vmerge-head-op DEFINES-PRIVATE ${A}-vmerge-head-op -A-vmerge-tail-op DEFINES-PRIVATE ${A}-vmerge-tail-op -A-v-conversion-op DEFINES-PRIVATE ${A}-v-conversion-op -A-vpack-op DEFINES-PRIVATE ${A}-vpack-op -A-vunpack-head-op DEFINES-PRIVATE ${A}-vunpack-head-op -A-vunpack-tail-op DEFINES-PRIVATE ${A}-vunpack-tail-op - -WHERE - -SLOT: underlying1 -SLOT: underlying2 - -TUPLE: A -{ underlying1 byte-array initial: $[ 16 ] read-only } -{ underlying2 byte-array initial: $[ 16 ] read-only } ; - -INSTANCE: A simd-256 - -M: A clone - [ underlying1>> clone ] [ underlying2>> clone ] bi - \ A boa ; inline - -M: A length drop N ; inline - -M: A equal? - over \ A instance? [ v= vall? ] [ 2drop f ] if ; - -: A-deref ( n seq -- n' seq' ) - over N/2 < [ underlying1>> ] [ [ N/2 - ] dip underlying2>> ] if \ A/2 boa ; inline - -M: A nth-unsafe A-deref nth-unsafe ; inline - -M: A set-nth-unsafe A-deref set-nth-unsafe ; inline - -: >A ( seq -- simd-array ) \ A new clone-like ; - -M: A like drop dup \ A instance? [ >A ] unless ; inline - -M: A new-sequence - drop dup N = - [ drop 16 16 \ A boa ] - [ N bad-length ] - if ; inline - -M: A c:byte-length drop 32 ; inline - -M: A element-type drop A-rep rep-component-type ; - -SYNTAX: A{ \ } [ >A ] parse-literal ; - -M: A pprint-delims drop \ A{ \ } ; - -M: A >pprint-sequence ; - -M: A pprint* pprint-object ; - -: A-with ( x -- simd-array ) - [ A/2-with ] [ A/2-with ] bi [ underlying>> ] bi@ - \ A boa ; inline - -: A-boa ( ... -- simd-array ) - [ A/2-boa ] N/2 ndip A/2-boa [ underlying>> ] bi@ - \ A boa ; inline - -\ A-rep 2 boa-effect \ A-boa set-stack-effect - -: A-cast ( simd-array -- simd-array' ) - [ underlying1>> ] [ underlying2>> ] bi \ A boa ; inline - -INSTANCE: A sequence - -: A-vv->v-op ( v1 v2 quot -- v3 ) - [ [ [ underlying1>> ] bi@ A-rep ] dip call ] - [ [ [ underlying2>> ] bi@ A-rep ] dip call ] 3bi - \ A boa ; inline - -: A-vn->v-op ( v1 v2 quot -- v3 ) - [ [ [ underlying1>> ] dip A-rep ] dip call ] - [ [ [ underlying2>> ] dip A-rep ] dip call ] 3bi - \ A boa ; inline - -: A-v->v-op ( v1 combine-quot -- v2 ) - [ [ underlying1>> A-rep ] dip call ] - [ [ underlying2>> A-rep ] dip call ] 2bi - \ A boa ; inline - -: A-v.-op ( v1 v2 quot -- n ) - [ [ [ underlying1>> ] bi@ A-rep ] dip call ] - [ [ [ underlying2>> ] bi@ A-rep ] dip call ] 3bi - + ; inline - -: (A-v->n-op) ( v1 quot reduce-quot -- n ) - '[ [ underlying1>> ] [ underlying2>> ] bi A-rep @ A-rep ] dip call ; inline - -: A-sum-op ( v1 quot -- n ) - [ (simd-v+) ] (A-v->n-op) ; inline - -: A-vany-op ( v1 quot -- n ) - [ (simd-vbitor) ] (A-v->n-op) ; inline -: A-vall-op ( v1 quot -- n ) - [ (simd-vbitand) ] (A-v->n-op) ; inline - -: A-vmerge-head-op ( v1 v2 quot -- v ) - drop - [ underlying1>> ] bi@ - [ A-rep (simd-(vmerge-head)) ] - [ A-rep (simd-(vmerge-tail)) ] 2bi - \ A boa ; inline - -: A-vmerge-tail-op ( v1 v2 quot -- v ) - drop - [ underlying2>> ] bi@ - [ A-rep (simd-(vmerge-head)) ] - [ A-rep (simd-(vmerge-tail)) ] 2bi - \ A boa ; inline - -: A-v-conversion-op ( v1 to-type quot -- v ) - swap [ - [ [ underlying1>> A-rep ] dip call ] - [ [ underlying2>> A-rep ] dip call ] 2bi - ] dip '[ _ boa ] call( u1 u2 -- v ) ; inline - -: A-vpack-op ( v1 v2 to-type quot -- v ) - swap [ - '[ [ underlying1>> ] [ underlying2>> ] bi A-rep @ ] bi* - ] dip '[ _ boa ] call( u1 u2 -- v ) ; inline - -: A-vunpack-head-op ( v1 to-type quot -- v ) - '[ - underlying1>> - [ A-rep @ ] - [ A-rep (simd-(vunpack-tail)) ] bi - ] dip '[ _ boa ] call( u1 u2 -- v ) ; inline - -: A-vunpack-tail-op ( v1 to-type quot -- v ) - '[ - underlying2>> - [ A-rep (simd-(vunpack-head)) ] - [ A-rep @ ] bi - ] dip '[ _ boa ] call( u1 u2 -- v ) ; inline - -simd new - \ A >>class - \ A-with >>ctor - \ A-rep >>rep - { - { v. A-v.-op } - { sum A-sum-op } - { vnone? A-vany-op } - { vany? A-vany-op } - { vall? A-vall-op } - { (vmerge-head) A-vmerge-head-op } - { (vmerge-tail) A-vmerge-tail-op } - { (v>integer) A-v-conversion-op } - { (v>float) A-v-conversion-op } - { (vpack-signed) A-vpack-op } - { (vpack-unsigned) A-vpack-op } - { (vunpack-head) A-vunpack-head-op } - { (vunpack-tail) A-vunpack-tail-op } - } >>special-wrappers - { - { { +vector+ +vector+ -> +vector+ } A-vv->v-op } - { { +vector+ +scalar+ -> +vector+ } A-vn->v-op } - { { +vector+ +literal+ -> +vector+ } A-vn->v-op } - { { +vector+ -> +vector+ } A-v->v-op } - } >>schema-wrappers -(define-simd-256) - -;FUNCTOR diff --git a/basis/math/vectors/simd/intrinsics/authors.txt b/basis/math/vectors/simd/intrinsics/authors.txt deleted file mode 100644 index d4f5d6b3ae..0000000000 --- a/basis/math/vectors/simd/intrinsics/authors.txt +++ /dev/null @@ -1 +0,0 @@ -Slava Pestov \ No newline at end of file diff --git a/basis/math/vectors/simd/intrinsics/intrinsics-tests.factor b/basis/math/vectors/simd/intrinsics/intrinsics-tests.factor deleted file mode 100644 index 84eee935a0..0000000000 --- a/basis/math/vectors/simd/intrinsics/intrinsics-tests.factor +++ /dev/null @@ -1,18 +0,0 @@ -IN: math.vectors.simd.intrinsics.tests -USING: math.vectors.simd.intrinsics cpu.architecture tools.test ; - -[ 16 ] [ uchar-16-rep rep-components ] unit-test -[ 16 ] [ char-16-rep rep-components ] unit-test -[ 8 ] [ ushort-8-rep rep-components ] unit-test -[ 8 ] [ short-8-rep rep-components ] unit-test -[ 4 ] [ uint-4-rep rep-components ] unit-test -[ 4 ] [ int-4-rep rep-components ] unit-test -[ 4 ] [ float-4-rep rep-components ] unit-test -[ 2 ] [ double-2-rep rep-components ] unit-test - -{ 4 1 } [ uint-4-rep (simd-boa) ] must-infer-as -{ 4 1 } [ int-4-rep (simd-boa) ] must-infer-as -{ 4 1 } [ float-4-rep (simd-boa) ] must-infer-as -{ 2 1 } [ double-2-rep (simd-boa) ] must-infer-as - - diff --git a/basis/math/vectors/simd/intrinsics/intrinsics.factor b/basis/math/vectors/simd/intrinsics/intrinsics.factor index 003b42fe83..d80755a6a5 100644 --- a/basis/math/vectors/simd/intrinsics/intrinsics.factor +++ b/basis/math/vectors/simd/intrinsics/intrinsics.factor @@ -1,207 +1,255 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: alien alien.c-types alien.data assocs combinators -cpu.architecture compiler.cfg.comparisons fry generalizations -kernel libc macros math -math.vectors.conversion.backend -sequences sets effects accessors namespaces -lexer parser vocabs.parser words arrays math.vectors ; +! (c)2009 Slava Pestov, Joe Groff bsd license +USING: accessors alien alien.c-types alien.data combinators +sequences.cords cpu.architecture fry generalizations grouping +kernel libc locals math math.libm math.order math.ranges +math.vectors sequences sequences.private specialized-arrays +vocabs.loader ; +QUALIFIED-WITH: alien.c-types c +SPECIALIZED-ARRAYS: + c:char c:short c:int c:longlong + c:uchar c:ushort c:uint c:ulonglong + c:float c:double ; IN: math.vectors.simd.intrinsics -ERROR: bad-simd-call word ; - -<< - -: simd-effect ( word -- effect ) - stack-effect [ in>> "rep" suffix ] [ out>> ] bi ; -: simd-conversion-effect ( word -- effect ) - stack-effect [ in>> but-last "rep" suffix ] [ out>> ] bi ; - -SYMBOL: simd-ops - -V{ } clone simd-ops set-global - -: (SIMD-OP:) ( accum quot -- accum ) - [ - scan-word dup name>> "(simd-" ")" surround create-in - [ nip dup '[ _ bad-simd-call ] define ] - ] dip - '[ _ dip set-stack-effect ] - [ 2array simd-ops get push ] - 2tri ; inline - -SYNTAX: SIMD-OP: - [ simd-effect ] (SIMD-OP:) ; - -SYNTAX: SIMD-CONVERSION-OP: - [ simd-conversion-effect ] (SIMD-OP:) ; - ->> - -SIMD-OP: v+ -SIMD-OP: v- -SIMD-OP: vneg -SIMD-OP: v+- -SIMD-OP: vs+ -SIMD-OP: vs- -SIMD-OP: vs* -SIMD-OP: v* -SIMD-OP: v/ -SIMD-OP: vmin -SIMD-OP: vmax -SIMD-OP: v. -SIMD-OP: vsqrt -SIMD-OP: sum -SIMD-OP: vabs -SIMD-OP: vbitand -SIMD-OP: vbitandn -SIMD-OP: vbitor -SIMD-OP: vbitxor -SIMD-OP: vbitnot -SIMD-OP: vand -SIMD-OP: vandn -SIMD-OP: vor -SIMD-OP: vxor -SIMD-OP: vnot -SIMD-OP: vlshift -SIMD-OP: vrshift -SIMD-OP: hlshift -SIMD-OP: hrshift -SIMD-OP: vshuffle-elements -SIMD-OP: vshuffle-bytes -SIMD-OP: (vmerge-head) -SIMD-OP: (vmerge-tail) -SIMD-OP: v<= -SIMD-OP: v< -SIMD-OP: v= -SIMD-OP: v> -SIMD-OP: v>= -SIMD-OP: vunordered? -SIMD-OP: vany? -SIMD-OP: vall? -SIMD-OP: vnone? - -SIMD-CONVERSION-OP: (v>float) -SIMD-CONVERSION-OP: (v>integer) -SIMD-CONVERSION-OP: (vpack-signed) -SIMD-CONVERSION-OP: (vpack-unsigned) -SIMD-CONVERSION-OP: (vunpack-head) -SIMD-CONVERSION-OP: (vunpack-tail) - -: (simd-with) ( x rep -- v ) bad-simd-call ; -: (simd-gather-2) ( a b rep -- v ) bad-simd-call ; -: (simd-gather-4) ( a b c d rep -- v ) bad-simd-call ; -: (simd-select) ( v n rep -- x ) bad-simd-call ; - : assert-positive ( x -- y ) ; -: alien-vector ( c-ptr n rep -- value ) - ! Inefficient version for when intrinsics are missing - [ swap ] dip rep-size memory>byte-array ; +bitwise-vector-rep ( rep -- rep' ) + { + { float-4-rep [ uint-4-rep ] } + { double-2-rep [ ulonglong-2-rep ] } + [ ] + } case ; foldable + +: >uint-vector-rep ( rep -- rep' ) + { + { longlong-2-rep [ ulonglong-2-rep ] } + { int-4-rep [ uint-4-rep ] } + { short-8-rep [ ushort-8-rep ] } + { char-16-rep [ uchar-16-rep ] } + [ ] + } case ; foldable + +: >int-vector-rep ( rep -- rep' ) + { + { float-4-rep [ int-4-rep ] } + { double-2-rep [ longlong-2-rep ] } + } case ; foldable + +: >float-vector-rep ( rep -- rep' ) + { + { int-4-rep [ float-4-rep ] } + { longlong-2-rep [ double-2-rep ] } + } case ; foldable + +: [byte>rep-array] ( rep -- class ) + { + { char-16-rep [ [ byte-array>char-array ] ] } + { uchar-16-rep [ [ byte-array>uchar-array ] ] } + { short-8-rep [ [ byte-array>short-array ] ] } + { ushort-8-rep [ [ byte-array>ushort-array ] ] } + { int-4-rep [ [ byte-array>int-array ] ] } + { uint-4-rep [ [ byte-array>uint-array ] ] } + { longlong-2-rep [ [ byte-array>longlong-array ] ] } + { ulonglong-2-rep [ [ byte-array>ulonglong-array ] ] } + { float-4-rep [ [ byte-array>float-array ] ] } + { double-2-rep [ [ byte-array>double-array ] ] } + } case ; foldable + +: [>rep-array] ( rep -- class ) + { + { char-16-rep [ [ >char-array ] ] } + { uchar-16-rep [ [ >uchar-array ] ] } + { short-8-rep [ [ >short-array ] ] } + { ushort-8-rep [ [ >ushort-array ] ] } + { int-4-rep [ [ >int-array ] ] } + { uint-4-rep [ [ >uint-array ] ] } + { longlong-2-rep [ [ >longlong-array ] ] } + { ulonglong-2-rep [ [ >ulonglong-array ] ] } + { float-4-rep [ [ >float-array ] ] } + { double-2-rep [ [ >double-array ] ] } + } case ; foldable + +: [] ( rep -- class ) + { + { char-16-rep [ [ 16 (char-array) ] ] } + { uchar-16-rep [ [ 16 (uchar-array) ] ] } + { short-8-rep [ [ 8 (short-array) ] ] } + { ushort-8-rep [ [ 8 (ushort-array) ] ] } + { int-4-rep [ [ 4 (int-array) ] ] } + { uint-4-rep [ [ 4 (uint-array) ] ] } + { longlong-2-rep [ [ 2 (longlong-array) ] ] } + { ulonglong-2-rep [ [ 2 (ulonglong-array) ] ] } + { float-4-rep [ [ 4 (float-array) ] ] } + { double-2-rep [ [ 2 (double-array) ] ] } + } case ; foldable + +: rep-tf-values ( rep -- t f ) + float-vector-rep? [ -1 bits>double 0.0 ] [ -1 0 ] if ; + +: >rep-array ( a rep -- a' ) + [byte>rep-array] call( a -- a' ) ; inline +: 2>rep-array ( a b rep -- a' b' ) + [byte>rep-array] '[ _ call( a -- a' ) ] bi@ ; inline +: ( rep -- a' ) + [] call( -- a' ) ; inline + +: components-map ( a rep quot -- c ) + [ >rep-array ] dip map underlying>> ; inline +: components-2map ( a b rep quot -- c ) + [ 2>rep-array ] dip 2map underlying>> ; inline +: components-reduce ( a rep quot -- x ) + [ >rep-array [ ] ] dip map-reduce ; inline + +: bitwise-components-map ( a rep quot -- c ) + [ >bitwise-vector-rep >rep-array ] dip map underlying>> ; inline +: bitwise-components-2map ( a b rep quot -- c ) + [ >bitwise-vector-rep 2>rep-array ] dip 2map underlying>> ; inline +: bitwise-components-reduce ( a rep quot -- x ) + [ >bitwise-vector-rep >rep-array [ ] ] dip map-reduce ; inline + +:: (vshuffle) ( a elts rep -- c ) + a rep >rep-array :> a' + rep :> c' + elts [| from to | + from rep rep-length 1 - bitand + a' nth-unsafe + to c' set-nth-unsafe + ] each-index + c' underlying>> ; inline + +PRIVATE> + +: (simd-v+) ( a b rep -- c ) [ + ] components-2map ; +: (simd-v-) ( a b rep -- c ) [ - ] components-2map ; +: (simd-vneg) ( a rep -- c ) [ neg ] components-map ; +:: (simd-v+-) ( a b rep -- c ) + a b rep 2>rep-array :> ( a' b' ) + rep :> c' + 0 rep rep-length 1 - 2 [| n | + n a' nth-unsafe n b' nth-unsafe - + n c' set-nth-unsafe + + n 1 + a' nth-unsafe n 1 + b' nth-unsafe + + n 1 + c' set-nth-unsafe + ] each + c' underlying>> ; +: (simd-vs+) ( a b rep -- c ) + dup rep-component-type '[ + _ c-type-clamp ] components-2map ; +: (simd-vs-) ( a b rep -- c ) + dup rep-component-type '[ - _ c-type-clamp ] components-2map ; +: (simd-vs*) ( a b rep -- c ) + dup rep-component-type '[ * _ c-type-clamp ] components-2map ; +: (simd-v*) ( a b rep -- c ) [ * ] components-2map ; +: (simd-v*high) ( a b rep -- c ) + dup rep-component-type heap-size -8 * '[ * _ shift ] components-2map ; +:: (simd-v*hs+) ( a b rep -- c ) + rep { char-16-rep uchar-16-rep } member-eq? + [ uchar-16-rep char-16-rep ] + [ rep rep ] if :> ( a-rep b-rep ) + b-rep widen-vector-rep signed-rep :> wide-rep + wide-rep rep-component-type :> wide-type + a a-rep >rep-array 2 :> a' + b b-rep >rep-array 2 :> b' + a' b' [ + [ [ first ] bi@ * ] + [ [ second ] bi@ * ] 2bi + + wide-type c-type-clamp + ] wide-rep 2map-as underlying>> ; +: (simd-v/) ( a b rep -- c ) [ / ] components-2map ; +: (simd-vavg) ( a b rep -- c ) + [ + dup integer? [ 1 + -1 shift ] [ 0.5 * ] if ] components-2map ; +: (simd-vmin) ( a b rep -- c ) [ min ] components-2map ; +: (simd-vmax) ( a b rep -- c ) [ max ] components-2map ; +: (simd-v.) ( a b rep -- n ) + [ 2>rep-array [ [ first ] bi@ * ] 2keep ] keep + 1 swap rep-length [a,b) [ '[ _ swap nth-unsafe ] bi@ * + ] with with each ; +: (simd-vsqrt) ( a rep -- c ) [ fsqrt ] components-map ; +: (simd-vsad) ( a b rep -- c ) 2>rep-array [ - abs ] [ + ] 2map-reduce ; +: (simd-sum) ( a rep -- n ) [ + ] components-reduce ; +: (simd-vabs) ( a rep -- c ) [ abs ] components-map ; +: (simd-vbitand) ( a b rep -- c ) [ bitand ] bitwise-components-2map ; +: (simd-vbitandn) ( a b rep -- c ) [ [ bitnot ] dip bitand ] bitwise-components-2map ; +: (simd-vbitor) ( a b rep -- c ) [ bitor ] bitwise-components-2map ; +: (simd-vbitxor) ( a b rep -- c ) [ bitxor ] bitwise-components-2map ; +: (simd-vbitnot) ( a rep -- c ) [ bitnot ] bitwise-components-map ; +: (simd-vand) ( a b rep -- c ) [ bitand ] bitwise-components-2map ; +: (simd-vandn) ( a b rep -- c ) [ [ bitnot ] dip bitand ] bitwise-components-2map ; +: (simd-vor) ( a b rep -- c ) [ bitor ] bitwise-components-2map ; +: (simd-vxor) ( a b rep -- c ) [ bitxor ] bitwise-components-2map ; +: (simd-vnot) ( a rep -- c ) [ bitnot ] bitwise-components-map ; +: (simd-vlshift) ( a n rep -- c ) swap '[ _ shift ] bitwise-components-map ; +: (simd-vrshift) ( a n rep -- c ) swap '[ _ neg shift ] bitwise-components-map ; +: (simd-hlshift) ( a n rep -- c ) + drop head-slice* 16 0 pad-head ; +: (simd-hrshift) ( a n rep -- c ) + drop tail-slice 16 0 pad-tail ; +: (simd-vshuffle-elements) ( a n rep -- c ) [ rep-length 0 pad-tail ] keep (vshuffle) ; +: (simd-vshuffle-bytes) ( a b rep -- c ) drop uchar-16-rep (vshuffle) ; +:: (simd-vmerge-head) ( a b rep -- c ) + a b rep 2>rep-array :> ( a' b' ) + rep :> c' + rep rep-length 2 /i iota [| n | + n a' nth-unsafe n 2 * c' set-nth-unsafe + n b' nth-unsafe n 2 * 1 + c' set-nth-unsafe + ] each + c' underlying>> ; +:: (simd-vmerge-tail) ( a b rep -- c ) + a b rep 2>rep-array :> ( a' b' ) + rep :> c' + rep rep-length 2 /i :> len + len iota [| n | + n len + a' nth-unsafe n 2 * c' set-nth-unsafe + n len + b' nth-unsafe n 2 * 1 + c' set-nth-unsafe + ] each + c' underlying>> ; +: (simd-v<=) ( a b rep -- c ) + dup rep-tf-values '[ <= _ _ ? ] components-2map ; +: (simd-v<) ( a b rep -- c ) + dup rep-tf-values '[ < _ _ ? ] components-2map ; +: (simd-v=) ( a b rep -- c ) + dup rep-tf-values '[ = _ _ ? ] components-2map ; +: (simd-v>) ( a b rep -- c ) + dup rep-tf-values '[ > _ _ ? ] components-2map ; +: (simd-v>=) ( a b rep -- c ) + dup rep-tf-values '[ >= _ _ ? ] components-2map ; +: (simd-vunordered?) ( a b rep -- c ) + dup rep-tf-values '[ unordered? _ _ ? ] components-2map ; +: (simd-vany?) ( a rep -- ? ) [ bitor ] bitwise-components-reduce zero? not ; +: (simd-vall?) ( a rep -- ? ) [ bitand ] bitwise-components-reduce zero? not ; +: (simd-vnone?) ( a rep -- ? ) [ bitor ] bitwise-components-reduce zero? ; +: (simd-v>float) ( a rep -- c ) + [ >rep-array [ >float ] ] [ >float-vector-rep ] bi map-as underlying>> ; +: (simd-v>integer) ( a rep -- c ) + [ >rep-array [ >integer ] ] [ >int-vector-rep ] bi map-as underlying>> ; +: (simd-vpack-signed) ( a b rep -- c ) + [ 2>rep-array cord-append ] + [ narrow-vector-rep [ ] [ rep-component-type ] bi ] bi + '[ _ c-type-clamp ] swap map-as underlying>> ; +: (simd-vpack-unsigned) ( a b rep -- c ) + [ 2>rep-array cord-append ] + [ narrow-vector-rep >uint-vector-rep [ ] [ rep-component-type ] bi ] bi + '[ _ c-type-clamp ] swap map-as underlying>> ; +: (simd-vunpack-head) ( a rep -- c ) + [ >rep-array ] [ widen-vector-rep [ rep-length ] [ [>rep-array] ] bi ] bi + [ head-slice ] dip call( a' -- c' ) underlying>> ; +: (simd-vunpack-tail) ( a rep -- c ) + [ >rep-array ] [ widen-vector-rep [ rep-length ] [ [>rep-array] ] bi ] bi + [ tail-slice ] dip call( a' -- c' ) underlying>> ; +: (simd-with) ( n rep -- v ) + [ rep-length swap '[ _ ] ] [ ] bi replicate-as + underlying>> ; +: (simd-gather-2) ( m n rep -- v ) [ 2 set-firstn ] keep underlying>> ; +: (simd-gather-4) ( m n o p rep -- v ) [ 4 set-firstn ] keep underlying>> ; +: (simd-select) ( a n rep -- x ) [ swap ] dip >rep-array nth-unsafe ; + +: alien-vector ( c-ptr n rep -- value ) + [ swap ] dip rep-size memory>byte-array ; +: set-alien-vector ( value c-ptr n rep -- ) [ swap swap ] dip rep-size memcpy ; -<< +"compiler.cfg.intrinsics.simd" require +"compiler.tree.propagation.simd" require +"compiler.cfg.value-numbering.simd" require -: rep-components ( rep -- n ) - 16 swap rep-component-type heap-size /i ; foldable - -: rep-coercer ( rep -- quot ) - { - { [ dup int-vector-rep? ] [ [ >fixnum ] ] } - { [ dup float-vector-rep? ] [ [ >float ] ] } - } cond nip ; foldable - -: rep-coerce ( value rep -- value' ) - rep-coercer call( value -- value' ) ; inline - -CONSTANT: rep-gather-words - { - { 2 (simd-gather-2) } - { 4 (simd-gather-4) } - } - -: rep-gather-word ( rep -- word ) - rep-components rep-gather-words at ; - ->> - -MACRO: (simd-boa) ( rep -- quot ) - { - [ rep-coercer ] - [ rep-components ] - [ ] - [ rep-gather-word ] - } cleave - '[ _ _ napply _ _ execute ] ; - -GENERIC# supported-simd-op? 1 ( rep intrinsic -- ? ) - -: (%unpack-reps) ( -- reps ) - %merge-vector-reps [ int-vector-rep? ] filter - %unpack-vector-head-reps union ; - -: (%abs-reps) ( -- reps ) - cc> %compare-vector-reps [ int-vector-rep? ] filter - %xor-vector-reps [ float-vector-rep? ] filter - union - [ { } ] [ { uchar-16-rep ushort-8-rep uint-4-rep ulonglong-2-rep } union ] if-empty ; - -: (%shuffle-imm-reps) ( -- reps ) - %shuffle-vector-reps %shuffle-vector-imm-reps union ; - -M: vector-rep supported-simd-op? - { - { \ (simd-v+) [ %add-vector-reps ] } - { \ (simd-vs+) [ %saturated-add-vector-reps ] } - { \ (simd-v+-) [ %add-sub-vector-reps ] } - { \ (simd-v-) [ %sub-vector-reps ] } - { \ (simd-vs-) [ %saturated-sub-vector-reps ] } - { \ (simd-vneg) [ %sub-vector-reps ] } - { \ (simd-v*) [ %mul-vector-reps ] } - { \ (simd-vs*) [ %saturated-mul-vector-reps ] } - { \ (simd-v/) [ %div-vector-reps ] } - { \ (simd-vmin) [ %min-vector-reps cc< %compare-vector-reps union ] } - { \ (simd-vmax) [ %max-vector-reps cc> %compare-vector-reps union ] } - { \ (simd-v.) [ %dot-vector-reps ] } - { \ (simd-vsqrt) [ %sqrt-vector-reps ] } - { \ (simd-sum) [ %horizontal-add-vector-reps ] } - { \ (simd-vabs) [ (%abs-reps) ] } - { \ (simd-vbitand) [ %and-vector-reps ] } - { \ (simd-vbitandn) [ %andn-vector-reps ] } - { \ (simd-vbitor) [ %or-vector-reps ] } - { \ (simd-vbitxor) [ %xor-vector-reps ] } - { \ (simd-vbitnot) [ %xor-vector-reps ] } - { \ (simd-vand) [ %and-vector-reps ] } - { \ (simd-vandn) [ %andn-vector-reps ] } - { \ (simd-vor) [ %or-vector-reps ] } - { \ (simd-vxor) [ %xor-vector-reps ] } - { \ (simd-vnot) [ %xor-vector-reps ] } - { \ (simd-vlshift) [ %shl-vector-reps ] } - { \ (simd-vrshift) [ %shr-vector-reps ] } - { \ (simd-hlshift) [ %horizontal-shl-vector-imm-reps ] } - { \ (simd-hrshift) [ %horizontal-shr-vector-imm-reps ] } - { \ (simd-vshuffle-elements) [ (%shuffle-imm-reps) ] } - { \ (simd-vshuffle-bytes) [ %shuffle-vector-reps ] } - { \ (simd-(vmerge-head)) [ %merge-vector-reps ] } - { \ (simd-(vmerge-tail)) [ %merge-vector-reps ] } - { \ (simd-(v>float)) [ %integer>float-vector-reps ] } - { \ (simd-(v>integer)) [ %float>integer-vector-reps ] } - { \ (simd-(vpack-signed)) [ %signed-pack-vector-reps ] } - { \ (simd-(vpack-unsigned)) [ %unsigned-pack-vector-reps ] } - { \ (simd-(vunpack-head)) [ (%unpack-reps) ] } - { \ (simd-(vunpack-tail)) [ (%unpack-reps) ] } - { \ (simd-v<=) [ unsign-rep cc<= %compare-vector-reps ] } - { \ (simd-v<) [ unsign-rep cc< %compare-vector-reps ] } - { \ (simd-v=) [ unsign-rep cc= %compare-vector-reps ] } - { \ (simd-v>) [ unsign-rep cc> %compare-vector-reps ] } - { \ (simd-v>=) [ unsign-rep cc>= %compare-vector-reps ] } - { \ (simd-vunordered?) [ unsign-rep cc/<>= %compare-vector-reps ] } - { \ (simd-gather-2) [ %gather-vector-2-reps ] } - { \ (simd-gather-4) [ %gather-vector-4-reps ] } - { \ (simd-vany?) [ %test-vector-reps ] } - { \ (simd-vall?) [ %test-vector-reps ] } - { \ (simd-vnone?) [ %test-vector-reps ] } - } case member? ; diff --git a/basis/math/vectors/simd/mirrors/mirrors.factor b/basis/math/vectors/simd/mirrors/mirrors.factor new file mode 100644 index 0000000000..e8a103d449 --- /dev/null +++ b/basis/math/vectors/simd/mirrors/mirrors.factor @@ -0,0 +1,3 @@ +USING: math.vectors.simd mirrors ; +IN: math.vectors.simd.mirrors +INSTANCE: simd-128 enumerated-sequence diff --git a/basis/math/vectors/simd/simd-docs.factor b/basis/math/vectors/simd/simd-docs.factor index 2fbe823965..540838bdd5 100644 --- a/basis/math/vectors/simd/simd-docs.factor +++ b/basis/math/vectors/simd/simd-docs.factor @@ -1,6 +1,6 @@ USING: classes.tuple.private cpu.architecture help.markup -help.syntax kernel.private math math.vectors -math.vectors.simd.intrinsics sequences ; +help.syntax kernel.private math math.vectors math.vectors.simd.intrinsics +sequences ; IN: math.vectors.simd ARTICLE: "math.vectors.simd.intro" "Introduction to SIMD support" @@ -19,11 +19,11 @@ $nl ARTICLE: "math.vectors.simd.support" "Supported SIMD instruction sets and operations" "At present, the SIMD support makes use of a subset of SSE up to SSE4.1. The subset used depends on the current CPU type." $nl -"SSE1 only supports single-precision SIMD (" { $snippet "float-4" } " and " { $snippet "float-8" } ")." +"SSE1 only supports single-precision SIMD (" { $snippet "float-4" } ")." $nl -"SSE2 introduces double-precision SIMD (" { $snippet "double-2" } " and " { $snippet "double-4" } ") and integer SIMD (all types). Integer SIMD is missing a few features, in particular the " { $link vmin } " and " { $link vmax } " operations only work on " { $snippet "uchar-16" } " and " { $snippet "short-8" } "." +"SSE2 introduces double-precision SIMD (" { $snippet "double-2" } ") and integer SIMD (all types). Integer SIMD is missing a few features; in particular, the " { $link vmin } " and " { $link vmax } " operations only work on " { $snippet "uchar-16" } " and " { $snippet "short-8" } "." $nl -"SSE3 introduces horizontal adds (summing all components of a single vector register), which is useful for computing dot products. Where available, SSE3 operations are used to speed up " { $link sum } ", " { $link v. } ", " { $link norm-sq } ", " { $link norm } ", and " { $link distance } "." +"SSE3 introduces horizontal adds (summing all components of a single vector register), which are useful for computing dot products. Where available, SSE3 operations are used to speed up " { $link sum } ", " { $link v. } ", " { $link norm-sq } ", " { $link norm } ", and " { $link distance } "." $nl "SSSE3 introduces " { $link vabs } " for " { $snippet "char-16" } ", " { $snippet "short-8" } " and " { $snippet "int-4" } "." $nl @@ -36,47 +36,18 @@ $nl ARTICLE: "math.vectors.simd.types" "SIMD vector types" "Each SIMD vector type is named " { $snippet "scalar-count" } ", where " { $snippet "scalar" } " is a scalar C type and " { $snippet "count" } " is a vector dimension." $nl -"To use a SIMD vector type, a parsing word is used to generate the relevant code and bring it into the vocabulary search path; this is the same idea as with " { $link "specialized-arrays" } ":" -{ $subsections - POSTPONE: SIMD: - POSTPONE: SIMDS: -} -"The following scalar types are supported:" -{ $code - "char" - "uchar" - "short" - "ushort" - "int" - "uint" - "longlong" - "ulonglong" - "float" - "double" -} - -"The following vector types are generated from the above scalar types:" +"The following vector types are available:" { $code "char-16" "uchar-16" - "char-32" - "uchar-32" "short-8" "ushort-8" - "short-16" - "ushort-16" "int-4" "uint-4" - "int-8" - "uint-8" "longlong-2" "ulonglong-2" - "longlong-4" - "ulonglong-4" "float-4" - "float-8" "double-2" - "double-4" } ; ARTICLE: "math.vectors.simd.words" "SIMD vector words" @@ -103,19 +74,17 @@ $nl { $code """USING: compiler.tree.debugger math.vectors math.vectors.simd ; -SIMD: double SYMBOLS: x y ; [ - double-4{ 1.5 2.0 3.7 0.4 } x set - double-4{ 1.5 2.0 3.7 0.4 } y set + float-4{ 1.5 2.0 3.7 0.4 } x set + float-4{ 1.5 2.0 3.7 0.4 } y set x get y get v+ ] optimizer-report.""" } "The following word benefits from SIMD optimization, because it begins with an unsafe declaration:" { $code """USING: compiler.tree.debugger kernel.private math.vectors math.vectors.simd ; -SIMD: float IN: simd-demo : interpolate ( v a b -- w ) @@ -129,7 +98,6 @@ $nl { $code """USING: compiler.tree.debugger hints math.vectors math.vectors.simd ; -SIMD: float IN: simd-demo : interpolate ( v a b -- w ) @@ -145,7 +113,6 @@ $nl "In the " { $snippet "interpolate" } " word, there is still a call to the " { $link } " primitive, because the return value at the end is being boxed on the heap. In the next example, no memory allocation occurs at all because the SIMD vectors are stored inside a struct class (see " { $link "classes.struct" } "); also note the use of inlining:" { $code """USING: compiler.tree.debugger math.vectors math.vectors.simd ; -SIMD: float IN: simd-demo STRUCT: actor @@ -182,7 +149,6 @@ ARTICLE: "math.vectors.simd.intrinsics" "Low-level SIMD primitives" { $list "They operate on raw byte arrays, with a separate “representation†parameter passed in to determine the type of the operands and result." "They are unsafe; passing values which are not byte arrays, or byte arrays with the wrong size, will dereference invalid memory and possibly crash Factor." - { "They do not have software fallbacks; if the current CPU does not have SIMD support, a " { $link bad-simd-call } " error will be thrown." } } "The compiler converts " { $link "math-vectors" } " into SIMD primitives automatically in cases where it is safe; this means that the input types are known to be SIMD vectors, and the CPU supports SIMD." $nl @@ -203,7 +169,7 @@ $nl ARTICLE: "math.vectors.simd.accuracy" "Numerical accuracy of SIMD primitives" "No guarantees are made that " { $vocab-link "math.vectors.simd" } " words will give identical results on different SSE versions, or between the hardware intrinsics and the software fallbacks." $nl -"In particular, horizontal operations on " { $snippet "float-4" } " and " { $snippet "float-8" } " are affected by this. They are computed with lower precision in intrinsics than the software fallback. Horizontal operations include anything involving adding together the components of a vector, such as " { $link sum } " or " { $link normalize } "." ; +"In particular, horizontal operations on " { $snippet "float-4" } " vectors are affected by this. They are computed with lower precision in intrinsics than the software fallback. Horizontal operations include anything involving adding together the components of a vector, such as " { $link sum } " or " { $link normalize } "." ; ARTICLE: "math.vectors.simd" "Hardware vector arithmetic (SIMD)" "The " { $vocab-link "math.vectors.simd" } " vocabulary extends the " { $vocab-link "math.vectors" } " vocabulary to support efficient vector arithmetic on small, fixed-size vectors." @@ -218,16 +184,4 @@ ARTICLE: "math.vectors.simd" "Hardware vector arithmetic (SIMD)" "math.vectors.simd.intrinsics" } ; -HELP: SIMD: -{ $syntax "SIMD: type" } -{ $values { "type" "a scalar C type" } } -{ $description "Defines 128-bit and 256-bit SIMD arrays for holding elements of " { $snippet "type" } " into the vocabulary search path. The allowed scalar types, and the auto-generated type/length vector combinations that result, are listed in " { $link "math.vectors.simd.types" } ". Generated words are documented in " { $link "math.vectors.simd.words" } "." } ; - -HELP: SIMDS: -{ $syntax "SIMDS: type type type ... ;" } -{ $values { "type" "a scalar C type" } } -{ $description "Defines 128-bit and 256-bit SIMD arrays for holding elements of each " { $snippet "type" } " into the vocabulary search path. The possible type/length combinations are listed in " { $link "math.vectors.simd.types" } " and the generated words are documented in " { $link "math.vectors.simd.words" } "." } ; - -{ POSTPONE: SIMD: POSTPONE: SIMDS: } related-words - ABOUT: "math.vectors.simd" diff --git a/basis/math/vectors/simd/simd-tests.factor b/basis/math/vectors/simd/simd-tests.factor index 396b8da22a..342c565dce 100644 --- a/basis/math/vectors/simd/simd-tests.factor +++ b/basis/math/vectors/simd/simd-tests.factor @@ -3,22 +3,14 @@ effects fry io kernel kernel.private math math.functions math.private math.vectors math.vectors.simd math.vectors.simd.private prettyprint random sequences system tools.test vocabs assocs compiler.cfg.debugger words -locals math.vectors.specialization combinators cpu.architecture -math.vectors.conversion.backend -math.vectors.simd.intrinsics namespaces byte-arrays alien +locals combinators cpu.architecture namespaces byte-arrays alien specialized-arrays classes.struct eval classes.algebra sets -quotations math.constants compiler.units ; +quotations math.constants compiler.units splitting ; +FROM: math.vectors.simd.intrinsics => alien-vector set-alien-vector ; QUALIFIED-WITH: alien.c-types c SPECIALIZED-ARRAY: c:float -SIMD: c:char -SIMDS: c:uchar c:short c:ushort c:int c:uint c:longlong c:ulonglong c:float c:double ; IN: math.vectors.simd.tests -! Make sure the functor doesn't generate bogus vocabularies -2 [ [ "USE: math.vectors.simd SIMD: rubinius" eval( -- ) ] must-fail ] times - -[ f ] [ "math.vectors.simd.instances.rubinius" vocab ] unit-test - ! Test type propagation [ V{ float } ] [ [ { float-4 } declare norm-sq ] final-classes ] unit-test @@ -38,10 +30,6 @@ IN: math.vectors.simd.tests [ V{ integer } ] [ [ { longlong-2 } declare second ] final-classes ] unit-test -[ V{ int-8 } ] [ [ { int-8 int-8 } declare v+ ] final-classes ] unit-test - -[ t ] [ [ { int-8 } declare second ] final-classes first integer class<= ] unit-test - ! Test puns; only on x86 cpu x86? [ [ double-2{ 4 1024 } ] [ @@ -55,26 +43,80 @@ CONSTANT: simd-classes { char-16 uchar-16 - char-32 - uchar-32 short-8 ushort-8 - short-16 - ushort-16 int-4 uint-4 - int-8 - uint-8 longlong-2 ulonglong-2 - longlong-4 - ulonglong-4 float-4 - float-8 double-2 - double-4 } +SYMBOLS: -> +vector+ +any-vector+ +scalar+ +boolean+ +nonnegative+ +literal+ ; + +CONSTANT: vector-words + H{ + { [v-] { +vector+ +vector+ -> +vector+ } } + { distance { +vector+ +vector+ -> +nonnegative+ } } + { n*v { +scalar+ +vector+ -> +vector+ } } + { n+v { +scalar+ +vector+ -> +vector+ } } + { n-v { +scalar+ +vector+ -> +vector+ } } + { n/v { +scalar+ +vector+ -> +vector+ } } + { norm { +vector+ -> +nonnegative+ } } + { norm-sq { +vector+ -> +nonnegative+ } } + { normalize { +vector+ -> +vector+ } } + { v* { +vector+ +vector+ -> +vector+ } } + { vs* { +vector+ +vector+ -> +vector+ } } + { v*n { +vector+ +scalar+ -> +vector+ } } + { v*high { +vector+ +vector+ -> +vector+ } } + { v*hs+ { +vector+ +vector+ -> +vector+ } } + { v+ { +vector+ +vector+ -> +vector+ } } + { vs+ { +vector+ +vector+ -> +vector+ } } + { v+- { +vector+ +vector+ -> +vector+ } } + { v+n { +vector+ +scalar+ -> +vector+ } } + { v- { +vector+ +vector+ -> +vector+ } } + { vneg { +vector+ -> +vector+ } } + { vs- { +vector+ +vector+ -> +vector+ } } + { v-n { +vector+ +scalar+ -> +vector+ } } + { v. { +vector+ +vector+ -> +scalar+ } } + { vsad { +vector+ +vector+ -> +scalar+ } } + { v/ { +vector+ +vector+ -> +vector+ } } + { v/n { +vector+ +scalar+ -> +vector+ } } + { vceiling { +vector+ -> +vector+ } } + { vfloor { +vector+ -> +vector+ } } + { vmax { +vector+ +vector+ -> +vector+ } } + { vmin { +vector+ +vector+ -> +vector+ } } + { vavg { +vector+ +vector+ -> +vector+ } } + { vneg { +vector+ -> +vector+ } } + { vtruncate { +vector+ -> +vector+ } } + { sum { +vector+ -> +scalar+ } } + { vabs { +vector+ -> +vector+ } } + { vsqrt { +vector+ -> +vector+ } } + { vbitand { +vector+ +vector+ -> +vector+ } } + { vbitandn { +vector+ +vector+ -> +vector+ } } + { vbitor { +vector+ +vector+ -> +vector+ } } + { vbitxor { +vector+ +vector+ -> +vector+ } } + { vbitnot { +vector+ -> +vector+ } } + { vand { +vector+ +vector+ -> +vector+ } } + { vandn { +vector+ +vector+ -> +vector+ } } + { vor { +vector+ +vector+ -> +vector+ } } + { vxor { +vector+ +vector+ -> +vector+ } } + { vnot { +vector+ -> +vector+ } } + { vlshift { +vector+ +scalar+ -> +vector+ } } + { vrshift { +vector+ +scalar+ -> +vector+ } } + { (vmerge-head) { +vector+ +vector+ -> +vector+ } } + { (vmerge-tail) { +vector+ +vector+ -> +vector+ } } + { v<= { +vector+ +vector+ -> +vector+ } } + { v< { +vector+ +vector+ -> +vector+ } } + { v= { +vector+ +vector+ -> +vector+ } } + { v> { +vector+ +vector+ -> +vector+ } } + { v>= { +vector+ +vector+ -> +vector+ } } + { vunordered? { +vector+ +vector+ -> +vector+ } } + } + +: vector-word-inputs ( schema -- seq ) { -> } split first ; + : with-ctors ( -- seq ) simd-classes [ [ name>> "-with" append ] [ vocabulary>> ] bi lookup ] map ; @@ -82,16 +124,17 @@ CONSTANT: simd-classes simd-classes [ [ name>> "-boa" append ] [ vocabulary>> ] bi lookup ] map ; : check-optimizer ( seq quot eq-quot -- failures ) - '[ + dup '[ @ [ dup [ class ] { } map-as ] dip '[ _ declare @ ] { [ "print-mr" get [ nip test-mr mr. ] [ 2drop ] if ] [ "print-checks" get [ [ . ] bi@ ] [ 2drop ] if ] - [ [ call ] dip call ] - [ [ call ] dip compile-call ] + [ [ [ call ] dip call ] call( quot quot -- result ) ] + [ [ [ call ] dip compile-call ] call( quot quot -- result ) ] + [ [ t "always-inline-simd-intrinsics" [ [ call ] dip compile-call ] with-variable ] call( quot quot -- result ) ] } 2cleave - @ not + [ drop @ ] [ nip @ ] 3bi and not ] filter ; inline "== Checking -new constructors" print @@ -132,7 +175,8 @@ CONSTANT: simd-classes "== Checking vector operations" print : random-int-vector ( class -- vec ) - new [ drop 1,000 random ] map ; + new [ drop 1000 random ] map ; + : random-float-vector ( class -- vec ) new [ drop @@ -158,7 +202,7 @@ CONSTANT: simd-classes { vsqrt n/v v/n v/ normalize } unique assoc-diff ; : remove-integer-words ( alist -- alist' ) - { vlshift vrshift } unique assoc-diff ; + { vlshift vrshift v*high v*hs+ } unique assoc-diff ; : boolean-ops ( -- words ) { vand vandn vor vxor vnot } ; @@ -166,26 +210,15 @@ CONSTANT: simd-classes : remove-boolean-words ( alist -- alist' ) boolean-ops unique assoc-diff ; -: remove-special-words ( alist -- alist' ) - ! These have their own tests later - { - hlshift hrshift vshuffle-bytes vshuffle-elements vbroadcast - vany? vall? vnone? - (v>float) (v>integer) - (vpack-signed) (vpack-unsigned) - (vunpack-head) (vunpack-tail) - } unique assoc-diff ; - : ops-to-check ( elt-class -- alist ) [ vector-words >alist ] dip float = [ remove-integer-words ] [ remove-float-words ] if - remove-boolean-words - remove-special-words ; + remove-boolean-words ; : check-vector-ops ( class elt-class compare-quot -- ) [ [ nip ops-to-check ] 2keep - '[ first2 inputs _ _ check-vector-op ] + '[ first2 vector-word-inputs _ _ check-vector-op ] ] dip check-optimizer ; inline : (approx=) ( x y -- ? ) @@ -233,10 +266,10 @@ simd-classes&reps [ ] [ ] map-as word '[ _ execute ] ; -: check-boolean-ops ( class elt-class compare-quot -- ) +: check-boolean-ops ( class elt-class compare-quot -- seq ) [ - [ boolean-ops [ dup word-schema ] { } map>assoc ] 2dip - '[ first2 inputs _ _ check-boolean-op ] + [ boolean-ops [ dup vector-words at ] { } map>assoc ] 2dip + '[ first2 vector-word-inputs _ _ check-boolean-op ] ] dip check-optimizer ; inline simd-classes&reps [ @@ -357,13 +390,15 @@ simd-classes [ new [ drop 16 random ] map ; :: test-shift-vector ( class -- ? ) - class random-int-vector :> src - char-16 random-shift-vector :> perm - { class char-16 } :> decl - - src perm vshuffle - src perm [ decl declare vshuffle ] compile-call - = ; inline + [ + class random-int-vector :> src + char-16 random-shift-vector :> perm + { class char-16 } :> decl + + src perm vshuffle + src perm [ decl declare vshuffle ] compile-call + = + ] call( -- ? ) ; { char-16 uchar-16 short-8 ushort-8 int-4 uint-4 longlong-2 ulonglong-2 } [ 10 swap '[ [ t ] [ _ test-shift-vector ] unit-test ] times ] each @@ -371,19 +406,23 @@ simd-classes [ "== Checking vector tests" print :: test-vector-tests-bool ( vector declaration -- none? any? all? ) - vector - [ [ declaration declare vnone? ] compile-call ] - [ [ declaration declare vany? ] compile-call ] - [ [ declaration declare vall? ] compile-call ] tri ; inline + [ + vector + [ [ declaration declare vnone? ] compile-call ] + [ [ declaration declare vany? ] compile-call ] + [ [ declaration declare vall? ] compile-call ] tri + ] call( -- none? any? all? ) ; : yes ( -- x ) t ; : no ( -- x ) f ; :: test-vector-tests-branch ( vector declaration -- none? any? all? ) - vector - [ [ declaration declare vnone? [ yes ] [ no ] if ] compile-call ] - [ [ declaration declare vany? [ yes ] [ no ] if ] compile-call ] - [ [ declaration declare vall? [ yes ] [ no ] if ] compile-call ] tri ; inline + [ + vector + [ [ declaration declare vnone? [ yes ] [ no ] if ] compile-call ] + [ [ declaration declare vany? [ yes ] [ no ] if ] compile-call ] + [ [ declaration declare vall? [ yes ] [ no ] if ] compile-call ] tri + ] call( -- none? any? all? ) ; TUPLE: inconsistent-vector-test bool branch ; @@ -391,12 +430,14 @@ TUPLE: inconsistent-vector-test bool branch ; 2dup = [ drop ] [ inconsistent-vector-test boa ] if ; :: test-vector-tests ( vector decl -- none? any? all? ) - vector decl test-vector-tests-bool :> ( bool-none bool-any bool-all ) - vector decl test-vector-tests-branch :> ( branch-none branch-any branch-all ) - - bool-none branch-none ?inconsistent - bool-any branch-any ?inconsistent - bool-all branch-all ?inconsistent ; inline + [ + vector decl test-vector-tests-bool :> ( bool-none bool-any bool-all ) + vector decl test-vector-tests-branch :> ( branch-none branch-any branch-all ) + + bool-none branch-none ?inconsistent + bool-any branch-any ?inconsistent + bool-all branch-all ?inconsistent + ] call( -- none? any? all? ) ; [ f t t ] [ float-4{ t t t t } { float-4 } test-vector-tests ] unit-test @@ -419,32 +460,11 @@ TUPLE: inconsistent-vector-test bool branch ; [ t f f ] [ int-4{ f f f f } { int-4 } test-vector-tests ] unit-test -[ f t t ] -[ float-8{ t t t t t t t t } { float-8 } test-vector-tests ] unit-test -[ f t f ] -[ float-8{ f t t t t f t t } { float-8 } test-vector-tests ] unit-test -[ t f f ] -[ float-8{ f f f f f f f f } { float-8 } test-vector-tests ] unit-test - -[ f t t ] -[ double-4{ t t t t } { double-4 } test-vector-tests ] unit-test -[ f t f ] -[ double-4{ f t t f } { double-4 } test-vector-tests ] unit-test -[ t f f ] -[ double-4{ f f f f } { double-4 } test-vector-tests ] unit-test - -[ f t t ] -[ int-8{ t t t t t t t t } { int-8 } test-vector-tests ] unit-test -[ f t f ] -[ int-8{ f t t t t f f f } { int-8 } test-vector-tests ] unit-test -[ t f f ] -[ int-8{ f f f f f f f f } { int-8 } test-vector-tests ] unit-test - "== Checking element access" print ! Test element access -- it should box bignums for int-4 on x86 : test-accesses ( seq -- failures ) - [ length >array ] keep + [ length iota >array ] keep '[ [ _ 1quotation ] dip '[ _ swap nth ] ] [ = ] check-optimizer ; inline [ { } ] [ float-4{ 1.0 2.0 3.0 4.0 } test-accesses ] unit-test @@ -459,18 +479,10 @@ TUPLE: inconsistent-vector-test bool branch ; [ { } ] [ longlong-2{ 1 2 } test-accesses ] unit-test [ { } ] [ ulonglong-2{ 1 2 } test-accesses ] unit-test -[ { } ] [ float-8{ 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 } test-accesses ] unit-test -[ { } ] [ int-8{ 1 2 3 4 5 6 7 8 } test-accesses ] unit-test -[ { } ] [ uint-8{ 1 2 3 4 5 6 7 8 } test-accesses ] unit-test - -[ { } ] [ double-4{ 1.0 2.0 3.0 4.0 } test-accesses ] unit-test -[ { } ] [ longlong-4{ 1 2 3 4 } test-accesses ] unit-test -[ { } ] [ ulonglong-4{ 1 2 3 4 } test-accesses ] unit-test - "== Checking broadcast" print : test-broadcast ( seq -- failures ) - [ length >array ] keep - '[ [ _ 1quotation ] dip '[ _ vbroadcast ] ] [ = ] check-optimizer ; inline + [ length iota >array ] keep + '[ [ _ 1quotation ] dip '[ _ vbroadcast ] ] [ = ] check-optimizer ; [ { } ] [ float-4{ 1.0 2.0 3.0 4.0 } test-broadcast ] unit-test [ { } ] [ int-4{ HEX: 7fffffff 3 4 -8 } test-broadcast ] unit-test @@ -480,14 +492,6 @@ TUPLE: inconsistent-vector-test bool branch ; [ { } ] [ longlong-2{ 1 2 } test-broadcast ] unit-test [ { } ] [ ulonglong-2{ 1 2 } test-broadcast ] unit-test -[ { } ] [ float-8{ 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 } test-broadcast ] unit-test -[ { } ] [ int-8{ 1 2 3 4 5 6 7 8 } test-broadcast ] unit-test -[ { } ] [ uint-8{ 1 2 3 4 5 6 7 8 } test-broadcast ] unit-test - -[ { } ] [ double-4{ 1.0 2.0 3.0 4.0 } test-broadcast ] unit-test -[ { } ] [ longlong-4{ 1 2 3 4 } test-broadcast ] unit-test -[ { } ] [ ulonglong-4{ 1 2 3 4 } test-broadcast ] unit-test - ! Make sure we use the fallback in the correct situations [ int-4{ 3 3 3 3 } ] [ int-4{ 12 34 3 17 } 2 [ { int-4 fixnum } declare vbroadcast ] compile-call ] unit-test @@ -521,37 +525,37 @@ TUPLE: inconsistent-vector-test bool branch ; STRUCT: simd-struct { x float-4 } { y longlong-2 } -{ z double-4 } -{ w int-8 } ; +{ z double-2 } +{ w int-4 } ; [ t ] [ [ simd-struct ] compile-call >c-ptr [ 0 = ] all? ] unit-test [ float-4{ 1 2 3 4 } longlong-2{ 2 1 } - double-4{ 4 3 2 1 } - int-8{ 1 2 3 4 5 6 7 8 } + double-2{ 4 3 } + int-4{ 1 2 3 4 } ] [ simd-struct float-4{ 1 2 3 4 } >>x longlong-2{ 2 1 } >>y - double-4{ 4 3 2 1 } >>z - int-8{ 1 2 3 4 5 6 7 8 } >>w + double-2{ 4 3 } >>z + int-4{ 1 2 3 4 } >>w { [ x>> ] [ y>> ] [ z>> ] [ w>> ] } cleave ] unit-test [ float-4{ 1 2 3 4 } longlong-2{ 2 1 } - double-4{ 4 3 2 1 } - int-8{ 1 2 3 4 5 6 7 8 } + double-2{ 4 3 } + int-4{ 1 2 3 4 } ] [ [ simd-struct float-4{ 1 2 3 4 } >>x longlong-2{ 2 1 } >>y - double-4{ 4 3 2 1 } >>z - int-8{ 1 2 3 4 5 6 7 8 } >>w + double-2{ 4 3 } >>z + int-4{ 1 2 3 4 } >>w { [ x>> ] [ y>> ] [ z>> ] [ w>> ] } cleave ] compile-call ] unit-test @@ -561,9 +565,9 @@ STRUCT: simd-struct [ ] [ char-16 new 1array stack. ] unit-test ! CSSA bug -[ 8000000 ] [ - int-8{ 1000 1000 1000 1000 1000 1000 1000 1000 } - [ { int-8 } declare dup [ * ] [ + ] 2map-reduce ] compile-call +[ 4000000 ] [ + int-4{ 1000 1000 1000 1000 } + [ { int-4 } declare dup [ * ] [ + ] 2map-reduce ] compile-call ] unit-test ! Coalescing was too aggressive diff --git a/basis/math/vectors/simd/simd.factor b/basis/math/vectors/simd/simd.factor index 388fed5f31..acf13599c1 100644 --- a/basis/math/vectors/simd/simd.factor +++ b/basis/math/vectors/simd/simd.factor @@ -1,42 +1,344 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: alien.c-types combinators fry kernel parser math math.parser -math.vectors.simd.functor sequences splitting vocabs.generated -vocabs.loader vocabs.parser words accessors vocabs compiler.units -definitions ; +USING: accessors alien.c-types arrays byte-arrays classes combinators +cpu.architecture effects fry functors generalizations generic +generic.parser kernel lexer literals macros math math.functions +math.vectors math.vectors.private math.vectors.simd.intrinsics namespaces parser +prettyprint.custom quotations sequences sequences.private vocabs +vocabs.loader words ; QUALIFIED-WITH: alien.c-types c IN: math.vectors.simd -ERROR: bad-base-type type ; +ERROR: bad-simd-length got expected ; + +ERROR: bad-simd-vector obj ; + +<< +> @ ] keep new-underlying ; inline +PRIVATE> +>> > "math.vectors.simd.instances." prepend ; +! Helper for boolean vector literals -: parse-base-type ( c-type -- c-type ) - dup { c:char c:uchar c:short c:ushort c:int c:uint c:longlong c:ulonglong c:float c:double } member-eq? - [ bad-base-type ] unless ; +: vector-true-value ( class -- value ) + { c:float c:double } member? [ -1 bits>double ] [ -1 ] if ; foldable -: forget-instances ( -- ) - [ - "math.vectors.simd.instances" child-vocabs - [ forget-vocab ] each - ] with-compilation-unit ; +: vector-false-value ( type -- value ) + { c:float c:double } member? [ 0.0 ] [ 0 ] if ; foldable + +: boolean>element ( bool/elt type -- elt ) + swap { + { t [ vector-true-value ] } + { f [ vector-false-value ] } + [ nip ] + } case ; inline PRIVATE> -: define-simd-vocab ( type -- vocab ) - parse-base-type - [ simd-vocab ] keep '[ - _ - [ define-simd-128 ] - [ define-simd-256 ] bi - ] generate-vocab ; +! SIMD base type -SYNTAX: SIMD: - scan-word define-simd-vocab use-vocab ; +TUPLE: simd-128 + { underlying byte-array read-only initial: $[ 16 ] } ; -SYNTAX: SIMDS: - \ ; parse-until [ define-simd-vocab use-vocab ] each ; +GENERIC: simd-element-type ( obj -- c-type ) +GENERIC: simd-rep ( simd -- rep ) +GENERIC: simd-with ( n exemplar -- v ) +M: object simd-element-type drop f ; +M: object simd-rep drop f ; + +<< +> ] bi ; inline + +: v->v-op ( a rep quot: ( (a) rep -- (c) ) fallback-quot -- c ) + drop [ simd-unbox ] 2dip 2curry make-underlying ; inline + +: vn->v-op ( a n rep quot: ( (a) n rep -- (c) ) fallback-quot -- c ) + drop [ simd-unbox ] 3dip 3curry make-underlying ; inline + +: vn->n-op ( a n rep quot: ( (a) n rep -- n ) fallback-quot -- n ) + drop [ underlying>> ] 3dip call ; inline + +: v->n-op ( a rep quot: ( (a) rep -- n ) fallback-quot -- n ) + drop [ underlying>> ] 2dip call ; inline + +: (vv->v-op) ( a b rep quot: ( (a) (b) rep -- (c) ) -- c ) + [ [ simd-unbox ] [ underlying>> ] bi* ] 2dip 3curry make-underlying ; inline + +: (vv->n-op) ( a b rep quot: ( (a) (b) rep -- n ) -- n ) + [ [ underlying>> ] bi@ ] 2dip 3curry call ; inline + +: vv->v-op ( a b rep quot: ( (a) (b) rep -- (c) ) fallback-quot -- c ) + [ '[ _ (vv->v-op) ] ] [ '[ drop @ ] ] bi* if-both-vectors-match ; inline + +: vv'->v-op ( a b rep quot: ( (a) (b) rep -- (c) ) fallback-quot -- c ) + [ '[ _ (vv->v-op) ] ] [ '[ drop @ ] ] bi* if-both-vectors ; inline + +: vv->n-op ( a b rep quot: ( (a) (b) rep -- n ) fallback-quot -- n ) + [ '[ _ (vv->n-op) ] ] [ '[ drop @ ] ] bi* if-both-vectors-match ; inline + +PRIVATE> +>> + +<< + +! SIMD vectors as sequences + +M: simd-128 hashcode* underlying>> hashcode* ; inline +M: simd-128 clone [ clone ] change-underlying ; inline +M: simd-128 c:byte-length drop 16 ; inline + +M: simd-128 new-sequence + 2dup length = + [ nip [ 16 (byte-array) ] make-underlying ] + [ length bad-simd-length ] if ; inline + +M: simd-128 equal? + dup simd-rep [ drop v= vall? ] [ 3drop f ] if-both-vectors-match ; inline + +! SIMD primitive operations + +M: simd-128 v+ + dup simd-rep [ (simd-v+) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 v- + dup simd-rep [ (simd-v-) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vneg + dup simd-rep [ (simd-vneg) ] [ call-next-method ] v->v-op ; inline +M: simd-128 v+- + dup simd-rep [ (simd-v+-) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vs+ + dup simd-rep [ (simd-vs+) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vs- + dup simd-rep [ (simd-vs-) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vs* + dup simd-rep [ (simd-vs*) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 v* + dup simd-rep [ (simd-v*) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 v*high + dup simd-rep [ (simd-v*high) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 v/ + dup simd-rep [ (simd-v/) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vavg + dup simd-rep [ (simd-vavg) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vmin + dup simd-rep [ (simd-vmin) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vmax + dup simd-rep [ (simd-vmax) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 v. + dup simd-rep [ (simd-v.) ] [ call-next-method ] vv->n-op ; inline +M: simd-128 vsad + dup simd-rep [ (simd-vsad) ] [ call-next-method ] vv->n-op ; inline +M: simd-128 vsqrt + dup simd-rep [ (simd-vsqrt) ] [ call-next-method ] v->v-op ; inline +M: simd-128 sum + dup simd-rep [ (simd-sum) ] [ call-next-method ] v->n-op ; inline +M: simd-128 vabs + dup simd-rep [ (simd-vabs) ] [ call-next-method ] v->v-op ; inline +M: simd-128 vbitand + dup simd-rep [ (simd-vbitand) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vbitandn + dup simd-rep [ (simd-vbitandn) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vbitor + dup simd-rep [ (simd-vbitor) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vbitxor + dup simd-rep [ (simd-vbitxor) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vbitnot + dup simd-rep [ (simd-vbitnot) ] [ call-next-method ] v->v-op ; inline +M: simd-128 vand + dup simd-rep [ (simd-vand) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vandn + dup simd-rep [ (simd-vandn) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vor + dup simd-rep [ (simd-vor) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vxor + dup simd-rep [ (simd-vxor) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vnot + dup simd-rep [ (simd-vnot) ] [ call-next-method ] v->v-op ; inline +M: simd-128 vlshift + over simd-rep [ (simd-vlshift) ] [ call-next-method ] vn->v-op ; inline +M: simd-128 vrshift + over simd-rep [ (simd-vrshift) ] [ call-next-method ] vn->v-op ; inline +M: simd-128 hlshift + over simd-rep [ (simd-hlshift) ] [ call-next-method ] vn->v-op ; inline +M: simd-128 hrshift + over simd-rep [ (simd-hrshift) ] [ call-next-method ] vn->v-op ; inline +M: simd-128 vshuffle-elements + over simd-rep [ (simd-vshuffle-elements) ] [ call-next-method ] vn->v-op ; inline +M: simd-128 vshuffle-bytes + dup simd-rep [ (simd-vshuffle-bytes) ] [ call-next-method ] vv'->v-op ; inline +M: simd-128 (vmerge-head) + dup simd-rep [ (simd-vmerge-head) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 (vmerge-tail) + dup simd-rep [ (simd-vmerge-tail) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 v<= + dup simd-rep [ (simd-v<=) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 v< + dup simd-rep [ (simd-v<) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 v= + dup simd-rep [ (simd-v=) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 v> + dup simd-rep [ (simd-v>) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 v>= + dup simd-rep [ (simd-v>=) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vunordered? + dup simd-rep [ (simd-vunordered?) ] [ call-next-method ] vv->v-op ; inline +M: simd-128 vany? + dup simd-rep [ (simd-vany?) ] [ call-next-method ] v->n-op ; inline +M: simd-128 vall? + dup simd-rep [ (simd-vall?) ] [ call-next-method ] v->n-op ; inline +M: simd-128 vnone? + dup simd-rep [ (simd-vnone?) ] [ call-next-method ] v->n-op ; inline + +! SIMD high-level specializations + +M: simd-128 vbroadcast swap [ nth ] [ simd-with ] bi ; inline +M: simd-128 n+v [ simd-with ] keep v+ ; inline +M: simd-128 n-v [ simd-with ] keep v- ; inline +M: simd-128 n*v [ simd-with ] keep v* ; inline +M: simd-128 n/v [ simd-with ] keep v/ ; inline +M: simd-128 v+n over simd-with v+ ; inline +M: simd-128 v-n over simd-with v- ; inline +M: simd-128 v*n over simd-with v* ; inline +M: simd-128 v/n over simd-with v/ ; inline +M: simd-128 norm-sq dup v. assert-positive ; inline +M: simd-128 distance v- norm ; inline + +M: simd-128 >pprint-sequence ; +M: simd-128 pprint* pprint-object ; + +A DEFINES >${T} +A-boa DEFINES ${T}-boa +A-with DEFINES ${T}-with +A-cast DEFINES ${T}-cast +A{ DEFINES ${T}{ + +ELT [ A-rep rep-component-type ] +N [ A-rep rep-length ] +COERCER [ ELT c-type-class "coercer" word-prop [ ] or ] + +SET-NTH [ ELT dup c:c-setter c:array-accessor ] + +BOA-EFFECT [ N "n" { "v" } ] + +WHERE + +TUPLE: A < simd-128 ; + +M: A new-underlying drop \ A boa ; inline +M: A simd-rep drop A-rep ; inline +M: A simd-element-type drop ELT ; inline +M: A simd-with drop A-with ; inline + +M: A nth-unsafe + swap \ A-rep [ (simd-select) ] [ call-next-method ] vn->n-op ; inline +M: A set-nth-unsafe + [ ELT boolean>element ] 2dip + underlying>> SET-NTH call ; inline + +: >A ( seq -- simd ) \ A new clone-like ; inline + +M: A like drop dup \ A instance? [ >A ] unless ; inline + +: A-with ( n -- v ) COERCER call \ A-rep (simd-with) \ A boa ; inline +: A-cast ( v -- v' ) underlying>> \ A boa ; inline + +M: A length drop N ; inline + +\ A-boa +[ COERCER N napply ] N { + { 2 [ [ A-rep (simd-gather-2) A boa ] ] } + { 4 [ [ A-rep (simd-gather-4) A boa ] ] } + [ \ A new '[ _ _ nsequence ] ] +} case compose +BOA-EFFECT define-inline + +M: A pprint-delims drop \ A{ \ } ; +SYNTAX: A{ \ } [ >A ] parse-literal ; + +INSTANCE: A sequence + +c: + byte-array >>class + A >>boxed-class + { A-rep alien-vector A boa } >quotation >>getter + { + [ dup simd-128? [ bad-simd-vector ] unless underlying>> ] 2dip + A-rep set-alien-vector + } >quotation >>setter + 16 >>size + 16 >>align + A-rep >>rep +\ A c:typedef + +;FUNCTOR + +SYNTAX: SIMD-128: + scan define-simd-128 ; + +PRIVATE> + +>> + +! SIMD instances + +SIMD-128: char-16 +SIMD-128: uchar-16 +SIMD-128: short-8 +SIMD-128: ushort-8 +SIMD-128: int-4 +SIMD-128: uint-4 +SIMD-128: longlong-2 +SIMD-128: ulonglong-2 +SIMD-128: float-4 +SIMD-128: double-2 + +! misc + +M: simd-128 vshuffle ( u perm -- v ) + vshuffle-bytes ; inline + +M: uchar-16 v*hs+ + uchar-16-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op short-8-cast ; inline +M: ushort-8 v*hs+ + ushort-8-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op uint-4-cast ; inline +M: uint-4 v*hs+ + uint-4-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op ulonglong-2-cast ; inline +M: char-16 v*hs+ + char-16-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op short-8-cast ; inline +M: short-8 v*hs+ + short-8-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op int-4-cast ; inline +M: int-4 v*hs+ + int-4-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op longlong-2-cast ; inline + +"mirrors" vocab [ + "math.vectors.simd.mirrors" require +] when diff --git a/basis/math/vectors/specialization/specialization-tests.factor b/basis/math/vectors/specialization/specialization-tests.factor deleted file mode 100644 index f4d4fd93e8..0000000000 --- a/basis/math/vectors/specialization/specialization-tests.factor +++ /dev/null @@ -1,28 +0,0 @@ -IN: math.vectors.specialization.tests -USING: compiler.tree.debugger math.vectors tools.test kernel -kernel.private math specialized-arrays ; -QUALIFIED-WITH: alien.c-types c -QUALIFIED-WITH: alien.complex c -SPECIALIZED-ARRAY: c:double -SPECIALIZED-ARRAY: c:complex-float -SPECIALIZED-ARRAY: c:float - -[ V{ t } ] [ - [ { double-array double-array } declare distance 0.0 < not ] final-literals -] unit-test - -[ V{ float } ] [ - [ { float-array float } declare v*n norm ] final-classes -] unit-test - -[ V{ complex } ] [ - [ { complex-float-array complex-float-array } declare v. ] final-classes -] unit-test - -[ V{ float } ] [ - [ { float-array float } declare v*n norm ] final-classes -] unit-test - -[ V{ float } ] [ - [ { complex-float-array complex } declare v*n norm ] final-classes -] unit-test \ No newline at end of file diff --git a/basis/math/vectors/specialization/specialization.factor b/basis/math/vectors/specialization/specialization.factor deleted file mode 100644 index 602fd9802c..0000000000 --- a/basis/math/vectors/specialization/specialization.factor +++ /dev/null @@ -1,207 +0,0 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: words kernel make sequences effects sets kernel.private -accessors combinators math math.intervals math.vectors -math.vectors.conversion.backend namespaces assocs fry splitting -classes.algebra generalizations locals -compiler.tree.propagation.info ; -IN: math.vectors.specialization - -SYMBOLS: -> +vector+ +any-vector+ +scalar+ +boolean+ +nonnegative+ +literal+ ; - -: parent-vector-class ( type -- type' ) - { - { [ dup simd-128 class<= ] [ drop simd-128 ] } - { [ dup simd-256 class<= ] [ drop simd-256 ] } - [ "Not a vector class" throw ] - } cond ; - -: signature-for-schema ( array-type elt-type schema -- signature ) - [ - { - { +vector+ [ drop ] } - { +any-vector+ [ drop parent-vector-class ] } - { +scalar+ [ nip ] } - { +boolean+ [ 2drop boolean ] } - { +nonnegative+ [ nip ] } - { +literal+ [ 2drop f ] } - } case - ] with with map ; - -: (specialize-vector-word) ( word array-type elt-type schema -- word' ) - signature-for-schema - [ [ name>> ] [ [ name>> ] map "," join ] bi* "=>" glue f ] - [ [ , \ declare , def>> % ] [ ] make ] - [ drop stack-effect ] - 2tri - [ define-declared ] [ 2drop ] 3bi ; - -: output-infos ( array-type elt-type schema -- value-infos ) - [ - { - { +vector+ [ drop ] } - { +any-vector+ [ drop parent-vector-class ] } - { +scalar+ [ nip ] } - { +boolean+ [ 2drop boolean ] } - { - +nonnegative+ - [ - nip - dup complex class<= [ drop float ] when - [0,inf] - ] - } - } case - ] with with map ; - -: record-output-signature ( word array-type elt-type schema -- word ) - output-infos - [ drop ] - [ drop ] - [ [ stack-effect in>> length '[ _ ndrop ] ] dip append ] 2tri - "outputs" set-word-prop ; - -CONSTANT: vector-words -H{ - { [v-] { +vector+ +vector+ -> +vector+ } } - { distance { +vector+ +vector+ -> +nonnegative+ } } - { n*v { +scalar+ +vector+ -> +vector+ } } - { n+v { +scalar+ +vector+ -> +vector+ } } - { n-v { +scalar+ +vector+ -> +vector+ } } - { n/v { +scalar+ +vector+ -> +vector+ } } - { norm { +vector+ -> +nonnegative+ } } - { norm-sq { +vector+ -> +nonnegative+ } } - { normalize { +vector+ -> +vector+ } } - { v* { +vector+ +vector+ -> +vector+ } } - { vs* { +vector+ +vector+ -> +vector+ } } - { v*n { +vector+ +scalar+ -> +vector+ } } - { v+ { +vector+ +vector+ -> +vector+ } } - { vs+ { +vector+ +vector+ -> +vector+ } } - { v+- { +vector+ +vector+ -> +vector+ } } - { v+n { +vector+ +scalar+ -> +vector+ } } - { v- { +vector+ +vector+ -> +vector+ } } - { vneg { +vector+ -> +vector+ } } - { vs- { +vector+ +vector+ -> +vector+ } } - { v-n { +vector+ +scalar+ -> +vector+ } } - { v. { +vector+ +vector+ -> +scalar+ } } - { v/ { +vector+ +vector+ -> +vector+ } } - { v/n { +vector+ +scalar+ -> +vector+ } } - { vceiling { +vector+ -> +vector+ } } - { vfloor { +vector+ -> +vector+ } } - { vmax { +vector+ +vector+ -> +vector+ } } - { vmin { +vector+ +vector+ -> +vector+ } } - { vneg { +vector+ -> +vector+ } } - { vtruncate { +vector+ -> +vector+ } } - { sum { +vector+ -> +scalar+ } } - { vabs { +vector+ -> +vector+ } } - { vsqrt { +vector+ -> +vector+ } } - { vbitand { +vector+ +vector+ -> +vector+ } } - { vbitandn { +vector+ +vector+ -> +vector+ } } - { vbitor { +vector+ +vector+ -> +vector+ } } - { vbitxor { +vector+ +vector+ -> +vector+ } } - { vbitnot { +vector+ -> +vector+ } } - { vand { +vector+ +vector+ -> +vector+ } } - { vandn { +vector+ +vector+ -> +vector+ } } - { vor { +vector+ +vector+ -> +vector+ } } - { vxor { +vector+ +vector+ -> +vector+ } } - { vnot { +vector+ -> +vector+ } } - { vlshift { +vector+ +scalar+ -> +vector+ } } - { vrshift { +vector+ +scalar+ -> +vector+ } } - { hlshift { +vector+ +literal+ -> +vector+ } } - { hrshift { +vector+ +literal+ -> +vector+ } } - { vshuffle-elements { +vector+ +literal+ -> +vector+ } } - { vshuffle-bytes { +vector+ +any-vector+ -> +vector+ } } - { vbroadcast { +vector+ +literal+ -> +vector+ } } - { (vmerge-head) { +vector+ +vector+ -> +vector+ } } - { (vmerge-tail) { +vector+ +vector+ -> +vector+ } } - { (v>float) { +vector+ +literal+ -> +vector+ } } - { (v>integer) { +vector+ +literal+ -> +vector+ } } - { (vpack-signed) { +vector+ +vector+ +literal+ -> +vector+ } } - { (vpack-unsigned) { +vector+ +vector+ +literal+ -> +vector+ } } - { (vunpack-head) { +vector+ +literal+ -> +vector+ } } - { (vunpack-tail) { +vector+ +literal+ -> +vector+ } } - { v<= { +vector+ +vector+ -> +vector+ } } - { v< { +vector+ +vector+ -> +vector+ } } - { v= { +vector+ +vector+ -> +vector+ } } - { v> { +vector+ +vector+ -> +vector+ } } - { v>= { +vector+ +vector+ -> +vector+ } } - { vunordered? { +vector+ +vector+ -> +vector+ } } - { vany? { +vector+ -> +boolean+ } } - { vall? { +vector+ -> +boolean+ } } - { vnone? { +vector+ -> +boolean+ } } -} - -PREDICATE: vector-word < word vector-words key? ; - -: specializations ( word -- assoc ) - dup "specializations" word-prop - [ ] [ V{ } clone [ "specializations" set-word-prop ] keep ] ?if ; - -M: vector-word subwords specializations values [ word? ] filter ; - -: add-specialization ( new-word signature word -- ) - specializations set-at ; - -ERROR: bad-vector-word word ; - -: word-schema ( word -- schema ) - vector-words ?at [ bad-vector-word ] unless ; - -: inputs ( schema -- seq ) { -> } split first ; - -: outputs ( schema -- seq ) { -> } split second ; - -: loop-vector-op ( word array-type elt-type -- word' ) - pick word-schema - [ inputs (specialize-vector-word) ] - [ outputs record-output-signature ] 3bi ; - -:: specialize-vector-word ( word array-type elt-type simd -- word/quot' ) - word simd key? [ word simd at ] [ word array-type elt-type loop-vector-op ] if ; - -:: input-signature ( word array-type elt-type -- signature ) - array-type elt-type word word-schema inputs signature-for-schema ; - -: vector-words-for-type ( elt-type -- words ) - { - ! Can't do shifts on floats - { [ dup float class<= ] [ vector-words keys { vlshift vrshift } diff ] } - ! Can't divide integers - { [ dup integer class<= ] [ vector-words keys { vsqrt n/v v/n v/ normalize } diff ] } - ! Can't compute square root of complex numbers (vsqrt uses fsqrt not sqrt) - { [ dup complex class<= ] [ vector-words keys { vsqrt } diff ] } - [ { } ] - } cond - ! Don't specialize horizontal shifts, shuffles, and conversions at all, they're only for SIMD - { - hlshift hrshift vshuffle-elements vshuffle-bytes vbroadcast - (v>integer) (v>float) - (vpack-signed) (vpack-unsigned) - (vunpack-head) (vunpack-tail) - } diff - nip ; - -:: specialize-vector-words ( array-type elt-type simd -- ) - elt-type vector-words-for-type simd keys union [ - [ array-type elt-type simd specialize-vector-word ] - [ array-type elt-type input-signature ] - [ ] - tri add-specialization - ] each ; - -: specialization-matches? ( value-infos signature -- ? ) - [ [ [ class>> ] dip class<= ] [ literal?>> ] if* ] 2all? ; - -: find-specialization ( classes word -- word/f ) - specializations - [ first specialization-matches? ] with find - swap [ second ] when ; - -: vector-word-custom-inlining ( #call -- word/f ) - [ in-d>> [ value-info ] map ] [ word>> ] bi - find-specialization ; - -vector-words keys [ - [ vector-word-custom-inlining ] - "custom-inlining" set-word-prop -] each diff --git a/basis/math/vectors/vectors-docs.factor b/basis/math/vectors/vectors-docs.factor index b831ac7dbe..59246a6e64 100644 --- a/basis/math/vectors/vectors-docs.factor +++ b/basis/math/vectors/vectors-docs.factor @@ -125,8 +125,6 @@ ARTICLE: "math-vectors-simd-logic" "Componentwise logic with SIMD vectors" "Processor SIMD units supported by the " { $vocab-link "math.vectors.simd" } " vocabulary represent boolean values as bitmasks, where a true result's binary representation is all ones and a false representation is all zeroes. This is the format in which results from comparison words such as " { $link v= } " return their results and in which logic and test words such as " { $link vand } " and " { $link vall? } " take their inputs when working with SIMD types. For a float vector, false will manifest itself as " { $snippet "0.0" } " and true as a " { $link POSTPONE: NAN: } " literal with a string of set bits in its payload:" { $example """USING: math.vectors math.vectors.simd prettyprint ; -FROM: alien.c-types => float ; -SIMD: float float-4{ 1.0 2.0 3.0 0/0. } float-4{ 1.0 -2.0 3.0 0/0. } v= .""" """float-4{ NAN: fffffe0000000 0.0 NAN: fffffe0000000 0.0 }""" @@ -134,8 +132,6 @@ float-4{ 1.0 2.0 3.0 0/0. } float-4{ 1.0 -2.0 3.0 0/0. } v= .""" "For an integer vector, false will manifest as " { $snippet "0" } " and true as " { $snippet "-1" } " (for signed vectors) or the largest representable value of the element type (for unsigned vectors):" { $example """USING: math.vectors math.vectors.simd prettyprint alien.c-types ; -SIMD: int -SIMD: uchar int-4{ 1 2 3 0 } int-4{ 1 -2 3 4 } v= uchar-16{ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 } @@ -147,7 +143,6 @@ uchar-16{ 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 }""" "This differs from Factor's native representation of boolean values, where " { $link f } " is false and every other value (including " { $snippet "0" } " and " { $snippet "0.0" } ") is true. To make it easy to construct literal SIMD masks, " { $link t } " and " { $link f } " are accepted inside SIMD literal syntax and expand to the proper true or false representation for the underlying type:" { $example """USING: math.vectors math.vectors.simd prettyprint alien.c-types ; -SIMD: int int-4{ f f t f } .""" """int-4{ 0 0 -1 0 }""" } @@ -216,36 +211,36 @@ HELP: vtruncate { $description "Truncates each element of " { $snippet "u" } "." } ; HELP: n+v -{ $values { "n" "a number" } { "u" "a sequence of numbers" } { "v" "a sequence of numbers" } } +{ $values { "n" "a number" } { "v" "a sequence of numbers" } { "w" "a sequence of numbers" } } { $description "Adds " { $snippet "n" } " to each element of " { $snippet "u" } "." } ; HELP: v+n -{ $values { "u" "a sequence of numbers" } { "n" "a number" } { "v" "a sequence of numbers" } } +{ $values { "u" "a sequence of numbers" } { "n" "a number" } { "w" "a sequence of numbers" } } { $description "Adds " { $snippet "n" } " to each element of " { $snippet "u" } "." } ; HELP: n-v -{ $values { "n" "a number" } { "u" "a sequence of numbers" } { "v" "a sequence of numbers" } } +{ $values { "n" "a number" } { "v" "a sequence of numbers" } { "w" "a sequence of numbers" } } { $description "Subtracts each element of " { $snippet "u" } " from " { $snippet "n" } "." } ; HELP: v-n -{ $values { "u" "a sequence of numbers" } { "n" "a number" } { "v" "a sequence of numbers" } } +{ $values { "u" "a sequence of numbers" } { "n" "a number" } { "w" "a sequence of numbers" } } { $description "Subtracts " { $snippet "n" } " from each element of " { $snippet "u" } "." } ; HELP: n*v -{ $values { "n" "a number" } { "u" "a sequence of numbers" } { "v" "a sequence of numbers" } } +{ $values { "n" "a number" } { "v" "a sequence of numbers" } { "w" "a sequence of numbers" } } { $description "Multiplies each element of " { $snippet "u" } " by " { $snippet "n" } "." } ; HELP: v*n -{ $values { "u" "a sequence of numbers" } { "n" "a number" } { "v" "a sequence of numbers" } } +{ $values { "u" "a sequence of numbers" } { "n" "a number" } { "w" "a sequence of numbers" } } { $description "Multiplies each element of " { $snippet "u" } " by " { $snippet "n" } "." } ; HELP: n/v -{ $values { "n" "a number" } { "u" "a sequence of numbers" } { "v" "a sequence of numbers" } } +{ $values { "n" "a number" } { "v" "a sequence of numbers" } { "w" "a sequence of numbers" } } { $description "Divides " { $snippet "n" } " by each element of " { $snippet "u" } "." } { $errors "May throw an error if a division by zero occurs; see " { $link "division-by-zero" } "." } ; HELP: v/n -{ $values { "u" "a sequence of numbers" } { "n" "a number" } { "v" "a sequence of numbers" } } +{ $values { "u" "a sequence of numbers" } { "n" "a number" } { "w" "a sequence of numbers" } } { $description "Divides each element of " { $snippet "u" } " by " { $snippet "n" } "." } { $errors "May throw an error if a division by zero occurs; see " { $link "division-by-zero" } "." } ; @@ -259,7 +254,7 @@ HELP: v- HELP: v+- { $values { "u" "a sequence of numbers" } { "v" "a sequence of numbers" } { "w" "a sequence of numbers" } } -{ $description "Adds and subtracts alternate elements of " { $snippet "v" } " and " { $snippet "u" } " component-wise." } +{ $description "Adds and subtracts alternate elements of " { $snippet "v" } " and " { $snippet "u" } " component-wise. Elements at even indexes are subtracted, while elements at odd indexes are added." } { $examples { $example "USING: math.vectors prettyprint ;" @@ -413,7 +408,6 @@ HELP: vbroadcast { $examples { $example "USING: alien.c-types math.vectors math.vectors.simd" "prettyprint ;" - "SIMD: int" "int-4{ 69 42 911 13 } 2 vbroadcast ." "int-4{ 911 911 911 911 }" } @@ -429,14 +423,12 @@ HELP: vshuffle { $examples { $example "USING: alien.c-types math.vectors math.vectors.simd" "prettyprint ;" - "SIMD: int" "int-4{ 69 42 911 13 } { 1 3 2 3 } vshuffle ." "int-4{ 42 13 911 13 }" } { $example "USING: alien.c-types combinators math.vectors math.vectors.simd" "namespaces prettyprint prettyprint.config ;" - "SIMDS: int uchar ;" "IN: scratchpad" "" ": endian-swap ( size -- vector )" diff --git a/basis/math/vectors/vectors.factor b/basis/math/vectors/vectors.factor index 63564f064d..6cb16e5efc 100644 --- a/basis/math/vectors/vectors.factor +++ b/basis/math/vectors/vectors.factor @@ -1,149 +1,191 @@ -! Copyright (C) 2005, 2009 Slava Pestov. +! Copyright (C) 2005, 2010 Slava Pestov, Joe Groff. ! See http://factorcode.org/license.txt for BSD license. -USING: arrays alien.c-types assocs kernel sequences math math.functions -hints math.order math.libm math.floats.private fry combinators -byte-arrays accessors locals ; +USING: arrays alien.c-types assocs kernel sequences math +math.functions grouping math.order math.libm math.floats.private +fry combinators byte-arrays accessors locals ; QUALIFIED-WITH: alien.c-types c IN: math.vectors -MIXIN: simd-128 -MIXIN: simd-256 +GENERIC: vneg ( u -- v ) +M: object vneg [ neg ] map ; inline -GENERIC: element-type ( obj -- c-type ) -M: object element-type drop f ; inline +GENERIC# v+n 1 ( u n -- w ) +M: object v+n [ + ] curry map ; inline -: vneg ( u -- v ) [ neg ] map ; +GENERIC: n+v ( n v -- w ) +M: object n+v [ + ] with map ; inline -: v+n ( u n -- v ) [ + ] curry map ; -: n+v ( n u -- v ) [ + ] with map ; -: v-n ( u n -- v ) [ - ] curry map ; -: n-v ( n u -- v ) [ - ] with map ; +GENERIC# v-n 1 ( u n -- w ) +M: object v-n [ - ] curry map ; inline -: v*n ( u n -- v ) [ * ] curry map ; -: n*v ( n u -- v ) [ * ] with map ; -: v/n ( u n -- v ) [ / ] curry map ; -: n/v ( n u -- v ) [ / ] with map ; +GENERIC: n-v ( n v -- w ) +M: object n-v [ - ] with map ; inline -: v+ ( u v -- w ) [ + ] 2map ; -: v- ( u v -- w ) [ - ] 2map ; -: [v-] ( u v -- w ) [ [-] ] 2map ; -: v* ( u v -- w ) [ * ] 2map ; -: v/ ( u v -- w ) [ / ] 2map ; +GENERIC# v*n 1 ( u n -- w ) +M: object v*n [ * ] curry map ; inline + +GENERIC: n*v ( n v -- w ) +M: object n*v [ * ] with map ; inline + +GENERIC# v/n 1 ( u n -- w ) +M: object v/n [ / ] curry map ; inline + +GENERIC: n/v ( n v -- w ) +M: object n/v [ / ] with map ; inline + +GENERIC: v+ ( u v -- w ) +M: object v+ [ + ] 2map ; inline + +GENERIC: v- ( u v -- w ) +M: object v- [ - ] 2map ; inline + +GENERIC: [v-] ( u v -- w ) +M: object [v-] [ [-] ] 2map ; inline + +GENERIC: v* ( u v -- w ) +M: object v* [ * ] 2map ; inline + +GENERIC: v*high ( u v -- w ) [ first2 + ] map ; +: (h-) ( u -- w ) 2 [ first2 - ] map ; PRIVATE> -: vmax ( u v -- w ) [ [ float-max ] [ max ] if-both-floats ] 2map ; -: vmin ( u v -- w ) [ [ float-min ] [ min ] if-both-floats ] 2map ; +GENERIC: v*hs+ ( u v -- w ) +M: object v*hs+ [ * ] 2map (h+) ; inline -: v+- ( u v -- w ) +GENERIC: v/ ( u v -- w ) +M: object v/ [ / ] 2map ; inline + +GENERIC: vavg ( u v -- w ) +M: object vavg [ + 2 / ] 2map ; inline + +GENERIC: vmax ( u v -- w ) +M: object vmax [ max ] 2map ; inline + +GENERIC: vmin ( u v -- w ) +M: object vmin [ min ] 2map ; inline + +GENERIC: v+- ( u v -- w ) +M: object v+- [ t ] 2dip [ [ not ] 2dip pick [ + ] [ - ] if ] 2map - nip ; + nip ; inline + +GENERIC: vs+ ( u v -- w ) +M: object vs+ [ + ] 2map ; inline + +GENERIC: vs- ( u v -- w ) +M: object vs- [ - ] 2map ; inline + +GENERIC: vs* ( u v -- w ) +M: object vs* [ * ] 2map ; inline + +GENERIC: vabs ( u -- v ) +M: object vabs [ abs ] map ; inline + +GENERIC: vsqrt ( u -- v ) +M: object vsqrt [ >float fsqrt ] map ; inline + +GENERIC: vsad ( u v -- n ) +M: object vsad [ - abs ] [ + ] 2map-reduce ; inline - -: vs+ ( u v -- w ) [ + ] 2saturate-map ; -: vs- ( u v -- w ) [ - ] 2saturate-map ; -: vs* ( u v -- w ) [ * ] 2saturate-map ; - -: vabs ( u -- v ) [ abs ] map ; -: vsqrt ( u -- v ) [ >float fsqrt ] map ; - -bits ] bi@ ] dip call bits>double ] } - { c:float [ [ [ float>bits ] bi@ ] dip call bits>float ] } - [ drop call ] - } case ; inline - -: fp-bitwise-unary ( x seq quot -- z ) - swap element-type { - { c:double [ [ double>bits ] dip call bits>double ] } - { c:float [ [ float>bits ] dip call bits>float ] } - [ drop call ] - } case ; inline - -: element>bool ( x seq -- ? ) - element-type [ [ f ] when-zero ] when ; inline - : bitandn ( x y -- z ) [ bitnot ] dip bitand ; inline -GENERIC: new-underlying ( underlying seq -- seq' ) - -: change-underlying ( seq quot -- seq' ) - '[ underlying>> @ ] keep new-underlying ; inline - PRIVATE> -: vbitand ( u v -- w ) over '[ _ [ bitand ] fp-bitwise-op ] 2map ; -: vbitandn ( u v -- w ) over '[ _ [ bitandn ] fp-bitwise-op ] 2map ; -: vbitor ( u v -- w ) over '[ _ [ bitor ] fp-bitwise-op ] 2map ; -: vbitxor ( u v -- w ) over '[ _ [ bitxor ] fp-bitwise-op ] 2map ; -: vbitnot ( u -- w ) dup '[ _ [ bitnot ] fp-bitwise-unary ] map ; +GENERIC: vbitand ( u v -- w ) +M: object vbitand [ bitand ] 2map ; inline +GENERIC: vbitandn ( u v -- w ) +M: object vbitandn [ bitandn ] 2map ; inline +GENERIC: vbitor ( u v -- w ) +M: object vbitor [ bitor ] 2map ; inline +GENERIC: vbitxor ( u v -- w ) +M: object vbitxor [ bitxor ] 2map ; inline +GENERIC: vbitnot ( u -- w ) +M: object vbitnot [ bitnot ] map ; inline -:: vbroadcast ( u n -- v ) u length n u nth u like ; +GENERIC# vbroadcast 1 ( u n -- v ) +M:: object vbroadcast ( u n -- v ) u length n u nth u like ; inline -: vshuffle-elements ( u perm -- v ) +GENERIC# vshuffle-elements 1 ( u perm -- v ) +M: object vshuffle-elements over length 0 pad-tail - swap [ '[ _ nth ] ] keep map-as ; + swap [ '[ _ nth ] ] keep map-as ; inline -: vshuffle-bytes ( u perm -- v ) - underlying>> [ - swap [ '[ 15 bitand _ nth ] ] keep map-as - ] curry change-underlying ; +GENERIC# vshuffle-bytes 1 ( u perm -- v ) GENERIC: vshuffle ( u perm -- v ) M: array vshuffle ( u perm -- v ) vshuffle-elements ; inline -M: simd-128 vshuffle ( u perm -- v ) - vshuffle-bytes ; inline -: vlshift ( u n -- w ) '[ _ shift ] map ; -: vrshift ( u n -- w ) neg '[ _ shift ] map ; +GENERIC# vlshift 1 ( u n -- w ) +M: object vlshift '[ _ shift ] map ; inline +GENERIC# vrshift 1 ( u n -- w ) +M: object vrshift neg '[ _ shift ] map ; inline -: hlshift ( u n -- w ) '[ _ prepend 16 head ] change-underlying ; -: hrshift ( u n -- w ) '[ _ append 16 tail* ] change-underlying ; +GENERIC# hlshift 1 ( u n -- w ) +GENERIC# hrshift 1 ( u n -- w ) -: (vmerge-head) ( u v -- h ) - over length 2 /i '[ _ head-slice ] bi@ [ zip ] keep concat-as ; -: (vmerge-tail) ( u v -- t ) - over length 2 /i '[ _ tail-slice ] bi@ [ zip ] keep concat-as ; +GENERIC: (vmerge-head) ( u v -- h ) +M: object (vmerge-head) over length 2 /i '[ _ head-slice ] bi@ [ zip ] keep concat-as ; inline +GENERIC: (vmerge-tail) ( u v -- t ) +M: object (vmerge-tail) over length 2 /i '[ _ tail-slice ] bi@ [ zip ] keep concat-as ; inline -: (vmerge) ( u v -- h t ) +GENERIC: (vmerge) ( u v -- h t ) +M: object (vmerge) [ (vmerge-head) ] [ (vmerge-tail) ] 2bi ; inline -: vmerge ( u v -- w ) [ zip ] keep concat-as ; +GENERIC: vmerge ( u v -- w ) +M: object vmerge [ zip ] keep concat-as ; inline -: vand ( u v -- w ) over '[ [ _ element>bool ] bi@ and ] 2map ; -: vandn ( u v -- w ) over '[ [ _ element>bool ] bi@ [ not ] dip and ] 2map ; -: vor ( u v -- w ) over '[ [ _ element>bool ] bi@ or ] 2map ; -: vxor ( u v -- w ) over '[ [ _ element>bool ] bi@ xor ] 2map ; -: vnot ( u -- w ) dup '[ _ element>bool not ] map ; +GENERIC: vand ( u v -- w ) +M: object vand [ and ] 2map ; inline -: vall? ( v -- ? ) dup '[ _ element>bool ] all? ; -: vany? ( v -- ? ) dup '[ _ element>bool ] any? ; -: vnone? ( v -- ? ) dup '[ _ element>bool not ] all? ; +GENERIC: vandn ( u v -- w ) +M: object vandn [ [ not ] dip and ] 2map ; inline -: v< ( u v -- w ) [ < ] 2map ; -: v<= ( u v -- w ) [ <= ] 2map ; -: v>= ( u v -- w ) [ >= ] 2map ; -: v> ( u v -- w ) [ > ] 2map ; -: vunordered? ( u v -- w ) [ unordered? ] 2map ; -: v= ( u v -- w ) [ = ] 2map ; +GENERIC: vor ( u v -- w ) +M: object vor [ or ] 2map ; inline -: v? ( mask true false -- result ) +GENERIC: vxor ( u v -- w ) +M: object vxor [ xor ] 2map ; inline + +GENERIC: vnot ( u -- w ) +M: object vnot [ not ] map ; inline + +GENERIC: vall? ( v -- ? ) +M: object vall? [ ] all? ; inline + +GENERIC: vany? ( v -- ? ) +M: object vany? [ ] any? ; inline + +GENERIC: vnone? ( v -- ? ) +M: object vnone? [ not ] all? ; inline + +GENERIC: v< ( u v -- w ) +M: object v< [ < ] 2map ; inline + +GENERIC: v<= ( u v -- w ) +M: object v<= [ <= ] 2map ; inline + +GENERIC: v>= ( u v -- w ) +M: object v>= [ >= ] 2map ; inline + +GENERIC: v> ( u v -- w ) +M: object v> [ > ] 2map ; inline + +GENERIC: vunordered? ( u v -- w ) +M: object vunordered? [ unordered? ] 2map ; inline + +GENERIC: v= ( u v -- w ) +M: object v= [ = ] 2map ; inline + +GENERIC: v? ( mask true false -- result ) +M: object v? [ vand ] [ vandn ] bi-curry* bi vor ; inline :: vif ( mask true-quot false-quot -- result ) @@ -157,15 +199,21 @@ M: simd-128 vshuffle ( u perm -- v ) : vceiling ( u -- v ) [ ceiling ] map ; : vtruncate ( u -- v ) [ truncate ] map ; -: vsupremum ( seq -- vmax ) [ ] [ vmax ] map-reduce ; -: vinfimum ( seq -- vmin ) [ ] [ vmin ] map-reduce ; +: vsupremum ( seq -- vmax ) [ ] [ vmax ] map-reduce ; inline +: vinfimum ( seq -- vmin ) [ ] [ vmin ] map-reduce ; inline -: v. ( u v -- x ) [ conjugate * ] [ + ] 2map-reduce ; -: norm-sq ( v -- x ) [ absq ] [ + ] map-reduce ; -: norm ( v -- x ) norm-sq sqrt ; -: normalize ( u -- v ) dup norm v/n ; +GENERIC: v. ( u v -- x ) +M: object v. [ conjugate * ] [ + ] 2map-reduce ; inline -: distance ( u v -- x ) [ - absq ] [ + ] 2map-reduce sqrt ; +GENERIC: norm-sq ( v -- x ) +M: object norm-sq [ absq ] [ + ] map-reduce ; inline + +: norm ( v -- x ) norm-sq sqrt ; inline + +: normalize ( u -- v ) dup norm v/n ; inline + +GENERIC: distance ( u v -- x ) +M: object distance [ - absq ] [ + ] 2map-reduce sqrt ; inline : set-axis ( u v axis -- w ) [ [ zero? 2over ? ] dip swap nth ] map-index 2nip ; @@ -197,28 +245,3 @@ PRIVATE> : v~ ( a b epsilon -- ? ) [ ~ ] curry 2all? ; inline - -HINTS: vneg { array } ; -HINTS: norm-sq { array } ; -HINTS: norm { array } ; -HINTS: normalize { array } ; -HINTS: distance { array array } ; - -HINTS: n*v { object array } ; -HINTS: v*n { array object } ; -HINTS: n/v { array } ; -HINTS: v/n { array object } ; - -HINTS: v+ { array array } ; -HINTS: v- { array array } ; -HINTS: v* { array array } ; -HINTS: v/ { array array } ; -HINTS: vmax { array array } ; -HINTS: vmin { array array } ; -HINTS: v. { array array } ; - -HINTS: vlerp { array array array } ; -HINTS: vnlerp { array array object } ; - -HINTS: bilerp { object object object object array } ; -HINTS: trilerp { object object object object object object object object array } ; diff --git a/basis/mime/multipart/multipart.factor b/basis/mime/multipart/multipart.factor old mode 100755 new mode 100644 diff --git a/basis/models/arrow/smart/smart.factor b/basis/models/arrow/smart/smart.factor index 257a2bb1ea..7c29310a97 100644 --- a/basis/models/arrow/smart/smart.factor +++ b/basis/models/arrow/smart/smart.factor @@ -1,9 +1,9 @@ -! Copyright (C) 2009 Slava Pestov. +! Copyright (C) 2009, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: models.arrow models.product stack-checker accessors fry -generalizations macros kernel ; +generalizations combinators.smart macros kernel ; IN: models.arrow.smart MACRO: ( quot -- quot' ) - [ infer in>> dup ] keep + [ inputs dup ] keep '[ _ narray [ _ firstn @ ] ] ; \ No newline at end of file diff --git a/basis/models/models.factor b/basis/models/models.factor index 1c03bb224c..f9927cfd4c 100644 --- a/basis/models/models.factor +++ b/basis/models/models.factor @@ -17,8 +17,6 @@ value connections dependencies ref locked? ; : ( value -- model ) model new-model ; -M: model hashcode* drop model hashcode* ; - : add-dependency ( dep model -- ) dependencies>> push ; diff --git a/basis/nibble-arrays/nibble-arrays-tests.factor b/basis/nibble-arrays/nibble-arrays-tests.factor index 2a0eef7227..363f30678d 100644 --- a/basis/nibble-arrays/nibble-arrays-tests.factor +++ b/basis/nibble-arrays/nibble-arrays-tests.factor @@ -1,6 +1,6 @@ USING: nibble-arrays tools.test sequences kernel math ; IN: nibble-arrays.tests -[ t ] [ 16 dup >nibble-array sequence= ] unit-test +[ t ] [ 16 iota dup >nibble-array sequence= ] unit-test [ N{ 4 2 1 3 } ] [ N{ 3 1 2 4 } reverse ] unit-test [ N{ 1 4 9 0 9 4 } ] [ N{ 1 2 3 4 5 6 } [ sq ] map ] unit-test diff --git a/basis/opengl/capabilities/capabilities.factor b/basis/opengl/capabilities/capabilities.factor old mode 100755 new mode 100644 diff --git a/basis/opengl/gl/extensions/extensions.factor b/basis/opengl/gl/extensions/extensions.factor index 6292a683e3..540fba40f0 100644 --- a/basis/opengl/gl/extensions/extensions.factor +++ b/basis/opengl/gl/extensions/extensions.factor @@ -19,7 +19,7 @@ SYMBOL: +gl-function-pointers+ : reset-gl-function-pointers ( -- ) 100 +gl-function-pointers+ set-global ; -[ reset-gl-function-pointers ] "opengl.gl" add-init-hook +[ reset-gl-function-pointers ] "opengl.gl" add-startup-hook reset-gl-function-pointers reset-gl-function-number-counter diff --git a/basis/opengl/gl/windows/windows.factor b/basis/opengl/gl/windows/windows.factor old mode 100755 new mode 100644 diff --git a/basis/opengl/opengl-tests.factor b/basis/opengl/opengl-tests.factor new file mode 100644 index 0000000000..818d0db8b7 --- /dev/null +++ b/basis/opengl/opengl-tests.factor @@ -0,0 +1,6 @@ +USING: tools.test math opengl opengl.gl ; +IN: opengl.tests + +{ 2 1 } [ { GL_TEXTURE_2D } [ + ] all-enabled ] must-infer-as + +{ 2 1 } [ { GL_TEXTURE_2D } [ + ] all-enabled-client-state ] must-infer-as diff --git a/basis/opengl/opengl.factor b/basis/opengl/opengl.factor old mode 100755 new mode 100644 index 513ed912e4..1f6205e64f --- a/basis/opengl/opengl.factor +++ b/basis/opengl/opengl.factor @@ -56,7 +56,9 @@ TUPLE: gl-error function code string ; [ ?execute ] map ; : (all-enabled) ( seq quot -- ) - over [ glEnable ] each dip [ glDisable ] each ; inline + [ dup [ glEnable ] each ] dip + dip + [ glDisable ] each ; inline : (all-enabled-client-state) ( seq quot -- ) [ dup [ glEnableClientState ] each ] dip diff --git a/basis/opengl/shaders/shaders.factor b/basis/opengl/shaders/shaders.factor old mode 100755 new mode 100644 diff --git a/basis/opengl/textures/textures.factor b/basis/opengl/textures/textures.factor old mode 100755 new mode 100644 diff --git a/basis/openssl/openssl.factor b/basis/openssl/openssl.factor index 8f14c60e14..76806f9523 100644 --- a/basis/openssl/openssl.factor +++ b/basis/openssl/openssl.factor @@ -34,4 +34,4 @@ SYMBOL: ssl-initialized? t ssl-initialized? set-global ] unless ; -[ f ssl-initialized? set-global ] "openssl" add-init-hook +[ f ssl-initialized? set-global ] "openssl" add-startup-hook diff --git a/basis/pack/pack-tests.factor b/basis/pack/pack-tests.factor old mode 100755 new mode 100644 diff --git a/basis/pack/pack.factor b/basis/pack/pack.factor old mode 100755 new mode 100644 diff --git a/basis/pango/cairo/cairo.factor b/basis/pango/cairo/cairo.factor index 6fd8d57893..d6baaffe2e 100644 --- a/basis/pango/cairo/cairo.factor +++ b/basis/pango/cairo/cairo.factor @@ -240,4 +240,4 @@ SYMBOL: cached-layouts : cached-line ( font string -- line ) cached-layout layout>> first-line ; -[ cached-layouts set-global ] "pango.cairo" add-init-hook +[ cached-layouts set-global ] "pango.cairo" add-startup-hook diff --git a/basis/pango/fonts/fonts.factor b/basis/pango/fonts/fonts.factor index 280ddd20d6..31a51e3f12 100644 --- a/basis/pango/fonts/fonts.factor +++ b/basis/pango/fonts/fonts.factor @@ -111,4 +111,4 @@ MEMO: (cache-font-description) ( font -- description ) : cache-font-description ( font -- description ) strip-font-colors (cache-font-description) ; -[ \ (cache-font-description) reset-memoized ] "pango.fonts" add-init-hook +[ \ (cache-font-description) reset-memoized ] "pango.fonts" add-startup-hook diff --git a/basis/peg/ebnf/ebnf-docs.factor b/basis/peg/ebnf/ebnf-docs.factor index 9bfd8ce499..6895a2bd7b 100644 --- a/basis/peg/ebnf/ebnf-docs.factor +++ b/basis/peg/ebnf/ebnf-docs.factor @@ -435,9 +435,11 @@ ARTICLE: "peg.ebnf" "EBNF" "The " { $vocab-link "peg.ebnf" } " vocabulary provides a DSL that allows writing PEG parsers that look like " "EBNF syntax. It provides three parsing words described below. These words all " "accept the same EBNF syntax. The difference is in how they are used. " -{ $subsection POSTPONE: [let :> ; FROM: sequences => nth ; [let " % - dup length [ + [ over ebnf-var? [ " " % # " over nth :> " % name>> % ] [ 2drop ] if - ] 2each + ] each-index " " % % " nip ]" % diff --git a/basis/persistent/hashtables/hashtables-tests.factor b/basis/persistent/hashtables/hashtables-tests.factor index eea31dd34e..482367ad9c 100644 --- a/basis/persistent/hashtables/hashtables-tests.factor +++ b/basis/persistent/hashtables/hashtables-tests.factor @@ -1,6 +1,6 @@ IN: persistent.hashtables.tests USING: persistent.hashtables persistent.assocs hashtables assocs -tools.test kernel namespaces random math.ranges sequences fry ; +tools.test kernel locals namespaces random math.ranges sequences fry ; [ t ] [ PH{ } assoc-empty? ] unit-test @@ -81,12 +81,13 @@ M: hash-0-b hashcode* 2drop 0 ; ] unit-test : random-string ( -- str ) - 1000000 random ; ! [ CHAR: a CHAR: z [a,b] random ] "" replicate-as ; + 1000000 random ; + ! [ CHAR: a CHAR: z [a,b] random ] "" replicate-as ; : random-assocs ( n -- hash phash ) [ random-string ] replicate [ H{ } clone [ '[ swap _ set-at ] each-index ] keep ] - [ PH{ } clone swap [ spin new-at ] each-index ] + [ PH{ } clone swap [| ph elt i | i elt ph new-at ] each-index ] bi ; : ok? ( assoc1 assoc2 -- ? ) diff --git a/basis/persistent/hashtables/hashtables.factor b/basis/persistent/hashtables/hashtables.factor index 0179216e62..256baabd5e 100644 --- a/basis/persistent/hashtables/hashtables.factor +++ b/basis/persistent/hashtables/hashtables.factor @@ -1,7 +1,7 @@ ! Based on Clojure's PersistentHashMap by Rich Hickey. USING: kernel math accessors assocs fry combinators parser -prettyprint.custom make +prettyprint.custom locals make persistent.assocs persistent.hashtables.nodes persistent.hashtables.nodes.empty @@ -38,8 +38,8 @@ M: persistent-hash pluck-at M: persistent-hash >alist [ root>> >alist% ] { } make ; -: >persistent-hash ( assoc -- phash ) - T{ persistent-hash } swap [ spin new-at ] assoc-each ; +:: >persistent-hash ( assoc -- phash ) + T{ persistent-hash } assoc [| ph k v | v k ph new-at ] assoc-each ; M: persistent-hash equal? over persistent-hash? [ assoc= ] [ 2drop f ] if ; diff --git a/basis/persistent/vectors/vectors-tests.factor b/basis/persistent/vectors/vectors-tests.factor index 95fa70558d..6d340ca78a 100644 --- a/basis/persistent/vectors/vectors-tests.factor +++ b/basis/persistent/vectors/vectors-tests.factor @@ -18,14 +18,14 @@ vectors math math.order ; ] unit-test { 100 1060 2000 10000 100000 1000000 } [ - [ t ] swap [ dup >persistent-vector sequence= ] curry unit-test + [ t ] swap [ iota dup >persistent-vector sequence= ] curry unit-test ] each [ ] [ 10000 [ 16 random-bits ] PV{ } replicate-as "1" set ] unit-test [ ] [ "1" get >vector "2" set ] unit-test [ t ] [ - 3000 [ + 3000 iota [ drop 16 random-bits 10000 random [ "1" [ new-nth ] change ] @@ -56,11 +56,11 @@ vectors math math.order ; ] unit-test [ t ] [ - 10000 >persistent-vector 752 [ ppop ] times dup length sequence= + 10000 iota >persistent-vector 752 [ ppop ] times dup length iota sequence= ] unit-test [ t ] [ - 100 [ + 100 iota [ drop 100 random [ 16 random-bits [ "1" [ ppush ] change ] [ "2" get push ] bi diff --git a/basis/persistent/vectors/vectors.factor b/basis/persistent/vectors/vectors.factor index 2527959f32..b02604e9bd 100644 --- a/basis/persistent/vectors/vectors.factor +++ b/basis/persistent/vectors/vectors.factor @@ -58,7 +58,7 @@ M: persistent-vector nth-unsafe [ 2array ] [ drop level>> 1 + ] 2bi node boa ; : new-child ( new-child node -- node' expansion/f ) - dup full? [ tuck level>> 1node ] [ node-add f ] if ; + dup full? [ [ level>> 1node ] keep swap ] [ node-add f ] if ; : new-last ( val seq -- seq' ) [ length 1 - ] keep new-nth ; @@ -70,7 +70,7 @@ M: persistent-vector nth-unsafe dup level>> 1 = [ new-child ] [ - tuck children>> last (ppush-new-tail) + [ nip ] 2keep children>> last (ppush-new-tail) [ swap new-child ] [ swap node-set-last f ] ?if ] if ; diff --git a/basis/porter-stemmer/porter-stemmer.factor b/basis/porter-stemmer/porter-stemmer.factor index 2e1a47b951..e3cb186bf8 100644 --- a/basis/porter-stemmer/porter-stemmer.factor +++ b/basis/porter-stemmer/porter-stemmer.factor @@ -33,10 +33,10 @@ IN: porter-stemmer ] if ; : consonant-seq ( str -- n ) - 0 0 rot skip-consonants (consonant-seq) ; + [ 0 0 ] dip skip-consonants (consonant-seq) ; : stem-vowel? ( str -- ? ) - [ length ] keep [ consonant? ] curry all? not ; + [ length iota ] keep [ consonant? ] curry all? not ; : double-consonant? ( i str -- ? ) over 1 < [ diff --git a/basis/prettyprint/backend/backend.factor b/basis/prettyprint/backend/backend.factor index 0ba1d38ae6..04617a6c67 100644 --- a/basis/prettyprint/backend/backend.factor +++ b/basis/prettyprint/backend/backend.factor @@ -116,8 +116,7 @@ M: pathname pprint* : check-recursion ( obj quot -- ) nesting-limit? [ drop - "~" over class name>> "~" 3append - swap present-text + [ class name>> "~" dup surround ] keep present-text ] [ over recursion-check get member-eq? [ drop "~circularity~" swap present-text @@ -175,7 +174,7 @@ M: tuple pprint* : pprint-elements ( seq -- ) do-length-limit [ [ pprint* ] each ] dip - [ "~" swap number>string " more~" 3append text ] when* ; + [ number>string "~" " more~" surround text ] when* ; M: quotation pprint-delims drop \ [ \ ] ; M: curry pprint-delims drop \ [ \ ] ; diff --git a/basis/prettyprint/prettyprint.factor b/basis/prettyprint/prettyprint.factor index 6cff399201..65d25f1812 100644 --- a/basis/prettyprint/prettyprint.factor +++ b/basis/prettyprint/prettyprint.factor @@ -73,8 +73,8 @@ SYMBOL: -> : remove-breakpoints ( quot pos -- quot' ) over quotation? [ - 1 + cut [ (remove-breakpoints) ] bi@ - [ -> ] glue + 1 + short cut [ (remove-breakpoints) ] bi@ + [ -> ] glue ] [ drop ] if ; diff --git a/basis/prettyprint/sections/sections.factor b/basis/prettyprint/sections/sections.factor index 040b6d8f7c..6f5f61f688 100644 --- a/basis/prettyprint/sections/sections.factor +++ b/basis/prettyprint/sections/sections.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2003, 2009 Slava Pestov. +! Copyright (C) 2003, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: arrays generic hashtables io kernel math assocs namespaces make sequences strings io.styles vectors words @@ -309,7 +309,7 @@ SYMBOL: next : group-flow ( seq -- newseq ) [ - dup length [ + dup length iota [ 2dup 1 - swap ?nth prev set 2dup 1 + swap ?nth next set swap nth dup split-before dup , split-after diff --git a/basis/promises/promises-docs.factor b/basis/promises/promises-docs.factor old mode 100755 new mode 100644 diff --git a/basis/promises/promises.factor b/basis/promises/promises.factor old mode 100755 new mode 100644 diff --git a/basis/quoted-printable/quoted-printable-tests.factor b/basis/quoted-printable/quoted-printable-tests.factor index e258cb9a96..2a3239c72f 100644 --- a/basis/quoted-printable/quoted-printable-tests.factor +++ b/basis/quoted-printable/quoted-printable-tests.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2009 Daniel Ehrenberg ! See http://factorcode.org/license.txt for BSD license. USING: tools.test quoted-printable io.encodings.string -sequences io.encodings.8-bit splitting kernel ; +sequences splitting kernel io.encodings.8-bit.latin2 ; IN: quoted-printable.tests [ """José was the diff --git a/basis/random/mersenne-twister/mersenne-twister-tests.factor b/basis/random/mersenne-twister/mersenne-twister-tests.factor index b877af6f79..ede3c92f51 100644 --- a/basis/random/mersenne-twister/mersenne-twister-tests.factor +++ b/basis/random/mersenne-twister/mersenne-twister-tests.factor @@ -5,7 +5,7 @@ IN: random.mersenne-twister.tests : check-random ( max -- ? ) [ random 0 ] keep between? ; -[ t ] [ 100 [ drop 674 check-random ] all? ] unit-test +[ t ] [ 100 [ drop 674 check-random ] all-integers? ] unit-test : randoms ( -- seq ) 100 [ 100 random ] replicate ; @@ -16,11 +16,11 @@ IN: random.mersenne-twister.tests [ f ] [ 1234 [ randoms randoms = ] test-rng ] unit-test [ 1333075495 ] [ - 0 [ 1000 [ drop random-generator get random-32* drop ] each random-generator get random-32* ] test-rng + 0 [ 1000 [ drop random-generator get random-32* drop ] each-integer random-generator get random-32* ] test-rng ] unit-test [ 1575309035 ] [ - 0 [ 10000 [ drop random-generator get random-32* drop ] each random-generator get random-32* ] test-rng + 0 [ 10000 [ drop random-generator get random-32* drop ] each-integer random-generator get random-32* ] test-rng ] unit-test diff --git a/basis/random/mersenne-twister/mersenne-twister.factor b/basis/random/mersenne-twister/mersenne-twister.factor index a0e40e5c38..9fd82a3062 100644 --- a/basis/random/mersenne-twister/mersenne-twister.factor +++ b/basis/random/mersenne-twister/mersenne-twister.factor @@ -30,8 +30,8 @@ CONSTANT: a uint-array{ 0 HEX: 9908b0df } : mt-generate ( mt -- ) [ seq>> - [ [ n m - ] dip '[ [ m ] dip _ mt[k] ] each ] - [ [ m 1 - ] dip '[ [ m n - ] [ n m - + ] bi* _ mt[k] ] each ] + [ [ n m - ] dip '[ [ m ] dip _ mt[k] ] each-integer ] + [ [ m 1 - ] dip '[ [ m n - ] [ n m - + ] bi* _ mt[k] ] each-integer ] bi ] [ 0 >>i drop ] bi ; inline @@ -41,7 +41,7 @@ CONSTANT: a uint-array{ 0 HEX: 9908b0df } : init-mt-rest ( seq -- ) n 1 - swap '[ _ [ init-mt-formula ] [ [ 1 + ] dip set-nth ] 2bi - ] each ; inline + ] each-integer ; inline : init-mt-seq ( seed -- seq ) 32 bits n @@ -79,5 +79,5 @@ M: mersenne-twister random-32* ( mt -- r ) [ default-mersenne-twister random-generator set-global -] "bootstrap.random" add-init-hook +] "bootstrap.random" add-startup-hook diff --git a/basis/random/random-docs.factor b/basis/random/random-docs.factor old mode 100755 new mode 100644 index 788a6e700a..2bf92f64a3 --- a/basis/random/random-docs.factor +++ b/basis/random/random-docs.factor @@ -19,9 +19,8 @@ HELP: random-bytes* { $description "Generates a byte-array of random bytes." } ; HELP: random -{ $values { "seq" sequence } { "elt" "a random element" } } -{ $description "Outputs a random element of the input sequence. Outputs " { $link f } " if the sequence is empty." } -{ $notes "Since integers are sequences, passing an integer " { $snippet "n" } " outputs an integer in the interval " { $snippet "[0,n)" } "." } +{ $values { "obj" object } { "elt" "a random element" } } +{ $description "Outputs a random element of the input object, or outputs " { $link f } " if the object contains no elements." } { $examples { $unchecked-example "USING: random prettyprint ;" "10 random ." diff --git a/basis/random/random-tests.factor b/basis/random/random-tests.factor index 96dc8cc783..9341b96b11 100644 --- a/basis/random/random-tests.factor +++ b/basis/random/random-tests.factor @@ -11,8 +11,8 @@ IN: random.tests [ 2 ] [ V{ 10 20 30 } [ delete-random drop ] keep length ] unit-test [ V{ } [ delete-random drop ] keep length ] must-fail -[ t ] [ 10000 [ 0 [ drop 187 random + ] reduce ] keep / 2 * 187 10 ~ ] unit-test -[ t ] [ 10000 [ 0 [ drop 400 random + ] reduce ] keep / 2 * 400 10 ~ ] unit-test +[ t ] [ 10000 [ iota 0 [ drop 187 random + ] reduce ] keep / 2 * 187 10 ~ ] unit-test +[ t ] [ 10000 [ iota 0 [ drop 400 random + ] reduce ] keep / 2 * 400 10 ~ ] unit-test [ t ] [ 1000 [ 400 random ] replicate prune length 256 > ] unit-test @@ -29,7 +29,7 @@ IN: random.tests [ { 1 2 } 3 sample ] [ too-many-samples? ] must-fail-with [ 3 ] [ { 1 2 3 4 } 3 sample prune length ] unit-test -[ 99 ] [ 100 99 sample prune length ] unit-test +[ 99 ] [ 100 iota 99 sample prune length ] unit-test [ ] [ [ 100 random-bytes ] with-system-random drop ] unit-test diff --git a/basis/random/random.factor b/basis/random/random.factor old mode 100755 new mode 100644 index bfd107dbb6..1e54c56728 --- a/basis/random/random.factor +++ b/basis/random/random.factor @@ -50,7 +50,11 @@ PRIVATE> : random-bits* ( numbits -- n ) 1 - [ random-bits ] keep set-bit ; -: random ( seq -- elt ) +GENERIC: random ( obj -- elt ) + +M: integer random [ f ] [ random-integer ] if-zero ; + +M: sequence random [ f ] [ [ length random-integer ] keep nth ] if-empty ; @@ -59,7 +63,7 @@ PRIVATE> : randomize ( seq -- seq ) dup length [ dup 1 > ] - [ [ iota random ] [ 1 - ] bi [ pick exchange ] keep ] + [ [ random ] [ 1 - ] bi [ pick exchange ] keep ] while drop ; ERROR: too-many-samples seq n ; diff --git a/basis/random/sfmt/sfmt.factor b/basis/random/sfmt/sfmt.factor index 55606217c9..146db91172 100644 --- a/basis/random/sfmt/sfmt.factor +++ b/basis/random/sfmt/sfmt.factor @@ -4,7 +4,6 @@ USING: accessors alien.c-types kernel locals math math.ranges math.bitwise math.vectors math.vectors.simd random sequences specialized-arrays sequences.private classes.struct combinators.short-circuit fry ; -SIMDS: uchar uint ; SPECIALIZED-ARRAY: uint SPECIALIZED-ARRAY: uint-4 IN: random.sfmt diff --git a/basis/random/unix/unix.factor b/basis/random/unix/unix.factor index 599cd5e0ad..fd93d6492c 100644 --- a/basis/random/unix/unix.factor +++ b/basis/random/unix/unix.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 Doug Coleman ! See http://factorcode.org/license.txt for BSD license. USING: alien.c-types io io.files kernel namespaces random -io.encodings.binary init accessors system ; +io.encodings.binary init accessors system destructors ; IN: random.unix TUPLE: unix-random reader ; @@ -9,17 +9,19 @@ TUPLE: unix-random reader ; : ( path -- random ) binary unix-random boa ; +M: unix-random dispose reader>> dispose ; + M: unix-random random-bytes* ( n tuple -- byte-array ) reader>> stream-read ; os openbsd? [ [ - "/dev/srandom" secure-random-generator set-global - "/dev/arandom" system-random-generator set-global - ] "random.unix" add-init-hook + "/dev/srandom" &dispose secure-random-generator set-global + "/dev/arandom" &dispose system-random-generator set-global + ] "random.unix" add-startup-hook ] [ [ - "/dev/random" secure-random-generator set-global - "/dev/urandom" system-random-generator set-global - ] "random.unix" add-init-hook + "/dev/random" &dispose secure-random-generator set-global + "/dev/urandom" &dispose system-random-generator set-global + ] "random.unix" add-startup-hook ] if diff --git a/basis/random/windows/windows.factor b/basis/random/windows/windows.factor index d959b191c9..c1d3010c0f 100644 --- a/basis/random/windows/windows.factor +++ b/basis/random/windows/windows.factor @@ -1,7 +1,7 @@ USING: accessors alien.c-types alien.data byte-arrays combinators.short-circuit continuations destructors init kernel locals namespaces random windows.advapi32 windows.errors -windows.kernel32 math.bitwise ; +windows.kernel32 windows.types math.bitwise ; IN: random.windows TUPLE: windows-rng provider type ; @@ -16,7 +16,7 @@ M: windows-crypto-context dispose ( tuple -- ) CONSTANT: factor-crypto-container "FactorCryptoContainer" :: (acquire-crypto-context) ( provider type flags -- handle ret ) - "HCRYPTPROV" :> handle + HCRYPTPROV :> handle handle factor-crypto-container provider @@ -65,5 +65,11 @@ M: windows-rng random-bytes* ( n tuple -- bytes ) [ MS_STRONG_PROV PROV_RSA_FULL ] [ drop MS_ENH_RSA_AES_PROV PROV_RSA_AES ] recover secure-random-generator set-global +] "random.windows" add-startup-hook -] "random.windows" add-init-hook +[ + [ + ! system-random-generator get-global &dispose drop + ! secure-random-generator get-global &dispose drop + ] with-destructors +] "random.windows" add-shutdown-hook diff --git a/basis/refs/refs-docs.factor b/basis/refs/refs-docs.factor old mode 100755 new mode 100644 diff --git a/basis/regexp/dfa/dfa.factor b/basis/regexp/dfa/dfa.factor index 2de4e8b0e0..fa75232fd5 100644 --- a/basis/regexp/dfa/dfa.factor +++ b/basis/regexp/dfa/dfa.factor @@ -25,7 +25,7 @@ IN: regexp.dfa ] unless ; : epsilon-table ( states nfa -- table ) - [ H{ } clone tuck ] dip + [ [ H{ } clone ] dip over ] dip '[ _ _ t epsilon-loop ] each ; : find-epsilon-closure ( states nfa -- dfa-state ) diff --git a/basis/regexp/disambiguate/disambiguate.factor b/basis/regexp/disambiguate/disambiguate.factor index 876d898cb4..33b2ded448 100644 --- a/basis/regexp/disambiguate/disambiguate.factor +++ b/basis/regexp/disambiguate/disambiguate.factor @@ -11,9 +11,7 @@ TUPLE: parts in out ; zip [ first ] partition [ values ] bi@ parts boa ; : powerset-partition ( sequence -- partitions ) - [ length [ 2^ ] keep ] keep '[ - _ _ make-partition - ] map rest ; + [ length [ 2^ iota ] keep ] keep '[ _ _ make-partition ] map rest ; : partition>class ( parts -- class ) [ out>> [ ] map ] @@ -44,12 +42,12 @@ TUPLE: parts in out ; [ _ meaningful-integers ] keep add-out ] map ; -: class-partitions ( classes -- assoc ) - [ integer? ] partition [ - dup powerset-partition spin add-integers - [ [ partition>class ] keep 2array ] map - [ first ] filter - ] [ '[ _ singleton-partition ] map ] 2bi append ; +:: class-partitions ( classes -- assoc ) + classes [ integer? ] partition :> ( integers classes ) + + classes powerset-partition classes integers add-integers + [ [ partition>class ] keep 2array ] map [ first ] filter + integers [ classes singleton-partition ] map append ; : new-transitions ( transitions -- assoc ) ! assoc is class, partition values [ keys ] gather diff --git a/basis/regexp/minimize/minimize.factor b/basis/regexp/minimize/minimize.factor index 1885144e6c..a6eb4f00a2 100644 --- a/basis/regexp/minimize/minimize.factor +++ b/basis/regexp/minimize/minimize.factor @@ -85,7 +85,7 @@ IN: regexp.minimize '[ _ delete-duplicates ] change-transitions ; : combine-state-transitions ( hash -- hash ) - H{ } clone tuck '[ + [ H{ } clone ] dip over '[ _ [ 2array ] change-at ] assoc-each [ swap ] assoc-map ; diff --git a/basis/roman/roman-docs.factor b/basis/roman/roman-docs.factor index 50a057d7f4..c81ed0ae42 100644 --- a/basis/roman/roman-docs.factor +++ b/basis/roman/roman-docs.factor @@ -4,7 +4,7 @@ USING: help.markup help.syntax kernel math strings ; IN: roman HELP: >roman -{ $values { "n" "an integer" } { "str" "a string" } } +{ $values { "n" integer } { "str" string } } { $description "Converts a number to its lower-case Roman Numeral equivalent." } { $notes "The range for this word is 1-3999, inclusive." } { $examples @@ -15,7 +15,7 @@ HELP: >roman } ; HELP: >ROMAN -{ $values { "n" "an integer" } { "str" "a string" } } +{ $values { "n" integer } { "str" string } } { $description "Converts a number to its upper-case Roman numeral equivalent." } { $notes "The range for this word is 1-3999, inclusive." } { $examples @@ -26,7 +26,7 @@ HELP: >ROMAN } ; HELP: roman> -{ $values { "str" "a string" } { "n" "an integer" } } +{ $values { "str" string } { "n" integer } } { $description "Converts a Roman numeral to an integer." } { $notes "The range for this word is i-mmmcmxcix, inclusive." } { $examples @@ -39,7 +39,7 @@ HELP: roman> { >roman >ROMAN roman> } related-words HELP: roman+ -{ $values { "string" string } { "string" string } { "string" string } } +{ $values { "x" string } { "x" string } { "x" string } } { $description "Adds two Roman numerals." } { $examples { $example "USING: io roman ;" @@ -49,7 +49,7 @@ HELP: roman+ } ; HELP: roman- -{ $values { "string" string } { "string" string } { "string" string } } +{ $values { "x" string } { "x" string } { "x" string } } { $description "Subtracts two Roman numerals." } { $examples { $example "USING: io roman ;" @@ -61,7 +61,7 @@ HELP: roman- { roman+ roman- } related-words HELP: roman* -{ $values { "string" string } { "string" string } { "string" string } } +{ $values { "x" string } { "x" string } { "x" string } } { $description "Multiplies two Roman numerals." } { $examples { $example "USING: io roman ;" @@ -71,7 +71,7 @@ HELP: roman* } ; HELP: roman/i -{ $values { "string" string } { "string" string } { "string" string } } +{ $values { "x" string } { "x" string } { "x" string } } { $description "Computes the integer division of two Roman numerals." } { $examples { $example "USING: io roman ;" @@ -81,7 +81,7 @@ HELP: roman/i } ; HELP: roman/mod -{ $values { "string" string } { "string" string } { "string" string } { "string" string } } +{ $values { "x" string } { "x" string } { "x" string } { "x" string } } { $description "Computes the quotient and remainder of two Roman numerals." } { $examples { $example "USING: kernel io roman ;" diff --git a/basis/roman/roman-tests.factor b/basis/roman/roman-tests.factor index a510514e23..c7ab7fafd9 100644 --- a/basis/roman/roman-tests.factor +++ b/basis/roman/roman-tests.factor @@ -29,7 +29,7 @@ USING: arrays kernel math roman roman.private sequences tools.test ; [ 3444 ] [ 3444 >roman roman> ] unit-test [ 3999 ] [ 3999 >roman roman> ] unit-test [ 0 >roman ] must-fail -[ 4000 >roman ] must-fail +[ 40000 >roman ] must-fail [ "vi" ] [ "iii" "iii" roman+ ] unit-test [ "viii" ] [ "x" "ii" roman- ] unit-test [ "ix" ] [ "iii" "iii" roman* ] unit-test diff --git a/basis/roman/roman.factor b/basis/roman/roman.factor index f8c7da9ab4..a783e7973c 100644 --- a/basis/roman/roman.factor +++ b/basis/roman/roman.factor @@ -17,7 +17,7 @@ CONSTANT: roman-values ERROR: roman-range-error n ; : roman-range-check ( n -- n ) - dup 1 3999 between? [ roman-range-error ] unless ; + dup 1 10000 between? [ roman-range-error ] unless ; : roman-digit-index ( ch -- n ) 1string roman-digits index ; inline @@ -48,7 +48,7 @@ PRIVATE> > ] [ ] [ infer out>> ] tri + [ inputs ] [ ] [ outputs ] tri '[ [ roman> ] _ napply @ [ >roman ] _ napply ] ; PRIVATE> @@ -58,8 +58,7 @@ PRIVATE> SYNTAX: ROMAN-OP: scan-word [ name>> "roman" prepend create-in ] keep 1quotation '[ _ binary-roman-op ] - dup infer [ in>> ] [ out>> ] bi - [ "string" ] bi@ define-declared ; + dup infer define-declared ; >> diff --git a/basis/io/servers/packet/authors.txt b/basis/sequences/cords/authors.txt old mode 100755 new mode 100644 similarity index 100% rename from basis/io/servers/packet/authors.txt rename to basis/sequences/cords/authors.txt diff --git a/basis/sequences/cords/cords-tests.factor b/basis/sequences/cords/cords-tests.factor new file mode 100644 index 0000000000..fb9c440733 --- /dev/null +++ b/basis/sequences/cords/cords-tests.factor @@ -0,0 +1,4 @@ +USING: sequences.cords strings tools.test kernel sequences ; +IN: sequences.cords.tests + +[ "hello world" ] [ "hello" " world" cord-append dup like ] unit-test diff --git a/basis/sequences/cords/cords.factor b/basis/sequences/cords/cords.factor new file mode 100644 index 0000000000..fca005fa6e --- /dev/null +++ b/basis/sequences/cords/cords.factor @@ -0,0 +1,112 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors assocs sequences sorting binary-search fry math +math.order arrays classes combinators kernel functors math.functions +math.vectors ; +IN: sequences.cords + +MIXIN: cord + +TUPLE: generic-cord + { head read-only } { tail read-only } ; +INSTANCE: generic-cord cord + +M: cord length + [ head>> length ] [ tail>> length ] bi + ; inline + +M: cord virtual-exemplar head>> ; inline + +M: cord virtual@ + 2dup head>> length < + [ head>> ] [ [ head>> length - ] [ tail>> ] bi ] if ; inline + +INSTANCE: cord virtual-sequence + +GENERIC: cord-append ( seq1 seq2 -- cord ) + +M: object cord-append + generic-cord boa ; inline + +FUNCTOR: define-specialized-cord ( T C -- ) + +T-cord DEFINES-CLASS ${C} + +WHERE + +TUPLE: T-cord + { head T read-only } { tail T read-only } ; +INSTANCE: T-cord cord + +M: T cord-append + 2dup [ T instance? ] both? + [ T-cord boa ] [ generic-cord boa ] if ; inline + +;FUNCTOR + +: cord-map ( cord quot -- cord' ) + [ [ head>> ] dip call ] + [ [ tail>> ] dip call ] 2bi cord-append ; inline + +: cord-2map ( cord cord quot -- cord' ) + [ [ [ head>> ] bi@ ] dip call ] + [ [ [ tail>> ] bi@ ] dip call ] 3bi cord-append ; inline + +: cord-both ( cord quot -- h t ) + [ [ head>> ] [ tail>> ] bi ] dip bi@ ; inline + +: cord-2both ( cord cord quot -- h t ) + [ [ [ head>> ] bi@ ] dip call ] + [ [ [ tail>> ] bi@ ] dip call ] 3bi ; inline + +M: cord v+ [ v+ ] cord-2map ; inline +M: cord v- [ v- ] cord-2map ; inline +M: cord vneg [ vneg ] cord-map ; inline +M: cord v+- [ v+- ] cord-2map ; inline +M: cord vs+ [ vs+ ] cord-2map ; inline +M: cord vs- [ vs- ] cord-2map ; inline +M: cord vs* [ vs* ] cord-2map ; inline +M: cord v* [ v* ] cord-2map ; inline +M: cord v/ [ v/ ] cord-2map ; inline +M: cord vmin [ vmin ] cord-2map ; inline +M: cord vmax [ vmax ] cord-2map ; inline +M: cord v. [ v. ] cord-2both + ; inline +M: cord vsqrt [ vsqrt ] cord-map ; inline +M: cord sum [ sum ] cord-both + ; inline +M: cord vabs [ vabs ] cord-map ; inline +M: cord vbitand [ vbitand ] cord-2map ; inline +M: cord vbitandn [ vbitandn ] cord-2map ; inline +M: cord vbitor [ vbitor ] cord-2map ; inline +M: cord vbitxor [ vbitxor ] cord-2map ; inline +M: cord vbitnot [ vbitnot ] cord-map ; inline +M: cord vand [ vand ] cord-2map ; inline +M: cord vandn [ vandn ] cord-2map ; inline +M: cord vor [ vor ] cord-2map ; inline +M: cord vxor [ vxor ] cord-2map ; inline +M: cord vnot [ vnot ] cord-map ; inline +M: cord vlshift '[ _ vlshift ] cord-map ; inline +M: cord vrshift '[ _ vrshift ] cord-map ; inline +M: cord (vmerge-head) [ head>> ] bi@ (vmerge) cord-append ; inline +M: cord (vmerge-tail) [ tail>> ] bi@ (vmerge) cord-append ; inline +M: cord v<= [ v<= ] cord-2map ; inline +M: cord v< [ v< ] cord-2map ; inline +M: cord v= [ v= ] cord-2map ; inline +M: cord v> [ v> ] cord-2map ; inline +M: cord v>= [ v>= ] cord-2map ; inline +M: cord vunordered? [ vunordered? ] cord-2map ; inline +M: cord vany? [ vany? ] cord-both or ; inline +M: cord vall? [ vall? ] cord-both and ; inline +M: cord vnone? [ vnone? ] cord-both and ; inline + +M: cord n+v [ n+v ] with cord-map ; inline +M: cord n-v [ n-v ] with cord-map ; inline +M: cord n*v [ n*v ] with cord-map ; inline +M: cord n/v [ n/v ] with cord-map ; inline +M: cord v+n '[ _ v+n ] cord-map ; inline +M: cord v-n '[ _ v-n ] cord-map ; inline +M: cord v*n '[ _ v*n ] cord-map ; inline +M: cord v/n '[ _ v/n ] cord-map ; inline + +M: cord norm-sq [ norm-sq ] cord-both + ; inline +M: cord distance v- norm ; inline + + diff --git a/basis/cords/summary.txt b/basis/sequences/cords/summary.txt similarity index 100% rename from basis/cords/summary.txt rename to basis/sequences/cords/summary.txt diff --git a/basis/cords/tags.txt b/basis/sequences/cords/tags.txt similarity index 100% rename from basis/cords/tags.txt rename to basis/sequences/cords/tags.txt diff --git a/basis/sequences/deep/deep-docs.factor b/basis/sequences/deep/deep-docs.factor old mode 100755 new mode 100644 diff --git a/basis/sequences/deep/deep-tests.factor b/basis/sequences/deep/deep-tests.factor old mode 100755 new mode 100644 diff --git a/basis/sequences/deep/deep.factor b/basis/sequences/deep/deep.factor old mode 100755 new mode 100644 diff --git a/basis/sequences/merged/merged-docs.factor b/basis/sequences/merged/merged-docs.factor index da0d340126..9b98cd1ed8 100644 --- a/basis/sequences/merged/merged-docs.factor +++ b/basis/sequences/merged/merged-docs.factor @@ -20,7 +20,7 @@ HELP: merged HELP: ( seqs -- merged ) { $values { "seqs" "a sequence of sequences to merge" } { "merged" "a virtual sequence" } } -{ $description "Creates an instance of the " { $link merged } " virtual sequence." } +{ $description "Creates an instance of the " { $link merged } " virtual sequence. The length of the created virtual sequences is the minimum length of the input sequences times the number of input sequences." } { $see-also <2merged> <3merged> merge } ; HELP: <2merged> ( seq1 seq2 -- merged ) diff --git a/basis/sequences/merged/merged-tests.factor b/basis/sequences/merged/merged-tests.factor index 13a46f0b72..cbd4176bef 100644 --- a/basis/sequences/merged/merged-tests.factor +++ b/basis/sequences/merged/merged-tests.factor @@ -15,3 +15,6 @@ IN: sequences.merged.tests [ 6 ] [ 5 { 1 2 3 } { 4 5 6 } <2merged> nth ] unit-test [ 4 ] [ 4 { 1 2 } { 3 4 } { 5 6 } 3merge nth ] unit-test + +[ "" ] [ "abcdefg" "" 2merge ] unit-test +[ "a1b2" ] [ "abc" "12" <2merged> "" like ] unit-test diff --git a/basis/sequences/merged/merged.factor b/basis/sequences/merged/merged.factor index d64da6efe6..c14ccf2f20 100644 --- a/basis/sequences/merged/merged.factor +++ b/basis/sequences/merged/merged.factor @@ -1,6 +1,7 @@ ! Copyright (C) 2008 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. -USING: accessors arrays kernel math sequences ; +USING: accessors arrays kernel math math.order sequences +sequences.private ; IN: sequences.merged TUPLE: merged seqs ; @@ -10,19 +11,21 @@ C: merged : <3merged> ( seq1 seq2 seq3 -- merged ) 3array ; : merge ( seqs -- seq ) - dup swap first like ; + [ ] keep first like ; : 2merge ( seq1 seq2 -- seq ) - dupd <2merged> swap like ; + [ <2merged> ] 2keep drop like ; : 3merge ( seq1 seq2 seq3 -- seq ) - pick [ <3merged> ] dip like ; + [ <3merged> ] 3keep 2drop like ; -M: merged length seqs>> [ length ] map sum ; +M: merged length + seqs>> [ [ length ] [ min ] map-reduce ] [ length ] bi * ; inline M: merged virtual@ ( n seq -- n' seq' ) - seqs>> [ length /mod ] [ nth ] bi ; + seqs>> [ length /mod ] [ nth-unsafe ] bi ; inline -M: merged virtual-seq ( merged -- seq ) [ ] { } map-as ; +M: merged virtual-exemplar ( merged -- seq ) + seqs>> [ f ] [ first ] if-empty ; inline INSTANCE: merged virtual-sequence diff --git a/basis/sequences/parser/authors.txt b/basis/sequences/parser/authors.txt new file mode 100644 index 0000000000..a07c427c98 --- /dev/null +++ b/basis/sequences/parser/authors.txt @@ -0,0 +1,2 @@ +Daniel Ehrenberg +Doug Coleman diff --git a/extra/sequence-parser/sequence-parser-tests.factor b/basis/sequences/parser/parser-tests.factor similarity index 96% rename from extra/sequence-parser/sequence-parser-tests.factor rename to basis/sequences/parser/parser-tests.factor index af13e5b86e..0c4f1390bb 100644 --- a/extra/sequence-parser/sequence-parser-tests.factor +++ b/basis/sequences/parser/parser-tests.factor @@ -1,6 +1,6 @@ -USING: tools.test sequence-parser unicode.categories kernel +USING: tools.test sequences.parser unicode.categories kernel accessors ; -IN: sequence-parser.tests +IN: sequences.parser.tests [ "hello" ] [ "hello" [ take-rest ] parse-sequence ] unit-test diff --git a/extra/sequence-parser/sequence-parser.factor b/basis/sequences/parser/parser.factor similarity index 98% rename from extra/sequence-parser/sequence-parser.factor rename to basis/sequences/parser/parser.factor index d14a77057f..44fa75239c 100644 --- a/extra/sequence-parser/sequence-parser.factor +++ b/basis/sequences/parser/parser.factor @@ -3,7 +3,7 @@ USING: accessors circular combinators.short-circuit fry io kernel locals math math.order sequences sorting.functor sorting.slots unicode.categories ; -IN: sequence-parser +IN: sequences.parser TUPLE: sequence-parser sequence n ; @@ -83,7 +83,7 @@ TUPLE: sequence-parser sequence n ; sequence length :> growing sequence-parser [ - current growing push-growing-circular + current growing growing-circular-push sequence growing sequence= ] take-until :> found growing sequence sequence= [ diff --git a/basis/sequences/product/product-docs.factor b/basis/sequences/product/product-docs.factor index 0b6805eb71..06c99ab806 100644 --- a/basis/sequences/product/product-docs.factor +++ b/basis/sequences/product/product-docs.factor @@ -1,5 +1,5 @@ ! (c)2009 Joe Groff bsd license -USING: help.markup help.syntax quotations sequences ; +USING: assocs help.markup help.syntax quotations sequences ; IN: sequences.product HELP: product-sequence @@ -44,6 +44,14 @@ HELP: product-map { $description "Calls " { $snippet "quot" } " for every element of the cartesian product of " { $snippet "sequences" } " and collects the results from " { $snippet "quot" } " into an output sequence." } { $notes { $snippet "[ ... ] product-map" } " is equivalent to, but more efficient than, " { $snippet " [ ... ] map" } "." } ; +HELP: product-map-as +{ $values { "sequences" sequence } { "quot" { $quotation "( sequence -- value )" } } { "exemplar" sequence } { "sequence" sequence } } +{ $description "Calls " { $snippet "quot" } " for every element of the cartesian product of " { $snippet "sequences" } " and collects the results from " { $snippet "quot" } " into an output sequence the same type as the " { $snippet "exemplar" } " sequence." } ; + +HELP: product-map>assoc +{ $values { "sequences" sequence } { "quot" { $quotation "( sequence -- key value )" } } { "exemplar" assoc } { "assoc" assoc } } +{ $description "Calls " { $snippet "quot" } " for every element of the cartesian product of " { $snippet "sequences" } " and collects the results from " { $snippet "quot" } " into an output assoc." } ; + HELP: product-each { $values { "sequences" sequence } { "quot" { $quotation "( sequence -- )" } } } { $description "Calls " { $snippet "quot" } " for every element of the cartesian product of " { $snippet "sequences" } "." } @@ -57,6 +65,8 @@ ARTICLE: "sequences.product" "Product sequences" product-sequence product-map + product-map-as + product-map>assoc product-each } ; diff --git a/basis/sequences/product/product.factor b/basis/sequences/product/product.factor index f783fad312..4290085482 100644 --- a/basis/sequences/product/product.factor +++ b/basis/sequences/product/product.factor @@ -1,5 +1,5 @@ ! (c)2009 Joe Groff bsd license -USING: accessors arrays kernel locals math sequences ; +USING: accessors arrays assocs kernel locals math sequences ; IN: sequences.product TUPLE: product-sequence { sequences array read-only } { lengths array read-only } ; @@ -55,11 +55,21 @@ M: product-sequence nth [ ns sequences nths quot call ns lengths product-iter ] until ] unless ; inline -:: product-map ( sequences quot -- sequence ) +:: product-map-as ( sequences quot exemplar -- sequence ) 0 :> i! - sequences [ length ] [ * ] map-reduce sequences + sequences [ length ] [ * ] map-reduce exemplar [| result | sequences [ quot call i result set-nth i 1 + i! ] product-each result ] new-like ; inline +: product-map ( sequences quot -- sequence ) + over product-map-as ; inline + +:: product-map>assoc ( sequences quot exemplar -- assoc ) + 0 :> i! + sequences [ length ] [ * ] map-reduce { } + [| result | + sequences [ quot call 2array i result set-nth i 1 + i! ] product-each + result + ] new-like exemplar assoc-like ; inline diff --git a/basis/serialize/serialize-tests.factor b/basis/serialize/serialize-tests.factor index 6dbc76386d..036356e137 100644 --- a/basis/serialize/serialize-tests.factor +++ b/basis/serialize/serialize-tests.factor @@ -16,12 +16,12 @@ IN: serialize.tests [ t ] [ 100 [ drop - 40 [ test-serialize-cell ] all? - 4 [ 40 * test-serialize-cell ] all? - 4 [ 400 * test-serialize-cell ] all? - 4 [ 4000 * test-serialize-cell ] all? + 40 [ test-serialize-cell ] all-integers? + 4 [ 40 * test-serialize-cell ] all-integers? + 4 [ 400 * test-serialize-cell ] all-integers? + 4 [ 4000 * test-serialize-cell ] all-integers? and and and - ] all? + ] all-integers? ] unit-test TUPLE: serialize-test a b ; diff --git a/basis/serialize/serialize.factor b/basis/serialize/serialize.factor index 4de858e811..0840c778d7 100644 --- a/basis/serialize/serialize.factor +++ b/basis/serialize/serialize.factor @@ -26,7 +26,7 @@ TUPLE: id obj ; C: id -M: id hashcode* obj>> hashcode* ; +M: id hashcode* nip obj>> identity-hashcode ; M: id equal? over id? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ; @@ -240,7 +240,7 @@ SYMBOL: deserialized [ ] tri ; : copy-seq-to-tuple ( seq tuple -- ) - [ dup length ] dip [ set-array-nth ] curry 2each ; + [ set-array-nth ] curry each-index ; : deserialize-tuple ( -- array ) #! Ugly because we have to intern the tuple before reading diff --git a/basis/shuffle/shuffle-docs.factor b/basis/shuffle/shuffle-docs.factor index 15398450a7..363727a6c5 100644 --- a/basis/shuffle/shuffle-docs.factor +++ b/basis/shuffle/shuffle-docs.factor @@ -1,5 +1,7 @@ USING: help.markup help.syntax ; IN: shuffle +HELP: spin $complex-shuffle ; HELP: roll $complex-shuffle ; HELP: -roll $complex-shuffle ; +HELP: tuck $complex-shuffle ; diff --git a/basis/shuffle/shuffle.factor b/basis/shuffle/shuffle.factor index 43c0b75be1..b826606df5 100644 --- a/basis/shuffle/shuffle.factor +++ b/basis/shuffle/shuffle.factor @@ -8,7 +8,7 @@ IN: shuffle index-assoc ( sequence -- assoc ) - dup length zip >hashtable ; + dup length iota zip >hashtable ; PRIVATE> @@ -22,6 +22,10 @@ MACRO: shuffle-effect ( effect -- ) SYNTAX: shuffle( ")" parse-effect suffix! \ shuffle-effect suffix! ; +: tuck ( x y -- y x y ) swap over ; inline deprecated + +: spin ( x y z -- z y x ) swap rot ; inline deprecated + : roll ( x y z t -- y z t x ) [ rot ] dip swap ; inline deprecated : -roll ( x y z t -- t x y z ) swap [ -rot ] dip ; inline deprecated diff --git a/basis/smtp/smtp.factor b/basis/smtp/smtp.factor index 83457defa5..61ccd5c435 100644 --- a/basis/smtp/smtp.factor +++ b/basis/smtp/smtp.factor @@ -187,7 +187,7 @@ ERROR: invalid-header-string string ; "<" % 64 random-bits # "-" % - micros # + system-micros # "@" % smtp-domain get [ host-name ] unless* % ">" % diff --git a/basis/sorting/insertion/insertion.factor b/basis/sorting/insertion/insertion.factor index 78b1493920..b7fefcad63 100644 --- a/basis/sorting/insertion/insertion.factor +++ b/basis/sorting/insertion/insertion.factor @@ -13,4 +13,4 @@ PRIVATE> : insertion-sort ( seq quot -- ) ! quot is a transformation on elements - over length [ insert ] with with each ; inline + over length [ insert ] with with each-integer ; inline diff --git a/basis/sorting/slots/slots-tests.factor b/basis/sorting/slots/slots-tests.factor index 5ebd4438fe..08fc0e921d 100644 --- a/basis/sorting/slots/slots-tests.factor +++ b/basis/sorting/slots/slots-tests.factor @@ -1,8 +1,7 @@ ! Copyright (C) 2009 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: accessors math.order sorting.slots tools.test -sorting.human arrays sequences kernel assocs multiline -sorting.functor ; +arrays sequences kernel assocs multiline sorting.functor ; IN: sorting.literals.tests TUPLE: sort-test a b c tuple2 ; @@ -42,7 +41,7 @@ TUPLE: tuple2 d ; T{ sort-test f 1 1 11 } T{ sort-test f 2 5 3 } T{ sort-test f 2 5 2 } - } { { a>> human<=> } { b>> human>=< } { c>> <=> } } sort-by + } { { a>> <=> } { b>> >=< } { c>> <=> } } sort-by ] unit-test [ { } ] @@ -83,14 +82,14 @@ TUPLE: tuple2 d ; { length-test<=> <=> } sort-by ] unit-test -[ { { 0 1 } { 1 2 } { 1 1 } { 3 2 } } ] +[ { { { 0 } 1 } { { 1 } 2 } { { 1 } 1 } { { 3 1 } 2 } } ] [ - { { 3 2 } { 1 2 } { 0 1 } { 1 1 } } + { { { 3 1 } 2 } { { 1 } 2 } { { 0 } 1 } { { 1 } 1 } } { length-test<=> <=> } sort-keys-by ] unit-test -[ { { 0 1 } { 1 1 } { 3 2 } { 1 2 } } ] +[ { { 0 { 1 } } { 1 { 1 } } { 3 { 2 4 } } { 1 { 2 0 0 0 } } } ] [ - { { 3 2 } { 1 2 } { 0 1 } { 1 1 } } + { { 3 { 2 4 } } { 1 { 2 0 0 0 } } { 0 { 1 } } { 1 { 1 } } } { length-test<=> <=> } sort-values-by ] unit-test diff --git a/basis/specialized-arrays/mirrors/mirrors.factor b/basis/specialized-arrays/mirrors/mirrors.factor index ee7953b501..eea9e83b58 100644 --- a/basis/specialized-arrays/mirrors/mirrors.factor +++ b/basis/specialized-arrays/mirrors/mirrors.factor @@ -4,5 +4,3 @@ USING: mirrors specialized-arrays math.vectors ; IN: specialized-arrays.mirrors INSTANCE: specialized-array enumerated-sequence -INSTANCE: simd-128 enumerated-sequence -INSTANCE: simd-256 enumerated-sequence diff --git a/basis/specialized-arrays/prettyprint/prettyprint.factor b/basis/specialized-arrays/prettyprint/prettyprint.factor old mode 100755 new mode 100644 diff --git a/basis/specialized-arrays/specialized-arrays-docs.factor b/basis/specialized-arrays/specialized-arrays-docs.factor old mode 100755 new mode 100644 diff --git a/basis/specialized-arrays/specialized-arrays-tests.factor b/basis/specialized-arrays/specialized-arrays-tests.factor old mode 100755 new mode 100644 index bc293b19e0..c7e1285689 --- a/basis/specialized-arrays/specialized-arrays-tests.factor +++ b/basis/specialized-arrays/specialized-arrays-tests.factor @@ -10,8 +10,6 @@ FROM: alien.c-types => float ; SPECIALIZED-ARRAY: int SPECIALIZED-ARRAYS: bool ushort char uint float ulonglong ; -[ ulonglong ] [ ulonglong-array{ } element-type ] unit-test - [ t ] [ { 1 2 3 } >int-array int-array? ] unit-test [ t ] [ int-array{ 1 2 3 } int-array? ] unit-test @@ -20,7 +18,7 @@ SPECIALIZED-ARRAYS: bool ushort char uint float ulonglong ; [ t ] [ { t f t } >bool-array underlying>> - { 1 0 1 } "bool" heap-size { + { 1 0 1 } bool heap-size { { 1 [ >char-array ] } { 4 [ >uint-array ] } } case underlying>> = @@ -153,3 +151,22 @@ SPECIALIZED-ARRAY: __does_not_exist__ __does_not_exist__ specialized-array-vocab forget-vocab ] with-compilation-unit ] unit-test + +STRUCT: struct-resize-test { x int } ; + +SPECIALIZED-ARRAY: struct-resize-test + +[ 40 ] [ 10 byte-length ] unit-test + +: struct-resize-test-usage ( seq -- seq ) + [ struct-resize-test swap >>x ] map + >struct-resize-test-array + [ x>> ] { } map-as ; + +[ { 10 20 30 } ] [ { 10 20 30 } struct-resize-test-usage ] unit-test + +[ ] [ "IN: specialized-arrays.tests USE: classes.struct USE: alien.c-types STRUCT: struct-resize-test { x int } { y int } ;" eval( -- ) ] unit-test + +[ 80 ] [ 10 byte-length ] unit-test + +[ { 10 20 30 } ] [ { 10 20 30 } struct-resize-test-usage ] unit-test diff --git a/basis/specialized-arrays/specialized-arrays.factor b/basis/specialized-arrays/specialized-arrays.factor old mode 100755 new mode 100644 index 711354d803..eda793ff22 --- a/basis/specialized-arrays/specialized-arrays.factor +++ b/basis/specialized-arrays/specialized-arrays.factor @@ -2,8 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors alien alien.c-types alien.data alien.parser assocs byte-arrays classes compiler.units functors kernel lexer -libc math math.vectors math.vectors.private -math.vectors.specialization namespaces +libc math math.vectors math.vectors.private namespaces parser prettyprint.custom sequences sequences.private strings summary vocabs vocabs.loader vocabs.parser vocabs.generated words fry combinators make ; @@ -31,7 +30,6 @@ M: bad-byte-array-length summary FUNCTOR: define-array ( T -- ) A DEFINES-CLASS ${T}-array -S DEFINES-CLASS ${T}-sequence DEFINES <${A}> (A) DEFINES (${A}) DEFINES @@ -47,8 +45,6 @@ SET-NTH [ T dup c-setter array-accessor ] WHERE -MIXIN: S - TUPLE: A { underlying c-ptr read-only } { length array-capacity read-only } ; @@ -69,8 +65,6 @@ TUPLE: A [ drop \ T bad-byte-array-length ] unless ; inline -M: A new-underlying drop byte-array>A ; - M: A clone [ underlying>> clone ] [ length>> ] bi ; inline M: A length length>> ; inline @@ -96,8 +90,6 @@ M: A resize M: A byte-length length \ T heap-size * ; inline -M: A element-type drop \ T ; inline - M: A direct-array-syntax drop \ A@ ; M: A pprint-delims drop \ A{ \ } ; @@ -109,7 +101,11 @@ SYNTAX: A@ scan-object scan-object suffix! ; INSTANCE: A specialized-array -A T c-type-boxed-class f specialize-vector-words +M: A vs+ [ + \ T c-type-clamp ] 2map ; inline +M: A vs- [ - \ T c-type-clamp ] 2map ; inline +M: A vs* [ * \ T c-type-clamp ] 2map ; inline + +M: A v*high [ * \ T heap-size neg shift ] 2map ; inline ;FUNCTOR diff --git a/basis/specialized-vectors/specialized-vectors.factor b/basis/specialized-vectors/specialized-vectors.factor index 75197d9ec0..f71e308ad1 100644 --- a/basis/specialized-vectors/specialized-vectors.factor +++ b/basis/specialized-vectors/specialized-vectors.factor @@ -15,7 +15,6 @@ FUNCTOR: define-vector ( T -- ) V DEFINES-CLASS ${T}-vector A IS ${T}-array -S IS ${T}-sequence IS <${A}> >V DEFERS >${V} @@ -38,7 +37,6 @@ M: V pprint* pprint-object ; SYNTAX: V{ \ } [ >V ] parse-literal ; INSTANCE: V growable -INSTANCE: V S ;FUNCTOR diff --git a/basis/splitting/monotonic/monotonic.factor b/basis/splitting/monotonic/monotonic.factor index 3641345a3e..32bb8b46c6 100644 --- a/basis/splitting/monotonic/monotonic.factor +++ b/basis/splitting/monotonic/monotonic.factor @@ -26,7 +26,7 @@ PRIVATE> : (monotonic-slice) ( seq quot class -- slices ) [ dupd '[ - [ length ] [ ] [ 1 over change-circular-start ] tri + [ length iota ] [ ] [ 1 over change-circular-start ] tri [ @ not [ , ] [ drop ] if ] 3each ] { } make dup empty? [ over length 1 - prefix ] when -1 prefix 2 clump diff --git a/basis/stack-checker/alien/alien.factor b/basis/stack-checker/alien/alien.factor index 2a20ba74cd..fdfda6dd9e 100644 --- a/basis/stack-checker/alien/alien.factor +++ b/basis/stack-checker/alien/alien.factor @@ -1,8 +1,9 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel sequences accessors combinators math namespaces init sets words assocs alien.libraries alien alien.c-types -stack-checker.backend stack-checker.errors stack-checker.visitor ; +cpu.architecture fry stack-checker.backend stack-checker.errors +stack-checker.visitor ; IN: stack-checker.alien TUPLE: alien-node-params return parameters abi in-d out-d ; @@ -11,6 +12,8 @@ TUPLE: alien-invoke-params < alien-node-params library function ; TUPLE: alien-indirect-params < alien-node-params ; +TUPLE: alien-assembly-params < alien-node-params quot ; + TUPLE: alien-callback-params < alien-node-params quot xt ; : param-prep-quot ( node -- quot ) @@ -49,7 +52,7 @@ TUPLE: alien-callback-params < alien-node-params quot xt ; pop-literal nip >>parameters pop-literal nip >>return ! Quotation which coerces parameters to required types - dup param-prep-quot [ dip ] curry infer-quot-here + dup param-prep-quot '[ _ dip ] infer-quot-here ! Magic #: consume the function pointer, too dup 1 alien-stack ! Add node to IR @@ -57,11 +60,28 @@ TUPLE: alien-callback-params < alien-node-params quot xt ; ! Quotation which coerces return value to required type return-prep-quot infer-quot-here ; -: callback-xt ( word -- alien ) - callbacks get [ ] cache ; +: infer-alien-assembly ( -- ) + alien-assembly-params new + ! Compile-time parameters + pop-literal nip >>quot + pop-literal nip >>abi + pop-literal nip >>parameters + pop-literal nip >>return + ! Quotation which coerces parameters to required types + dup param-prep-quot infer-quot-here + ! Magic #: consume exactly the number of inputs + dup 0 alien-stack + ! Add node to IR + dup #alien-assembly, + ! Quotation which coerces return value to required type + return-prep-quot infer-quot-here ; + +: callback-xt ( word return-rewind -- alien ) + [ callbacks get ] dip '[ _ ] cache ; : callback-bottom ( params -- ) - xt>> [ callback-xt ] curry infer-quot-here ; + [ xt>> ] [ callback-return-rewind ] bi + '[ _ _ callback-xt ] infer-quot-here ; : infer-alien-callback ( -- ) alien-callback-params new @@ -69,6 +89,6 @@ TUPLE: alien-callback-params < alien-node-params quot xt ; pop-literal nip >>abi pop-literal nip >>parameters pop-literal nip >>return - "( callback )" f >>xt + "( callback )" >>xt dup callback-bottom #alien-callback, ; diff --git a/basis/stack-checker/backend/backend-tests.factor b/basis/stack-checker/backend/backend-tests.factor index 48cd10a7ee..b58998cb49 100644 --- a/basis/stack-checker/backend/backend-tests.factor +++ b/basis/stack-checker/backend/backend-tests.factor @@ -1,17 +1,21 @@ USING: stack-checker.backend tools.test kernel namespaces -stack-checker.state sequences ; +stack-checker.state stack-checker.values sequences assocs ; IN: stack-checker.backend.tests [ ] [ V{ } clone \ meta-d set V{ } clone \ meta-r set V{ } clone \ literals set - 0 d-in set + H{ } clone known-values set + 0 input-count set ] unit-test [ 0 ] [ 0 ensure-d length ] unit-test [ 2 ] [ 2 ensure-d length ] unit-test + +[ t ] [ meta-d [ known-values get at input-parameter? ] all? ] unit-test + [ 2 ] [ meta-d length ] unit-test [ 3 ] [ 3 ensure-d length ] unit-test diff --git a/basis/stack-checker/backend/backend.factor b/basis/stack-checker/backend/backend.factor old mode 100755 new mode 100644 index 5411c885ad..b2a99f0731 --- a/basis/stack-checker/backend/backend.factor +++ b/basis/stack-checker/backend/backend.factor @@ -5,15 +5,19 @@ parser sequences strings vectors words quotations effects classes continuations assocs combinators compiler.errors accessors math.order definitions sets hints macros stack-checker.state stack-checker.visitor stack-checker.errors stack-checker.values -stack-checker.recursive-state summary ; +stack-checker.recursive-state stack-checker.dependencies summary ; IN: stack-checker.backend : push-d ( obj -- ) meta-d push ; +: introduce-values ( values -- ) + [ [ [ input-parameter ] dip set-known ] each ] + [ length input-count +@ ] + [ #introduce, ] + tri ; + : pop-d ( -- obj ) - meta-d [ - dup 1array #introduce, d-in inc - ] [ pop ] if-empty ; + meta-d [ dup 1array introduce-values ] [ pop ] if-empty ; : peek-d ( -- obj ) pop-d dup push-d ; @@ -24,7 +28,7 @@ IN: stack-checker.backend meta-d 2dup length > [ 2dup [ nip >array ] [ length - make-values ] [ nip delete-all ] 2tri - [ length d-in +@ ] [ #introduce, ] [ meta-d push-all ] tri + [ introduce-values ] [ meta-d push-all ] bi meta-d push-all ] when swap tail* ; diff --git a/basis/stack-checker/branches/branches.factor b/basis/stack-checker/branches/branches.factor old mode 100755 new mode 100644 index 8b0665aa49..99e5a70409 --- a/basis/stack-checker/branches/branches.factor +++ b/basis/stack-checker/branches/branches.factor @@ -11,7 +11,7 @@ IN: stack-checker.branches SYMBOLS: +bottom+ +top+ ; -: unify-inputs ( max-d-in d-in meta-d -- new-meta-d ) +: unify-inputs ( max-input-count input-count meta-d -- new-meta-d ) ! Introduced values can be anything, and don't unify with ! literals. dup [ [ - +top+ ] dip append ] [ 3drop f ] if ; @@ -24,7 +24,7 @@ SYMBOLS: +bottom+ +top+ ; '[ _ +bottom+ pad-head ] map ] unless ; -: phi-inputs ( max-d-in pairs -- newseq ) +: phi-inputs ( max-input-count pairs -- newseq ) dup empty? [ nip ] [ swap '[ [ _ ] dip first2 unify-inputs ] map pad-with-bottom @@ -61,9 +61,9 @@ SYMBOL: quotations branch-variable ; : datastack-phi ( seq -- phi-in phi-out ) - [ d-in branch-variable ] [ \ meta-d active-variable ] bi + [ input-count branch-variable ] [ \ meta-d active-variable ] bi unify-branches - [ d-in set ] [ ] [ dup >vector \ meta-d set ] tri* ; + [ input-count set ] [ ] [ dup >vector \ meta-d set ] tri* ; : terminated-phi ( seq -- terminated ) terminated? branch-variable ; @@ -80,7 +80,7 @@ SYMBOL: quotations : copy-inference ( -- ) \ meta-d [ clone ] change literals [ clone ] change - d-in [ ] change ; + input-count [ ] change ; GENERIC: infer-branch ( literal -- namespace ) diff --git a/basis/math/vectors/simd/functor/authors.txt b/basis/stack-checker/dependencies/authors.txt similarity index 100% rename from basis/math/vectors/simd/functor/authors.txt rename to basis/stack-checker/dependencies/authors.txt diff --git a/basis/stack-checker/state/state-tests.factor b/basis/stack-checker/dependencies/dependencies-tests.factor similarity index 53% rename from basis/stack-checker/state/state-tests.factor rename to basis/stack-checker/dependencies/dependencies-tests.factor index a4dea993c0..9bcec64033 100644 --- a/basis/stack-checker/state/state-tests.factor +++ b/basis/stack-checker/dependencies/dependencies-tests.factor @@ -1,5 +1,5 @@ -IN: stack-checker.state.tests -USING: tools.test stack-checker.state words kernel namespaces +IN: stack-checker.dependencies.tests +USING: tools.test stack-checker.dependencies words kernel namespaces definitions ; : computing-dependencies ( quot -- dependencies ) @@ -28,3 +28,10 @@ SYMBOL: b b inlined-dependency depends-on ] computing-dependencies ] unit-test + +[ flushed-dependency ] [ f flushed-dependency strongest-dependency ] unit-test +[ flushed-dependency ] [ flushed-dependency f strongest-dependency ] unit-test +[ inlined-dependency ] [ flushed-dependency inlined-dependency strongest-dependency ] unit-test +[ inlined-dependency ] [ called-dependency inlined-dependency strongest-dependency ] unit-test +[ flushed-dependency ] [ called-dependency flushed-dependency strongest-dependency ] unit-test +[ called-dependency ] [ called-dependency f strongest-dependency ] unit-test diff --git a/basis/stack-checker/dependencies/dependencies.factor b/basis/stack-checker/dependencies/dependencies.factor new file mode 100644 index 0000000000..f0c77b8398 --- /dev/null +++ b/basis/stack-checker/dependencies/dependencies.factor @@ -0,0 +1,37 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: assocs classes.algebra fry kernel math namespaces +sequences words ; +IN: stack-checker.dependencies + +! Words that the current quotation depends on +SYMBOL: dependencies + +SYMBOLS: inlined-dependency flushed-dependency called-dependency ; + +: index>= ( obj1 obj2 seq -- ? ) + [ index ] curry bi@ >= ; + +: dependency>= ( how1 how2 -- ? ) + { called-dependency flushed-dependency inlined-dependency } + index>= ; + +: strongest-dependency ( how1 how2 -- how ) + [ called-dependency or ] bi@ [ dependency>= ] most ; + +: depends-on ( word how -- ) + over primitive? [ 2drop ] [ + dependencies get dup [ + swap '[ _ strongest-dependency ] change-at + ] [ 3drop ] if + ] if ; + +! Generic words that the current quotation depends on +SYMBOL: generic-dependencies + +: ?class-or ( class/f class -- class' ) + swap [ class-or ] when* ; + +: depends-on-generic ( generic class -- ) + generic-dependencies get dup + [ swap '[ _ ?class-or ] change-at ] [ 3drop ] if ; diff --git a/basis/stack-checker/errors/errors-docs.factor b/basis/stack-checker/errors/errors-docs.factor old mode 100755 new mode 100644 index 5da5197700..4b432e733f --- a/basis/stack-checker/errors/errors-docs.factor +++ b/basis/stack-checker/errors/errors-docs.factor @@ -12,10 +12,10 @@ HELP: do-not-compile } } ; -HELP: literal-expected -{ $error-description "Thrown when inference encounters a combinator or macro being applied to a value which is not known to be a literal, or constructed in a manner which can be analyzed statically. Such code needs changes before it can compile and run. See " { $link "inference-combinators" } " and " { $link "inference-escape" } " for details." } +HELP: unknown-macro-input +{ $error-description "Thrown when inference encounters a combinator or macro being applied to an input parameter of a non-" { $link POSTPONE: inline } " word. The word needs to be declared " { $link POSTPONE: inline } " before its callers can compile and run. See " { $link "inference-combinators" } " and " { $link "inference-escape" } " for details." } { $examples - "In this example, the words being defined cannot be called, because they fail to compile with a " { $link literal-expected } " error:" + "In this example, the words being defined cannot be called, because they fail to compile with a " { $link unknown-macro-input } " error:" { $code ": bad-example ( quot -- )" " [ call ] [ call ] bi ;" @@ -41,6 +41,27 @@ HELP: literal-expected } } ; +HELP: bad-macro-input +{ $error-description "Thrown when inference encounters a combinator or macro being applied to a value which is not known at compile time. Such code needs changes before it can compile and run. See " { $link "inference-combinators" } " and " { $link "inference-escape" } " for details." } +{ $examples + "In this example, the words being defined cannot be called, because they fail to compile with a " { $link bad-macro-input } " error:" + { $code + ": bad-example ( quot -- )" + " [ . ] append call ; inline" + "" + ": usage ( -- )" + " 2 2 [ + ] bad-example ;" + } + "One fix is to use " { $link compose } " instead of " { $link append } ":" + { $code + ": good-example ( quot -- )" + " [ . ] compose call ; inline" + "" + ": usage ( -- )" + " 2 2 [ + ] good-example ;" + } +} ; + HELP: unbalanced-branches-error { $values { "in" "a sequence of integers" } { "out" "a sequence of integers" } } { $description "Throws an " { $link unbalanced-branches-error } "." } @@ -121,7 +142,8 @@ ARTICLE: "inference-errors" "Stack checker errors" "Errors thrown when insufficient information is available to calculate the stack effect of a call to a combinator or macro (see " { $link "inference-combinators" } "):" { $subsections do-not-compile - literal-expected + unknown-macro-input + bad-macro-input } "Error thrown when a word's stack effect declaration does not match the composition of the stack effects of its factors:" { $subsections effect-error } diff --git a/basis/stack-checker/errors/errors.factor b/basis/stack-checker/errors/errors.factor index b1071df708..ff06b2ac27 100644 --- a/basis/stack-checker/errors/errors.factor +++ b/basis/stack-checker/errors/errors.factor @@ -1,13 +1,14 @@ ! Copyright (C) 2006, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel stack-checker.values ; IN: stack-checker.errors TUPLE: inference-error ; ERROR: do-not-compile < inference-error word ; -ERROR: literal-expected < inference-error what ; +ERROR: bad-macro-input < inference-error macro ; + +ERROR: unknown-macro-input < inference-error macro ; ERROR: unbalanced-branches-error < inference-error branches quots ; @@ -29,10 +30,6 @@ ERROR: unbalanced-recursion-error < inference-error word height ; ERROR: inconsistent-recursive-call-error < inference-error word ; -ERROR: unknown-primitive-error < inference-error ; +ERROR: transform-expansion-error < inference-error error continuation word ; -ERROR: transform-expansion-error < inference-error word error ; - -ERROR: bad-declaration-error < inference-error declaration ; - -M: object (literal) "literal value" literal-expected ; \ No newline at end of file +ERROR: bad-declaration-error < inference-error declaration ; \ No newline at end of file diff --git a/basis/stack-checker/errors/prettyprint/prettyprint.factor b/basis/stack-checker/errors/prettyprint/prettyprint.factor index 5be5722c23..f762e0559b 100644 --- a/basis/stack-checker/errors/prettyprint/prettyprint.factor +++ b/basis/stack-checker/errors/prettyprint/prettyprint.factor @@ -1,20 +1,21 @@ -! Copyright (C) 2008, 2009 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors kernel prettyprint io debugger +USING: accessors arrays kernel prettyprint io debugger sequences assocs stack-checker.errors summary effects ; IN: stack-checker.errors.prettyprint -M: literal-expected summary - what>> "Got a computed value where a " " was expected" surround ; +M: unknown-macro-input summary + macro>> name>> "Cannot apply “" "†to an input parameter of a non-inline word" surround ; -M: literal-expected error. summary print ; +M: bad-macro-input summary + macro>> name>> "Cannot apply “" "†to a run-time computed value" surround ; M: unbalanced-branches-error summary drop "Unbalanced branches" ; M: unbalanced-branches-error error. dup summary print - [ quots>> ] [ branches>> [ length ] { } assoc>map ] bi zip + [ quots>> ] [ branches>> [ length [ "x" ] bi@ ] { } assoc>map ] bi zip [ [ first pprint-short bl ] [ second effect>string print ] bi ] each ; M: too-many->r summary @@ -49,14 +50,14 @@ M: inconsistent-recursive-call-error summary "The recursive word " " calls itself with a different set of quotation parameters than were input" surround ; -M: unknown-primitive-error summary - word>> name>> "The " " word cannot be called from optimized words" surround ; - M: transform-expansion-error summary word>> name>> "Macro expansion of " " threw an error" surround ; M: transform-expansion-error error. - [ summary print ] [ error>> error. ] bi ; + [ summary print ] + [ nl "The error was:" print error>> error. nl ] + [ continuation>> traceback-link. ] + tri ; M: do-not-compile summary word>> name>> "Cannot compile call to " prepend ; \ No newline at end of file diff --git a/basis/stack-checker/inlining/inlining.factor b/basis/stack-checker/inlining/inlining.factor index c99e0f0252..20d61b9c37 100644 --- a/basis/stack-checker/inlining/inlining.factor +++ b/basis/stack-checker/inlining/inlining.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: fry namespaces assocs kernel sequences words accessors definitions math math.order effects classes arrays combinators @@ -10,6 +10,7 @@ stack-checker.visitor stack-checker.backend stack-checker.branches stack-checker.known-words +stack-checker.dependencies stack-checker.recursive-state ; IN: stack-checker.inlining @@ -28,8 +29,6 @@ fixed-point introductions loop? ; -M: inline-recursive hashcode* id>> hashcode* ; - : inlined-block? ( word -- ? ) "inlined-block" word-prop ; : ( word -- label ) @@ -43,7 +42,7 @@ M: inline-recursive hashcode* id>> hashcode* ; : make-copies ( values effect-in -- values' ) [ length cut* ] keep [ quotation-param? [ copy-value ] [ drop ] if ] 2map - [ make-values ] dip append ; + [ length make-values ] dip append ; SYMBOL: enter-in SYMBOL: enter-out @@ -81,7 +80,7 @@ SYMBOL: enter-out bi ; : recursive-word-inputs ( label -- n ) - entry-stack-height d-in get + ; + entry-stack-height input-count get + ; : (inline-recursive-word) ( word -- label in out visitor terminated? ) dup prepare-stack diff --git a/basis/stack-checker/known-words/known-words.factor b/basis/stack-checker/known-words/known-words.factor index 2c0ce853aa..9bc61c6353 100644 --- a/basis/stack-checker/known-words/known-words.factor +++ b/basis/stack-checker/known-words/known-words.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2004, 2009 Slava Pestov, Daniel Ehrenberg. +! Copyright (C) 2004, 2010 Slava Pestov, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. USING: fry accessors alien alien.accessors arrays byte-arrays classes continuations.private effects generic hashtables @@ -21,6 +21,7 @@ stack-checker.visitor stack-checker.backend stack-checker.branches stack-checker.transforms +stack-checker.dependencies stack-checker.recursive-state ; IN: stack-checker.known-words @@ -43,7 +44,6 @@ IN: stack-checker.known-words { swapd (( x y z -- y x z )) } { nip (( x y -- y )) } { 2nip (( x y z -- z )) } - { tuck (( x y -- y x y )) } { over (( x y -- x y x )) } { pick (( x y z -- x y z x )) } { swap (( x y -- y x )) } @@ -98,8 +98,8 @@ M: composed infer-call* 1 infer->r infer-call terminated? get [ 1 infer-r> infer-call ] unless ; -M: object infer-call* - "literal quotation" literal-expected ; +M: input-parameter infer-call* \ call unknown-macro-input ; +M: object infer-call* \ call bad-macro-input ; : infer-ndip ( word n -- ) [ literals get ] 2dip @@ -153,7 +153,7 @@ M: bad-executable summary : infer- ( -- ) \ - peek-d literal value>> second 1 + { tuple } + peek-d literal value>> second 1 + "obj" { tuple } apply-word/effect ; \ [ infer- ] "special" set-word-prop @@ -221,17 +221,32 @@ M: bad-executable summary dup '[ _ infer-call-effect ] "special" set-word-prop ] each -\ do-primitive [ unknown-primitive-error ] "special" set-word-prop - \ if [ infer-if ] "special" set-word-prop \ dispatch [ infer-dispatch ] "special" set-word-prop \ alien-invoke [ infer-alien-invoke ] "special" set-word-prop \ alien-indirect [ infer-alien-indirect ] "special" set-word-prop +\ alien-assembly [ infer-alien-assembly ] "special" set-word-prop \ alien-callback [ infer-alien-callback ] "special" set-word-prop +{ + do-primitive + mega-cache-miss + mega-cache-lookup + inline-cache-miss + inline-cache-miss-tail + unwind-native-frames + set-datastack + set-callstack + set-retainstack + unwind-native-frames + lazy-jit-compile + c-to-factor + call-clear +} [ dup '[ _ do-not-compile ] "special" set-word-prop ] each + : infer-special ( word -- ) - "special" word-prop call( -- ) ; + [ current-word set ] [ "special" word-prop call( -- ) ] bi ; : infer-local-reader ( word -- ) (( -- value )) apply-word/effect ; @@ -485,13 +500,13 @@ M: bad-executable summary \ (word) { object object object } { word } define-primitive \ (word) make-flushable -\ word-xt { word } { integer integer } define-primitive -\ word-xt make-flushable +\ word-code { word } { integer integer } define-primitive +\ word-code make-flushable -\ getenv { fixnum } { object } define-primitive -\ getenv make-flushable +\ special-object { fixnum } { object } define-primitive +\ special-object make-flushable -\ setenv { object fixnum } { } define-primitive +\ set-special-object { object fixnum } { } define-primitive \ (exists?) { string } { object } define-primitive @@ -511,8 +526,11 @@ M: bad-executable summary \ code-room { } { byte-array } define-primitive \ code-room make-flushable -\ micros { } { integer } define-primitive -\ micros make-flushable +\ system-micros { } { integer } define-primitive +\ system-micros make-flushable + +\ nano-count { } { integer } define-primitive +\ nano-count make-flushable \ tag { object } { fixnum } define-primitive \ tag make-foldable @@ -623,11 +641,7 @@ M: bad-executable summary \ { integer object } { array } define-primitive \ make-flushable -\ begin-scan { } { } define-primitive - -\ next-object { } { object } define-primitive - -\ end-scan { } { } define-primitive +\ all-instances { } { array } define-primitive \ size { object } { fixnum } define-primitive \ size make-flushable @@ -648,6 +662,8 @@ M: bad-executable summary \ fseek { alien integer integer } { } define-primitive +\ ftell { alien } { integer } define-primitive + \ fclose { alien } { } define-primitive \ { object } { wrapper } define-primitive @@ -662,8 +678,8 @@ M: bad-executable summary \ array>quotation { array } { quotation } define-primitive \ array>quotation make-flushable -\ quotation-xt { quotation } { integer } define-primitive -\ quotation-xt make-flushable +\ quotation-code { quotation } { integer integer } define-primitive +\ quotation-code make-flushable \ { tuple-layout } { tuple } define-primitive \ make-flushable @@ -704,15 +720,23 @@ M: bad-executable summary \ lookup-method { object array } { word } define-primitive \ reset-dispatch-stats { } { } define-primitive -\ dispatch-stats { } { array } define-primitive +\ dispatch-stats { } { byte-array } define-primitive \ optimized? { word } { object } define-primitive \ strip-stack-traces { } { } define-primitive -\ { word } { alien } define-primitive +\ { integer word } { alien } define-primitive \ enable-gc-events { } { } define-primitive \ disable-gc-events { } { object } define-primitive \ profiling { object } { } define-primitive + +\ (identity-hashcode) { object } { fixnum } define-primitive + +\ compute-identity-hashcode { object } { } define-primitive + +\ (exit) { integer } { } define-primitive + +\ quot-compiled? { quotation } { object } define-primitive diff --git a/basis/stack-checker/stack-checker-docs.factor b/basis/stack-checker/stack-checker-docs.factor index c806f98e2e..eb25b9be57 100644 --- a/basis/stack-checker/stack-checker-docs.factor +++ b/basis/stack-checker/stack-checker-docs.factor @@ -11,14 +11,14 @@ IN: stack-checker ARTICLE: "inference-simple" "Straight-line stack effects" "The simplest case is when a piece of code does not have any branches or recursion, and just pushes literals and calls words." $nl -"Pushing a literal has stack effect " { $snippet "( -- object )" } ". The stack effect of a most words is always known statically from the declaration. Stack effects of " { $link POSTPONE: inline } " words and " { $link "macros" } ", may depend on literals pushed on the stack prior to the call, and this case is discussed in " { $link "inference-combinators" } "." +"Pushing a literal has stack effect " { $snippet "( -- x )" } ". The stack effect of a most words is always known statically from the declaration. Stack effects of " { $link POSTPONE: inline } " words and " { $link "macros" } ", may depend on literals pushed on the stack prior to the call, and this case is discussed in " { $link "inference-combinators" } "." $nl "The stack effect of each element in a code snippet is composed. The result is then the stack effect of the snippet." $nl "An example:" -{ $example "[ 1 2 3 ] infer." "( -- object object object )" } +{ $example "[ 1 2 3 ] infer." "( -- x x x )" } "Another example:" -{ $example "[ 2 + ] infer." "( object -- object )" } ; +{ $example "[ 2 + ] infer." "( x -- x )" } ; ARTICLE: "inference-combinators" "Combinator stack effects" "If a word calls a combinator, one of the following two conditions must hold for the stack checker to succeed:" @@ -26,19 +26,19 @@ ARTICLE: "inference-combinators" "Combinator stack effects" { "The combinator must be called with a quotation that is either literal or built from literal quotations, " { $link curry } ", and " { $link compose } ". (Note that quotations that use " { $vocab-link "fry" } " or " { $vocab-link "locals" } " use " { $link curry } " and " { $link compose } " from the perspective of the stack checker.)" } { "If the word is declared " { $link POSTPONE: inline } ", the combinator may additionally be called on one of the word's input parameters or with quotations built from the word's input parameters, literal quotations, " { $link curry } ", and " { $link compose } ". When inline, a word is itself considered to be a combinator, and its callers must in turn satisfy these conditions." } } -"If neither condition holds, the stack checker throws a " { $link literal-expected } " error. To make the code compile, a runtime checking combinator such as " { $link POSTPONE: call( } " must be used instead. See " { $link "inference-escape" } " for details. An inline combinator can be called with an unknown quotation by " { $link curry } "ing the quotation onto a literal quotation that uses " { $link POSTPONE: call( } "." +"If neither condition holds, the stack checker throws a " { $link unknown-macro-input } " or " { $link bad-macro-input } " error. To make the code compile, a runtime checking combinator such as " { $link POSTPONE: call( } " must be used instead. See " { $link "inference-escape" } " for details. An inline combinator can be called with an unknown quotation by " { $link curry } "ing the quotation onto a literal quotation that uses " { $link POSTPONE: call( } "." { $heading "Examples" } { $subheading "Calling a combinator" } "The following usage of " { $link map } " passes the stack checker, because the quotation is the result of " { $link curry } ":" -{ $example "USING: math sequences ;" "[ [ + ] curry map ] infer." "( object object -- object )" } +{ $example "USING: math sequences ;" "[ [ + ] curry map ] infer." "( x x -- x )" } "The equivalent code using " { $vocab-link "fry" } " and " { $vocab-link "locals" } " likewise passes the stack checker:" -{ $example "USING: fry math sequences ;" "[ '[ _ + ] map ] infer." "( object object -- object )" } -{ $example "USING: locals math sequences ;" "[| a | [ a + ] map ] infer." "( object object -- object )" } +{ $example "USING: fry math sequences ;" "[ '[ _ + ] map ] infer." "( x x -- x )" } +{ $example "USING: locals math sequences ;" "[| a | [ a + ] map ] infer." "( x x -- x )" } { $subheading "Defining an inline combinator" } "The following word calls a quotation twice; the word is declared " { $link POSTPONE: inline } ", since it invokes " { $link call } " on the result of " { $link compose } " on an input parameter:" { $code ": twice ( value quot -- result ) dup compose call ; inline" } "The following code now passes the stack checker; it would fail were " { $snippet "twice" } " not declared " { $link POSTPONE: inline } ":" -{ $unchecked-example "USE: math.functions" "[ [ sqrt ] twice ] infer." "( object -- object )" } +{ $unchecked-example "USE: math.functions" "[ [ sqrt ] twice ] infer." "( x -- x )" } { $subheading "Defining a combinator for unknown quotations" } "In the next example, " { $link POSTPONE: call( } " must be used because the quotation the result of calling a runtime accessor, and the compiler cannot make any static assumptions about this quotation at all:" { $code @@ -51,24 +51,24 @@ ARTICLE: "inference-combinators" "Combinator stack effects" "However this fails to pass the stack checker since there is no guarantee the quotation has the right stack effect for " { $link map } ". It can be wrapped in a new quotation with a declaration:" { $code ": perform ( values action -- results )" " quot>> [ call( value -- result ) ] curry map ;" } { $heading "Explanation" } -"This restriction exists because without further information, one cannot say what the stack effect of " { $link call } " is; it depends on the given quotation. If the stack checker encounters a " { $link call } " without further information, a " { $link literal-expected } " error is raised." +"This restriction exists because without further information, one cannot say what the stack effect of " { $link call } " is; it depends on the given quotation. If the stack checker encounters a " { $link call } " without further information, a " { $link unknown-macro-input } " or " { $link bad-macro-input } " error is raised." $nl "On the other hand, the stack effect of applying " { $link call } " to a literal quotation or a " { $link curry } " of a literal quotation is easy to compute; it behaves as if the quotation was substituted at that point." { $heading "Limitations" } "The stack checker cannot guarantee that a literal quotation is still literal if it is passed on the data stack to an inlined recursive combinator such as " { $link each } " or " { $link map } ". For example, the following will not infer:" { $example - "[ [ reverse ] swap [ reverse ] map swap call ] infer." "Got a computed value where a literal quotation was expected" + "[ [ reverse ] swap [ reverse ] map swap call ] infer." "Cannot apply “call†to a run-time computed value\nmacro call" } "To make this work, use " { $link dip } " to pass the quotation instead:" { $example - "[ [ reverse ] [ [ reverse ] map ] dip call ] infer." "( object -- object )" + "[ [ reverse ] [ [ reverse ] map ] dip call ] infer." "( x -- x )" } ; ARTICLE: "inference-branches" "Branch stack effects" "Conditionals such as " { $link if } " and combinators built on top have the same restrictions as " { $link POSTPONE: inline } " combinators (see " { $link "inference-combinators" } ") with the additional requirement that all branches leave the stack at the same height. If this is not the case, the stack checker throws a " { $link unbalanced-branches-error } "." $nl "If all branches leave the stack at the same height, then the stack effect of the conditional is just the maximum of the stack effect of each branch. For example," -{ $example "[ [ + ] [ drop ] if ] infer." "( object object object -- object )" } +{ $example "[ [ + ] [ drop ] if ] infer." "( x x x -- x )" } "The call to " { $link if } " takes one value from the stack, a generalized boolean. The first branch " { $snippet "[ + ]" } " has stack effect " { $snippet "( x x -- x )" } " and the second has stack effect " { $snippet "( x -- )" } ". Since both branches decrease the height of the stack by one, we say that the stack effect of the two branches is " { $snippet "( x x -- x )" } ", and together with the boolean popped off the stack by " { $link if } ", this gives a total stack effect of " { $snippet "( x x x -- x )" } "." ; ARTICLE: "inference-recursive-combinators" "Recursive combinator stack effects" @@ -77,7 +77,7 @@ $nl "Combinators which are recursive require additional care. In addition to being declared " { $link POSTPONE: inline } ", they must be declared " { $link POSTPONE: recursive } ". There are three restrictions that only apply to combinators with this declaration:" { $heading "Input quotation declaration" } "Input parameters which are quotations must be annotated as much in the stack effect. For example, the following will not infer:" -{ $example ": bad ( quot -- ) [ call ] keep bad ; inline recursive" "[ [ ] bad ] infer." "Got a computed value where a literal quotation was expected" } +{ $unchecked-example ": bad ( quot -- ) [ call ] keep bad ; inline recursive" "[ [ ] bad ] infer." "Cannot apply “call†to a run-time computed value\nmacro call" } "The following is correct:" { $example ": good ( quot: ( -- ) -- ) [ call ] keep good ; inline recursive" "[ [ ] good ] infer." "( -- )" } "The effect of the nested quotation itself is only present for documentation purposes; the mere presence of a nested effect is sufficient to mark that value as a quotation parameter." @@ -85,9 +85,9 @@ $nl "The stack checker does not trace data flow in two instances." $nl "An inline recursive word cannot pass a quotation on the data stack through the recursive call. For example, the following will not infer:" -{ $example ": bad ( ? quot: ( ? -- ) -- ) 2dup [ not ] dip bad call ; inline recursive" "[ [ drop ] bad ] infer." "Got a computed value where a literal quotation was expected" } +{ $unchecked-example ": bad ( ? quot: ( ? -- ) -- ) 2dup [ not ] dip bad call ; inline recursive" "[ [ drop ] bad ] infer." "Cannot apply “call†to a run-time computed value\nmacro call" } "However a small change can be made:" -{ $example ": good ( ? quot: ( ? -- ) -- ) [ good ] 2keep [ not ] dip call ; inline recursive" "[ [ drop ] good ] infer." "( object -- )" } +{ $example ": good ( ? quot: ( ? -- ) -- ) [ good ] 2keep [ not ] dip call ; inline recursive" "[ [ drop ] good ] infer." "( x -- )" } "An inline recursive word must have a fixed stack effect in its base case. The following will not infer:" { $code ": foo ( quot ? -- ) [ f foo ] [ call ] if ; inline" diff --git a/basis/stack-checker/stack-checker-tests.factor b/basis/stack-checker/stack-checker-tests.factor index 414bcaaffe..270e5695b3 100644 --- a/basis/stack-checker/stack-checker-tests.factor +++ b/basis/stack-checker/stack-checker-tests.factor @@ -7,7 +7,7 @@ sorting assocs definitions prettyprint io inspector classes.tuple classes.union classes.predicate debugger threads.private io.streams.string io.timeouts io.thread sequences.private destructors combinators eval locals.backend -system compiler.units shuffle ; +system compiler.units shuffle vocabs ; IN: stack-checker.tests [ 1234 infer ] must-fail @@ -16,14 +16,18 @@ IN: stack-checker.tests { 1 2 } [ dup ] must-infer-as { 1 2 } [ [ dup ] call ] must-infer-as -[ [ call ] infer ] must-fail +[ [ call ] infer ] [ T{ unknown-macro-input f call } = ] must-fail-with +[ [ curry call ] infer ] [ T{ unknown-macro-input f call } = ] must-fail-with +[ [ { } >quotation call ] infer ] [ T{ bad-macro-input f call } = ] must-fail-with +[ [ append curry call ] infer ] [ T{ bad-macro-input f call } = ] must-fail-with { 2 4 } [ 2dup ] must-infer-as { 1 0 } [ [ ] [ ] if ] must-infer-as -[ [ if ] infer ] must-fail -[ [ [ ] if ] infer ] must-fail -[ [ [ 2 ] [ ] if ] infer ] must-fail +[ [ if ] infer ] [ T{ unknown-macro-input f if } = ] must-fail-with +[ [ { } >quotation { } >quotation if ] infer ] [ T{ bad-macro-input f if } = ] must-fail-with +[ [ [ ] if ] infer ] [ T{ unknown-macro-input f if } = ] must-fail-with +[ [ [ 2 ] [ ] if ] infer ] [ unbalanced-branches-error? ] must-fail-with { 4 3 } [ [ rot ] [ -rot ] if ] must-infer-as { 4 3 } [ @@ -46,7 +50,7 @@ IN: stack-checker.tests [ [ [ [ 2 2 fixnum+ ] ] [ [ 2 2 fixnum* ] ] if call ] infer -] must-fail +] [ T{ bad-macro-input f call } = ] must-fail-with ! Test inference of termination of control flow : termination-test-1 ( -- * ) "foo" throw ; @@ -198,42 +202,42 @@ DEFER: blah4 ! This used to hang [ [ [ dup call ] dup call ] infer ] -[ inference-error? ] must-fail-with +[ recursive-quotation-error? ] must-fail-with : m ( q -- ) dup call ; inline -[ [ [ m ] m ] infer ] [ inference-error? ] must-fail-with +[ [ [ m ] m ] infer ] [ recursive-quotation-error? ] must-fail-with : m' ( quot -- ) dup curry call ; inline -[ [ [ m' ] m' ] infer ] [ inference-error? ] must-fail-with +[ [ [ m' ] m' ] infer ] [ recursive-quotation-error? ] must-fail-with : m'' ( -- q ) [ dup curry ] ; inline : m''' ( -- ) m'' call call ; inline -[ [ [ m''' ] m''' ] infer ] [ inference-error? ] must-fail-with +[ [ [ m''' ] m''' ] infer ] [ recursive-quotation-error? ] must-fail-with -: m-if ( a b c -- ) t over if ; inline +: m-if ( a b c -- ) t over when ; inline -[ [ [ m-if ] m-if ] infer ] [ inference-error? ] must-fail-with +[ [ [ m-if ] m-if ] infer ] [ recursive-quotation-error? ] must-fail-with ! This doesn't hang but it's also an example of the ! undedicable case [ [ [ [ drop 3 ] swap call ] dup call ] infer ] -[ inference-error? ] must-fail-with +[ recursive-quotation-error? ] must-fail-with -[ [ 1 drop-locals ] infer ] [ inference-error? ] must-fail-with +[ [ 1 drop-locals ] infer ] [ too-many-r>? ] must-fail-with ! Regression -[ [ cleave ] infer ] [ inference-error? ] must-fail-with +[ [ cleave ] infer ] [ T{ unknown-macro-input f cleave } = ] must-fail-with ! Test some curry stuff { 1 1 } [ 3 [ ] curry 4 [ ] curry if ] must-infer-as { 2 1 } [ [ ] curry 4 [ ] curry if ] must-infer-as -[ [ 3 [ ] curry 1 2 [ ] 2curry if ] infer ] must-fail +[ [ 3 [ ] curry 1 2 [ ] 2curry if ] infer ] [ unbalanced-branches-error? ] must-fail-with { 1 3 } [ [ 2drop f ] assoc-find ] must-infer-as @@ -285,26 +289,26 @@ DEFER: an-inline-word ERROR: custom-error ; -[ T{ effect f 0 0 t } ] [ +[ T{ effect f { } { } t } ] [ [ custom-error ] infer ] unit-test : funny-throw ( a -- * ) throw ; inline -[ T{ effect f 0 0 t } ] [ +[ T{ effect f { } { } t } ] [ [ 3 funny-throw ] infer ] unit-test -[ T{ effect f 0 0 t } ] [ +[ T{ effect f { } { } t } ] [ [ custom-error inference-error ] infer ] unit-test -[ T{ effect f 1 2 t } ] [ +[ T{ effect f { "x" } { "x" "x" } t } ] [ [ dup [ 3 throw ] dip ] infer ] unit-test ! Regression -[ [ 1 load-locals ] infer ] must-fail +[ [ 1 load-locals ] infer ] [ too-many->r? ] must-fail-with ! Corner case [ [ [ f dup ] [ dup ] produce ] infer ] must-fail @@ -319,7 +323,7 @@ FORGET: erg's-inference-bug [ [ bad-recursion-3 ] infer ] must-fail FORGET: bad-recursion-3 -: bad-recursion-4 ( -- ) 4 [ dup call roll ] times ; inline recursive +: bad-recursion-4 ( -- ) 4 [ dup call [ rot ] dip swap ] times ; inline recursive [ [ [ ] [ 1 2 3 ] over dup bad-recursion-4 ] infer ] must-fail : bad-recursion-5 ( obj quot: ( -- ) -- ) dup call swap bad-recursion-5 ; inline recursive @@ -329,6 +333,8 @@ FORGET: bad-recursion-3 dup bad-recursion-6 call ; inline recursive [ [ [ drop f ] bad-recursion-6 ] infer ] must-fail +[ ] [ [ \ bad-recursion-6 forget ] with-compilation-unit ] unit-test + { 3 0 } [ [ 2drop "A" throw ] [ ] if 2drop ] must-infer-as { 2 0 } [ drop f f [ 2drop "A" throw ] [ ] if 2drop ] must-infer-as @@ -346,6 +352,9 @@ DEFER: eee' [ [ eee' ] infer ] [ inference-error? ] must-fail-with +[ ] [ [ \ ddd' forget ] with-compilation-unit ] unit-test +[ ] [ [ \ eee' forget ] with-compilation-unit ] unit-test + : bogus-error ( x -- ) dup "A" throw [ bogus-error ] [ drop ] if ; inline recursive @@ -367,9 +376,9 @@ DEFER: eee' [ ] [ [ \ forget-test forget ] with-compilation-unit ] unit-test [ forget-test ] must-infer -[ [ cond ] infer ] must-fail -[ [ bi ] infer ] must-fail -[ at ] must-infer +[ [ cond ] infer ] [ T{ unknown-macro-input f cond } = ] must-fail-with +[ [ bi ] infer ] [ T{ unknown-macro-input f call } = ] must-fail-with +[ [ each ] infer ] [ T{ unknown-macro-input f call } = ] must-fail-with [ [ [ "OOPS" throw ] dip ] [ drop ] if ] must-infer @@ -380,5 +389,16 @@ DEFER: eee' { 3 1 } [ call( a b -- c ) ] must-infer-as { 3 1 } [ execute( a b -- c ) ] must-infer-as -[ [ call-effect ] infer ] must-fail -[ [ execute-effect ] infer ] must-fail +[ [ call-effect ] infer ] [ T{ unknown-macro-input f call-effect } = ] must-fail-with +[ [ execute-effect ] infer ] [ T{ unknown-macro-input f execute-effect } = ] must-fail-with + +[ \ set-datastack def>> infer ] [ T{ do-not-compile f do-primitive } = ] must-fail-with +[ ] [ [ \ set-datastack def>> infer ] try ] unit-test + +! Make sure all primitives are covered +[ { } ] [ + all-words [ primitive? ] filter + [ "default-output-classes" word-prop not ] filter + [ "special" word-prop not ] filter + [ "shuffle" word-prop not ] filter +] unit-test diff --git a/basis/stack-checker/stack-checker.factor b/basis/stack-checker/stack-checker.factor index fe52357f9e..12e8660900 100644 --- a/basis/stack-checker/stack-checker.factor +++ b/basis/stack-checker/stack-checker.factor @@ -1,7 +1,8 @@ -! Copyright (C) 2004, 2009 Slava Pestov. +! Copyright (C) 2004, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel io effects namespaces sequences quotations vocabs -vocabs.loader generic words stack-checker.backend stack-checker.state +USING: accessors kernel io effects namespaces sequences +quotations vocabs vocabs.loader generic words +stack-checker.backend stack-checker.state stack-checker.known-words stack-checker.transforms stack-checker.errors stack-checker.inlining stack-checker.visitor.dummy ; @@ -15,3 +16,7 @@ M: callable infer ( quot -- effect ) : infer. ( quot -- ) #! Safe to call from inference transforms. infer effect>string print ; + +: inputs ( quot -- n ) infer in>> length ; + +: outputs ( quot -- n ) infer out>> length ; diff --git a/basis/stack-checker/state/state.factor b/basis/stack-checker/state/state.factor index a76d302a7e..f0b595ebe5 100644 --- a/basis/stack-checker/state/state.factor +++ b/basis/stack-checker/state/state.factor @@ -1,15 +1,16 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: assocs arrays namespaces sequences kernel definitions math effects accessors words fry classes.algebra -compiler.units stack-checker.values stack-checker.visitor ; +compiler.units stack-checker.values stack-checker.visitor +stack-checker.errors ; IN: stack-checker.state ! Did the current control-flow path throw an error? SYMBOL: terminated? ! Number of inputs current word expects from the stack -SYMBOL: d-in +SYMBOL: input-count DEFER: commit-literals @@ -34,33 +35,15 @@ SYMBOL: literals [ [ (push-literal) ] each ] [ delete-all ] bi ] unless-empty ; -: current-stack-height ( -- n ) meta-d length d-in get - ; +: current-stack-height ( -- n ) meta-d length input-count get - ; : current-effect ( -- effect ) - d-in get meta-d length terminated? get effect boa ; + input-count get "x" + meta-d length "x" + terminated? get effect boa ; : init-inference ( -- ) terminated? off V{ } clone \ meta-d set V{ } clone literals set - 0 d-in set ; - -! Words that the current quotation depends on -SYMBOL: dependencies - -: depends-on ( word how -- ) - over primitive? [ 2drop ] [ - dependencies get dup [ - swap '[ _ strongest-dependency ] change-at - ] [ 3drop ] if - ] if ; - -! Generic words that the current quotation depends on -SYMBOL: generic-dependencies - -: ?class-or ( class/f class -- class' ) - swap [ class-or ] when* ; - -: depends-on-generic ( generic class -- ) - generic-dependencies get dup - [ swap '[ _ ?class-or ] change-at ] [ 3drop ] if ; + 0 input-count set ; diff --git a/basis/stack-checker/transforms/transforms-tests.factor b/basis/stack-checker/transforms/transforms-tests.factor index 843083bd52..bbe3cb2ed9 100644 --- a/basis/stack-checker/transforms/transforms-tests.factor +++ b/basis/stack-checker/transforms/transforms-tests.factor @@ -1,15 +1,9 @@ IN: stack-checker.transforms.tests USING: sequences stack-checker.transforms tools.test math kernel -quotations stack-checker stack-checker.errors accessors combinators words arrays -classes classes.tuple ; +quotations stack-checker stack-checker.errors accessors +combinators words arrays classes classes.tuple macros ; -: compose-n ( quot n -- ) "OOPS" throw ; - -<< -: compose-n-quot ( n word -- quot' ) >quotation ; -\ compose-n [ compose-n-quot ] 2 define-transform -\ compose-n t "no-compile" set-word-prop ->> +MACRO: compose-n ( n word -- quot' ) >quotation ; : compose-n-test ( a b c -- x ) 2 \ + compose-n ; @@ -64,14 +58,16 @@ DEFER: smart-combo ( quot -- ) [ [ [ "a" "b" ] very-smart-combo "c" ] very-smart-combo ] must-infer ! Caveat found by Doug -DEFER: curry-folding-test ( quot -- ) - -\ curry-folding-test [ length \ drop >quotation ] 1 define-transform +MACRO: curry-folding-test ( quot -- ) + length \ drop >quotation ; { 3 0 } [ [ 1 2 3 ] curry-folding-test ] must-infer-as { 3 0 } [ 1 [ 2 3 ] curry curry-folding-test ] must-infer-as { 3 0 } [ [ 1 2 ] 3 [ ] curry compose curry-folding-test ] must-infer-as +[ [ curry curry-folding-test ] infer ] +[ T{ unknown-macro-input f curry-folding-test } = ] must-fail-with + : member?-test ( a -- ? ) { 1 2 3 10 7 58 } member? ; [ f ] [ 1.0 member?-test ] unit-test @@ -82,4 +78,8 @@ DEFER: curry-folding-test ( quot -- ) \ bad-macro [ "OOPS" throw ] 0 define-transform -[ [ bad-macro ] infer ] [ inference-error? ] must-fail-with \ No newline at end of file +[ [ bad-macro ] infer ] [ f >>continuation T{ transform-expansion-error f "OOPS" f bad-macro } = ] must-fail-with + +MACRO: two-params ( a b -- c ) + 1quotation ; + +[ [ 3 two-params ] infer ] [ T{ unknown-macro-input f two-params } = ] must-fail-with \ No newline at end of file diff --git a/basis/stack-checker/transforms/transforms.factor b/basis/stack-checker/transforms/transforms.factor old mode 100755 new mode 100644 index 11534c58f9..3fdf29b85e --- a/basis/stack-checker/transforms/transforms.factor +++ b/basis/stack-checker/transforms/transforms.factor @@ -7,40 +7,49 @@ classes.tuple.private effects summary hashtables classes sets definitions generic.standard slots.private continuations locals sequences.private generalizations stack-checker.backend stack-checker.state stack-checker.visitor stack-checker.errors -stack-checker.values stack-checker.recursive-state ; +stack-checker.values stack-checker.recursive-state +stack-checker.dependencies ; IN: stack-checker.transforms -: call-transformer ( word stack quot -- newquot ) - '[ _ _ with-datastack [ length 1 assert= ] [ first ] bi nip ] - [ transform-expansion-error ] +: call-transformer ( stack quot -- newquot ) + '[ _ _ with-datastack [ length 1 assert= ] [ first ] bi ] + [ error-continuation get current-word get transform-expansion-error ] recover ; -:: ((apply-transform)) ( word quot values stack rstate -- ) - rstate recursive-state - [ word stack quot call-transformer ] with-variable - [ - values [ length meta-d shorten-by ] [ #drop, ] bi - rstate infer-quot - ] [ word infer-word ] if* ; +:: ((apply-transform)) ( quot values stack rstate -- ) + rstate recursive-state [ stack quot call-transformer ] with-variable + values [ length meta-d shorten-by ] [ #drop, ] bi + rstate infer-quot ; -: literals? ( values -- ? ) [ literal-value? ] all? ; +: literal-values? ( values -- ? ) [ literal-value? ] all? ; -: (apply-transform) ( word quot n -- ) - ensure-d dup literals? [ - dup empty? [ dup recursive-state get ] [ - [ ] - [ [ literal value>> ] map ] - [ first literal recursion>> ] tri - ] if - ((apply-transform)) - ] [ 2drop infer-word ] if ; +: input-values? ( values -- ? ) + [ { [ literal-value? ] [ input-value? ] } 1|| ] all? ; + +: (apply-transform) ( quot n -- ) + ensure-d { + { [ dup literal-values? ] [ + dup empty? [ dup recursive-state get ] [ + [ ] + [ [ literal value>> ] map ] + [ first literal recursion>> ] tri + ] if + ((apply-transform)) + ] } + { [ dup input-values? ] [ drop current-word get unknown-macro-input ] } + [ drop current-word get bad-macro-input ] + } cond ; : apply-transform ( word -- ) - [ ] [ "transform-quot" word-prop ] [ "transform-n" word-prop ] tri + [ current-word set ] + [ "transform-quot" word-prop ] + [ "transform-n" word-prop ] tri (apply-transform) ; : apply-macro ( word -- ) - [ ] [ "macro" word-prop ] [ "declared-effect" word-prop in>> length ] tri + [ current-word set ] + [ "macro" word-prop ] + [ "declared-effect" word-prop in>> length ] tri (apply-transform) ; : define-transform ( word quot n -- ) diff --git a/basis/stack-checker/values/values.factor b/basis/stack-checker/values/values.factor index 19db441381..7e11ec3edb 100644 --- a/basis/stack-checker/values/values.factor +++ b/basis/stack-checker/values/values.factor @@ -1,7 +1,7 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors namespaces kernel assocs sequences -stack-checker.recursive-state ; +stack-checker.recursive-state stack-checker.errors ; IN: stack-checker.values ! Values @@ -28,21 +28,25 @@ SYMBOL: known-values GENERIC: (literal-value?) ( value -- ? ) -M: object (literal-value?) drop f ; +: literal-value? ( value -- ? ) known (literal-value?) ; -GENERIC: (literal) ( value -- literal ) +GENERIC: (input-value?) ( value -- ? ) + +: input-value? ( value -- ? ) known (input-value?) ; + +GENERIC: (literal) ( known -- literal ) ! Literal value -TUPLE: literal < identity-tuple value recursion hashcode ; +TUPLE: literal < identity-tuple value recursion ; : literal ( value -- literal ) known (literal) ; -: literal-value? ( value -- ? ) known (literal-value?) ; - -M: literal hashcode* nip hashcode>> ; +M: literal hashcode* nip value>> identity-hashcode ; : ( obj -- value ) - recursive-state get over hashcode \ literal boa ; + recursive-state get \ literal boa ; + +M: literal (input-value?) drop f ; M: literal (literal-value?) drop t ; @@ -51,7 +55,7 @@ M: literal (literal) ; : curried/composed-literal ( input1 input2 quot -- literal ) [ [ literal ] bi@ ] dip [ [ [ value>> ] bi@ ] dip call ] [ drop nip recursion>> ] 3bi - over hashcode \ literal boa ; inline + \ literal boa ; inline ! Result of curry TUPLE: curried obj quot ; @@ -61,7 +65,10 @@ C: curried : >curried< ( curried -- obj quot ) [ obj>> ] [ quot>> ] bi ; inline +M: curried (input-value?) >curried< [ input-value? ] either? ; + M: curried (literal-value?) >curried< [ literal-value? ] both? ; + M: curried (literal) >curried< [ curry ] curried/composed-literal ; ! Result of compose @@ -72,5 +79,27 @@ C: composed : >composed< ( composed -- quot1 quot2 ) [ quot1>> ] [ quot2>> ] bi ; inline +M: composed (input-value?) + [ quot1>> input-value? ] [ quot2>> input-value? ] bi or ; + M: composed (literal-value?) >composed< [ literal-value? ] both? ; -M: composed (literal) >composed< [ compose ] curried/composed-literal ; \ No newline at end of file + +M: composed (literal) >composed< [ compose ] curried/composed-literal ; + +! Input parameters +SINGLETON: input-parameter + +SYMBOL: current-word + +M: input-parameter (input-value?) drop t ; + +M: input-parameter (literal-value?) drop f ; + +M: input-parameter (literal) current-word get unknown-macro-input ; + +! Computed values +M: f (input-value?) drop f ; + +M: f (literal-value?) drop f ; + +M: f (literal) current-word get bad-macro-input ; \ No newline at end of file diff --git a/basis/stack-checker/visitor/dummy/dummy.factor b/basis/stack-checker/visitor/dummy/dummy.factor index 5f05d97d1a..871f79d320 100644 --- a/basis/stack-checker/visitor/dummy/dummy.factor +++ b/basis/stack-checker/visitor/dummy/dummy.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: stack-checker.visitor kernel ; IN: stack-checker.visitor.dummy @@ -24,4 +24,5 @@ M: f #copy, 2drop ; M: f #drop, drop ; M: f #alien-invoke, drop ; M: f #alien-indirect, drop ; +M: f #alien-assembly, drop ; M: f #alien-callback, drop ; diff --git a/basis/stack-checker/visitor/visitor.factor b/basis/stack-checker/visitor/visitor.factor index 6093cd008a..d4207caf5b 100644 --- a/basis/stack-checker/visitor/visitor.factor +++ b/basis/stack-checker/visitor/visitor.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: kernel arrays namespaces ; IN: stack-checker.visitor @@ -29,4 +29,5 @@ HOOK: #recursive, stack-visitor ( label inputs visitor -- ) HOOK: #copy, stack-visitor ( inputs outputs -- ) HOOK: #alien-invoke, stack-visitor ( params -- ) HOOK: #alien-indirect, stack-visitor ( params -- ) +HOOK: #alien-assembly, stack-visitor ( params -- ) HOOK: #alien-callback, stack-visitor ( params -- ) diff --git a/basis/strings/tables/tables.factor b/basis/strings/tables/tables.factor index 51032264c7..19d0051d17 100644 --- a/basis/strings/tables/tables.factor +++ b/basis/strings/tables/tables.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2009 Slava Pestov. +! Copyright (C) 2009, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel sequences fry math.order splitting ; IN: strings.tables @@ -6,7 +6,7 @@ IN: strings.tables ] dip '[ 0 = @ ] 2map ; inline + [ dup length iota ] dip '[ 0 = @ ] 2map ; inline : max-length ( seq -- n ) [ length ] [ max ] map-reduce ; diff --git a/basis/suffix-arrays/suffix-arrays-docs.factor b/basis/suffix-arrays/suffix-arrays-docs.factor old mode 100755 new mode 100644 diff --git a/basis/suffix-arrays/suffix-arrays-tests.factor b/basis/suffix-arrays/suffix-arrays-tests.factor old mode 100755 new mode 100644 diff --git a/basis/suffix-arrays/suffix-arrays.factor b/basis/suffix-arrays/suffix-arrays.factor old mode 100755 new mode 100644 index 931cb36ea9..134c144fda --- a/basis/suffix-arrays/suffix-arrays.factor +++ b/basis/suffix-arrays/suffix-arrays.factor @@ -7,7 +7,7 @@ IN: suffix-arrays ( begin seq -- <=> ) [ <=> ] [ swap head? ] 2bi [ drop +eq+ ] when ; @@ -22,8 +22,7 @@ IN: suffix-arrays : ( from/f to/f seq -- slice ) [ - tuck - [ drop 0 or ] [ length or ] 2bi* + [ drop 0 or ] [ length or ] bi-curry bi* [ min ] keep ] keep ; inline diff --git a/basis/suffix-arrays/words/words.factor b/basis/suffix-arrays/words/words.factor old mode 100755 new mode 100644 diff --git a/basis/syndication/syndication.factor b/basis/syndication/syndication.factor old mode 100755 new mode 100644 diff --git a/basis/system-info/system-info.factor b/basis/system-info/system-info.factor old mode 100755 new mode 100644 diff --git a/basis/system-info/windows/ce/ce.factor b/basis/system-info/windows/ce/ce.factor old mode 100755 new mode 100644 diff --git a/basis/system-info/windows/nt/nt.factor b/basis/system-info/windows/nt/nt.factor old mode 100755 new mode 100644 diff --git a/basis/system-info/windows/windows.factor b/basis/system-info/windows/windows.factor old mode 100755 new mode 100644 diff --git a/basis/threads/threads-docs.factor b/basis/threads/threads-docs.factor index 8956051b25..995fc867e7 100644 --- a/basis/threads/threads-docs.factor +++ b/basis/threads/threads-docs.factor @@ -1,6 +1,6 @@ USING: help.markup help.syntax kernel kernel.private io threads.private continuations init quotations strings -assocs heaps boxes namespaces deques dlists ; +assocs heaps boxes namespaces deques dlists system ; IN: threads ARTICLE: "threads-start/stop" "Starting and stopping threads" @@ -16,7 +16,7 @@ ARTICLE: "threads-start/stop" "Starting and stopping threads" } "Threads stop either when the quotation given to " { $link spawn } " returns, or when the following word is called:" { $subsections stop } -"If the image is saved and started again, all runnable threads are stopped. Vocabularies wishing to have a background thread always running should use " { $link add-init-hook } "." ; +"If the image is saved and started again, all runnable threads are stopped. Vocabularies wishing to have a background thread always running should use " { $link add-startup-hook } "." ; ARTICLE: "threads-yield" "Yielding and suspending threads" "Yielding to other threads:" @@ -113,8 +113,8 @@ HELP: sleep-queue { $var-description "A " { $link min-heap } " storing the queue of sleeping threads." } ; HELP: sleep-time -{ $values { "us/f" "a non-negative integer or " { $link f } } } -{ $description "Outputs the time until the next sleeping thread is scheduled to wake up, which could be zero if there are threads in the run queue, or threads which need to wake up right now. If there are no runnable or sleeping threads, outputs " { $link f } "." } ; +{ $values { "nanos/f" "a non-negative integer or " { $link f } } } +{ $description "Returns the time until the next sleeping thread is scheduled to wake up, which could be zero if there are threads in the run queue, or threads which need to wake up right now. If there are no runnable or sleeping threads, returns " { $link f } "." } ; HELP: stop { $description "Stops the current thread. The thread may be started again from another thread using " { $link (spawn) } "." } ; @@ -123,8 +123,8 @@ HELP: yield { $description "Adds the current thread to the end of the run queue, and switches to the next runnable thread." } ; HELP: sleep-until -{ $values { "time/f" "a non-negative integer or " { $link f } } } -{ $description "Suspends the current thread until the given time, or indefinitely if a value of " { $link f } " is passed in." +{ $values { "n/f" "a non-negative integer or " { $link f } } } +{ $description "Suspends the current thread until the given nanosecond count, returned by " { $link nano-count } ", is reached, or indefinitely if a value of " { $link f } " is passed in." $nl "Other threads may interrupt the sleep by calling " { $link interrupt } "." } ; diff --git a/basis/threads/threads-tests.factor b/basis/threads/threads-tests.factor index 79aad20b85..4568b7c491 100644 --- a/basis/threads/threads-tests.factor +++ b/basis/threads/threads-tests.factor @@ -1,6 +1,6 @@ USING: namespaces io tools.test threads kernel concurrency.combinators concurrency.promises locals math -words ; +words calendar sequences ; IN: threads.tests 3 "x" set @@ -20,7 +20,7 @@ yield [ f ] [ f get-global ] unit-test { { 0 3 6 9 12 15 18 21 24 27 } } [ - 10 [ + 10 iota [ 0 "i" tset [ "i" [ yield 3 + ] tchange @@ -42,3 +42,5 @@ yield [ t ] [ spawn-namespace-test ] unit-test [ "a" [ 1 1 + ] spawn 100 sleep ] must-fail + +[ ] [ 0.1 seconds sleep ] unit-test diff --git a/basis/threads/threads.factor b/basis/threads/threads.factor index dec44625f7..952652d801 100644 --- a/basis/threads/threads.factor +++ b/basis/threads/threads.factor @@ -21,7 +21,7 @@ mailbox variables sleep-entry ; -: self ( -- thread ) 63 getenv ; inline +: self ( -- thread ) 63 special-object ; inline ! Thread-local storage : tnamespace ( -- assoc ) @@ -36,7 +36,7 @@ sleep-entry ; : tchange ( key quot -- ) tnamespace swap change-at ; inline -: threads ( -- assoc ) 64 getenv ; +: threads ( -- assoc ) 64 special-object ; : thread ( id -- thread ) threads at ; @@ -61,7 +61,7 @@ ERROR: not-running thread ; : unregister-thread ( thread -- ) check-registered id>> threads delete-at ; -: set-self ( thread -- ) 63 setenv ; inline +: set-self ( thread -- ) 63 set-special-object ; inline PRIVATE> @@ -75,9 +75,9 @@ PRIVATE> : ( quot name -- thread ) \ thread new-thread ; -: run-queue ( -- dlist ) 65 getenv ; +: run-queue ( -- dlist ) 65 special-object ; -: sleep-queue ( -- heap ) 66 getenv ; +: sleep-queue ( -- heap ) 66 special-object ; : resume ( thread -- ) f >>state @@ -91,11 +91,11 @@ PRIVATE> f >>state check-registered 2array run-queue push-front ; -: sleep-time ( -- us/f ) +: sleep-time ( -- nanos/f ) { { [ run-queue deque-empty? not ] [ 0 ] } { [ sleep-queue heap-empty? ] [ f ] } - [ sleep-queue heap-peek nip micros [-] ] + [ sleep-queue heap-peek nip nano-count [-] ] } cond ; DEFER: stop @@ -108,7 +108,7 @@ DEFER: stop : expire-sleep? ( heap -- ? ) dup heap-empty? - [ drop f ] [ heap-peek nip micros <= ] if ; + [ drop f ] [ heap-peek nip nano-count <= ] if ; : expire-sleep ( thread -- ) f >>sleep-entry resume ; @@ -140,7 +140,11 @@ DEFER: next ! ! And if sleep-time outputs f, there are no sleeping ! threads either... so WTF. - sleep-time [ die 0 ] unless* (sleep) next ; + sleep-time { + { [ dup not ] [ drop die ] } + { [ dup 0 = ] [ drop ] } + [ (sleep) ] + } cond next ; : (next) ( arg thread -- * ) f >>state @@ -173,7 +177,7 @@ PRIVATE> : yield ( -- ) [ resume ] f suspend drop ; -GENERIC: sleep-until ( time/f -- ) +GENERIC: sleep-until ( n/f -- ) M: integer sleep-until '[ _ schedule-sleep ] "sleep" suspend drop ; @@ -184,7 +188,7 @@ M: f sleep-until GENERIC: sleep ( dt -- ) M: real sleep - micros + >integer sleep-until ; + >integer nano-count + sleep-until ; : interrupt ( thread -- ) dup state>> [ @@ -212,9 +216,9 @@ GENERIC: error-in-thread ( error thread -- ) 65 setenv - 66 setenv + H{ } clone 64 set-special-object + 65 set-special-object + 66 set-special-object initial-thread global [ drop [ ] "Initial" ] cache >>continuation @@ -225,4 +229,4 @@ GENERIC: error-in-thread ( error thread -- ) PRIVATE> -[ init-threads ] "threads" add-init-hook +[ init-threads ] "threads" add-startup-hook diff --git a/basis/tools/annotations/annotations-tests.factor b/basis/tools/annotations/annotations-tests.factor index c21e9e0c60..dcfc6ae522 100644 --- a/basis/tools/annotations/annotations-tests.factor +++ b/basis/tools/annotations/annotations-tests.factor @@ -1,5 +1,5 @@ USING: tools.test tools.annotations tools.time math parser eval -io.streams.string kernel strings ; +io.streams.string kernel strings sequences memory ; IN: tools.annotations.tests : foo ( -- ) ; @@ -60,3 +60,10 @@ M: object my-generic ; f my-generic drop ; [ ] [ some-code ] unit-test + +! Make sure annotations work on primitives +\ gc watch + +[ f ] [ [ gc ] with-string-writer empty? ] unit-test + +\ gc reset diff --git a/basis/tools/crossref/crossref-tests.factor b/basis/tools/crossref/crossref-tests.factor old mode 100755 new mode 100644 diff --git a/basis/tools/crossref/crossref.factor b/basis/tools/crossref/crossref.factor index 90fe7e8e9d..134395f1a8 100644 --- a/basis/tools/crossref/crossref.factor +++ b/basis/tools/crossref/crossref.factor @@ -135,6 +135,6 @@ SINGLETON: invalidate-crossref M: invalidate-crossref definitions-changed 2drop crossref global delete-at ; -[ invalidate-crossref add-definition-observer ] "tools.crossref" add-init-hook +[ invalidate-crossref add-definition-observer ] "tools.crossref" add-startup-hook PRIVATE> diff --git a/basis/tools/deploy/backend/backend.factor b/basis/tools/deploy/backend/backend.factor old mode 100755 new mode 100644 index bd58c7505b..fe8049e9e3 --- a/basis/tools/deploy/backend/backend.factor +++ b/basis/tools/deploy/backend/backend.factor @@ -71,6 +71,7 @@ DEFER: ?make-staging-image "-output-image=" over staging-image-name append , "-include=" swap " " join append , "-no-user-init" , + "-pic=0" , ] { } make ; : run-factor ( vm flags -- ) @@ -99,6 +100,7 @@ DEFER: ?make-staging-image [ "-deploy-vocab=" prepend , ] [ make-deploy-config "-deploy-config=" prepend , ] bi "-output-image=" prepend , + "-pic=0" , ] { } make ] bind ; diff --git a/basis/tools/deploy/deploy-tests.factor b/basis/tools/deploy/deploy-tests.factor index 784b034665..1412e65f95 100644 --- a/basis/tools/deploy/deploy-tests.factor +++ b/basis/tools/deploy/deploy-tests.factor @@ -5,32 +5,32 @@ io.launcher arrays namespaces continuations layouts accessors urls math.parser io.directories tools.deploy.test ; IN: tools.deploy.tests -[ t ] [ "hello-world" shake-and-bake 500000 small-enough? ] unit-test +[ ] [ "hello-world" shake-and-bake 500000 small-enough? ] unit-test -[ t ] [ "sudoku" shake-and-bake 800000 small-enough? ] unit-test +[ ] [ "sudoku" shake-and-bake 800000 small-enough? ] unit-test -[ t ] [ "hello-ui" shake-and-bake 1300000 small-enough? ] unit-test +[ ] [ "hello-ui" shake-and-bake 1300000 small-enough? ] unit-test [ "staging.math-threads-compiler-ui.image" ] [ "hello-ui" deploy-config [ bootstrap-profile staging-image-name file-name ] bind ] unit-test -[ t ] [ "maze" shake-and-bake 1200000 small-enough? ] unit-test +[ ] [ "maze" shake-and-bake 1200000 small-enough? ] unit-test -[ t ] [ "tetris" shake-and-bake 1500000 small-enough? ] unit-test +[ ] [ "tetris" shake-and-bake 1500000 small-enough? ] unit-test -[ t ] [ "spheres" shake-and-bake 1500000 small-enough? ] unit-test +[ ] [ "spheres" shake-and-bake 1500000 small-enough? ] unit-test -[ t ] [ "terrain" shake-and-bake 1700000 small-enough? ] unit-test +[ ] [ "terrain" shake-and-bake 1700000 small-enough? ] unit-test -[ t ] [ "bunny" shake-and-bake 2500000 small-enough? ] unit-test +[ ] [ "bunny" shake-and-bake 2500000 small-enough? ] unit-test os macosx? [ - [ t ] [ "webkit-demo" shake-and-bake 500000 small-enough? ] unit-test + [ ] [ "webkit-demo" shake-and-bake 500000 small-enough? ] unit-test ] when -[ t ] [ "benchmark.regex-dna" shake-and-bake 900000 small-enough? ] unit-test +[ ] [ "benchmark.regex-dna" shake-and-bake 900000 small-enough? ] unit-test { "tools.deploy.test.1" @@ -115,3 +115,5 @@ os macosx? [ ] unit-test [ ] [ "tools.deploy.test.16" shake-and-bake run-temp-image ] unit-test + +[ ] [ "tools.deploy.test.17" shake-and-bake run-temp-image ] unit-test diff --git a/basis/tools/deploy/macosx/macosx.factor b/basis/tools/deploy/macosx/macosx.factor old mode 100755 new mode 100644 diff --git a/basis/tools/deploy/shaker/shaker.factor b/basis/tools/deploy/shaker/shaker.factor old mode 100755 new mode 100644 index e42f478de6..06009992ad --- a/basis/tools/deploy/shaker/shaker.factor +++ b/basis/tools/deploy/shaker/shaker.factor @@ -9,6 +9,7 @@ compiler.units definitions generic generic.standard generic.single tools.deploy.config combinators classes classes.builtin slots.private grouping command-line ; QUALIFIED: bootstrap.stage2 +QUALIFIED: compiler.crossref QUALIFIED: compiler.errors QUALIFIED: continuations QUALIFIED: definitions @@ -23,28 +24,27 @@ IN: tools.deploy.shaker : add-command-line-hook ( -- ) [ (command-line) command-line set-global ] "command-line" - init-hooks get set-at ; + startup-hooks get set-at ; -: strip-init-hooks ( -- ) +: strip-startup-hooks ( -- ) "Stripping startup hooks" show { "alien.strings" "cpu.x86" - "destructors" "environment" "libc" } - [ init-hooks get delete-at ] each + [ startup-hooks get delete-at ] each deploy-threads? get [ - "threads" init-hooks get delete-at + "threads" startup-hooks get delete-at ] unless native-io? [ - "io.thread" init-hooks get delete-at + "io.thread" startup-hooks get delete-at ] unless strip-io? [ - "io.files" init-hooks get delete-at - "io.backend" init-hooks get delete-at - "io.thread" init-hooks get delete-at + "io.files" startup-hooks get delete-at + "io.backend" startup-hooks get delete-at + "io.thread" startup-hooks get delete-at ] when strip-dictionary? [ { @@ -52,7 +52,7 @@ IN: tools.deploy.shaker "vocabs" "vocabs.cache" "source-files.errors" - } [ init-hooks get delete-at ] each + } [ startup-hooks get delete-at ] each ] when ; : strip-debugger ( -- ) @@ -180,7 +180,6 @@ IN: tools.deploy.shaker "slots" "special" "specializer" - "specializations" "struct-slots" ! UI needs this ! "superclass" @@ -293,7 +292,7 @@ IN: tools.deploy.shaker continuations:error-continuation continuations:error-thread continuations:restarts - init:init-hooks + init:startup-hooks source-files:source-files input-stream output-stream @@ -340,8 +339,8 @@ IN: tools.deploy.shaker implementors-map update-map main-vocab-hook - compiled-crossref - compiled-generic-crossref + compiler.crossref:compiled-crossref + compiler.crossref:compiled-generic-crossref compiler-impl compiler.errors:compiler-errors lexer-factory @@ -394,7 +393,7 @@ IN: tools.deploy.shaker '[ drop _ member? not ] assoc-filter [ drop string? not ] assoc-filter ! strip CLI args sift-assoc - 21 setenv + 21 set-special-object ] [ drop ] if ; : strip-c-io ( -- ) @@ -445,10 +444,10 @@ SYMBOL: deploy-vocab : [print-error] ( -- word ) "print-error" "debugger" lookup ; -: deploy-boot-quot ( word -- ) +: deploy-startup-quot ( word -- ) [ [ boot ] % - init-hooks get values concat % + startup-hooks get values concat % strip-debugger? [ , ] [ ! Don't reference 'try' directly since we don't want ! to pull in the debugger and prettyprinter into every @@ -465,9 +464,9 @@ SYMBOL: deploy-vocab strip-io? [ [ flush ] % ] unless [ 0 exit ] % ] [ ] make - set-boot-quot ; + set-startup-quot ; -: init-stripper ( -- ) +: startup-stripper ( -- ) t "quiet" set-global f output-stream set-global ; @@ -506,7 +505,7 @@ SYMBOL: deploy-vocab [ clear-megamorphic-cache ] each ; : strip ( -- ) - init-stripper + startup-stripper strip-libc strip-destructors strip-call @@ -514,13 +513,13 @@ SYMBOL: deploy-vocab strip-debugger strip-specialized-arrays compute-next-methods - strip-init-hooks + strip-startup-hooks add-command-line-hook strip-c-io strip-default-methods strip-compiler-classes - f 5 setenv ! we can't use the Factor debugger or Factor I/O anymore - deploy-vocab get vocab-main deploy-boot-quot + f 5 set-special-object ! we can't use the Factor debugger or Factor I/O anymore + deploy-vocab get vocab-main deploy-startup-quot find-megamorphic-caches stripped-word-props stripped-globals strip-globals diff --git a/basis/tools/deploy/shaker/strip-cocoa.factor b/basis/tools/deploy/shaker/strip-cocoa.factor index 133308b732..7bb2f651dc 100644 --- a/basis/tools/deploy/shaker/strip-cocoa.factor +++ b/basis/tools/deploy/shaker/strip-cocoa.factor @@ -17,7 +17,7 @@ IN: cocoa.application : objc-error ( error -- ) die ; -[ [ die ] 19 setenv ] "cocoa.application" add-init-hook +[ [ die ] 19 set-special-object ] "cocoa.application" add-startup-hook H{ } clone \ pool [ global [ @@ -46,4 +46,4 @@ H{ } clone \ pool [ \ make-prepare-send reset-memoized \ reset-memoized -\ (send) def>> second clear-assoc \ No newline at end of file +\ (send) def>> second clear-assoc diff --git a/basis/tools/deploy/test/17/17.factor b/basis/tools/deploy/test/17/17.factor new file mode 100644 index 0000000000..a7cb0d25f2 --- /dev/null +++ b/basis/tools/deploy/test/17/17.factor @@ -0,0 +1,31 @@ +USING: accessors calendar db db.sqlite db.tuples db.types +io.files.temp kernel urls ; +IN: tools.deploy.test.17 + +TUPLE: person name birthday homepage occupation ; + +person "PEOPLE" { + { "name" "NAME" { VARCHAR 256 } +not-null+ +user-assigned-id+ } + { "birthday" "BIRTHDAY" DATETIME +not-null+ } + { "homepage" "HOMEPAGE" URL +not-null+ } + { "occupation" "OCCUPATION" { VARCHAR 256 } +not-null+ } +} define-persistent + +: db-deploy-test ( -- ) + "test.db" temp-file [ + person recreate-table + + person new + "Stephen Hawking" >>name + timestamp new 8 >>day 0 >>month 1942 >>year >>birthday + "http://en.wikipedia.org/wiki/Stephen_Hawking" >url >>homepage + "Dope MC" >>occupation + dup + insert-tuple + person new + "Stephen Hawking" >>name + select-tuple + assert= + ] with-db ; + +MAIN: db-deploy-test diff --git a/basis/tools/deploy/test/17/deploy.factor b/basis/tools/deploy/test/17/deploy.factor new file mode 100644 index 0000000000..62cc2cac7b --- /dev/null +++ b/basis/tools/deploy/test/17/deploy.factor @@ -0,0 +1,14 @@ +USING: tools.deploy.config ; +H{ + { deploy-name "tools.deploy.test.17" } + { deploy-ui? f } + { deploy-c-types? f } + { deploy-unicode? f } + { "stop-after-last-window?" t } + { deploy-io 3 } + { deploy-reflection 5 } + { deploy-word-props? f } + { deploy-math? t } + { deploy-threads? t } + { deploy-word-defs? f } +} diff --git a/basis/tools/deploy/test/4/4.factor b/basis/tools/deploy/test/4/4.factor index a9ee71131c..fb005d2a46 100644 --- a/basis/tools/deploy/test/4/4.factor +++ b/basis/tools/deploy/test/4/4.factor @@ -1,5 +1,5 @@ +USING: io.encodings.string kernel io.encodings.8-bit.latin7 ; IN: tools.deploy.test.4 -USING: io.encodings.8-bit io.encodings.string kernel ; : deploy-test-4 ( -- ) "xyzthg" \ latin7 encode drop ; diff --git a/basis/tools/deploy/test/5/deploy.factor b/basis/tools/deploy/test/5/deploy.factor index 3f9b7f1599..74f3a6942b 100644 --- a/basis/tools/deploy/test/5/deploy.factor +++ b/basis/tools/deploy/test/5/deploy.factor @@ -1,13 +1,14 @@ USING: tools.deploy.config ; H{ - { deploy-threads? t } - { deploy-c-types? f } - { deploy-ui? f } - { deploy-word-props? f } - { deploy-word-defs? f } - { deploy-math? t } - { deploy-io 3 } { deploy-name "tools.deploy.test.5" } - { deploy-reflection 1 } + { deploy-ui? f } + { deploy-c-types? f } + { deploy-unicode? f } { "stop-after-last-window?" t } + { deploy-io 3 } + { deploy-reflection 2 } + { deploy-word-props? f } + { deploy-math? t } + { deploy-threads? t } + { deploy-word-defs? f } } diff --git a/basis/tools/deploy/test/test.factor b/basis/tools/deploy/test/test.factor old mode 100755 new mode 100644 index c799ec615e..d8414baba7 --- a/basis/tools/deploy/test/test.factor +++ b/basis/tools/deploy/test/test.factor @@ -10,14 +10,16 @@ IN: tools.deploy.test dup deploy-config make-deploy-image ] with-directory ; -: small-enough? ( n -- ? ) +ERROR: image-too-big actual-size max-size ; + +: small-enough? ( n -- ) [ "test.image" temp-file file-info size>> ] [ cell 4 / * cpu ppc? [ 100000 + ] when os windows? [ 150000 + ] when ] bi* - <= ; + 2dup <= [ 2drop ] [ image-too-big ] if ; : deploy-test-command ( -- args ) os macosx? diff --git a/basis/tools/deploy/unix/unix.factor b/basis/tools/deploy/unix/unix.factor old mode 100755 new mode 100644 diff --git a/basis/tools/deploy/windows/windows.factor b/basis/tools/deploy/windows/windows.factor old mode 100755 new mode 100644 diff --git a/basis/tools/deprecation/deprecation.factor b/basis/tools/deprecation/deprecation.factor index 0ee60b06b5..8dbfda3011 100644 --- a/basis/tools/deprecation/deprecation.factor +++ b/basis/tools/deprecation/deprecation.factor @@ -73,6 +73,6 @@ M: deprecation-observer definitions-changed [ drop initialize-deprecation-notes ] if ; [ \ deprecation-observer add-definition-observer ] -"tools.deprecation" add-init-hook +"tools.deprecation" add-startup-hook initialize-deprecation-notes diff --git a/basis/tools/disassembler/disassembler.factor b/basis/tools/disassembler/disassembler.factor old mode 100755 new mode 100644 index 4aec909e88..c0b3c9a586 --- a/basis/tools/disassembler/disassembler.factor +++ b/basis/tools/disassembler/disassembler.factor @@ -7,12 +7,16 @@ IN: tools.disassembler GENERIC: disassemble ( obj -- ) +spaces "\t" "\s" ; +PRIVATE> + M: byte-array disassemble [ [ malloc-byte-array &free alien-address dup ] @@ -22,7 +26,7 @@ M: byte-array disassemble M: pair disassemble first2 disassemble* [ tabs>spaces print ] each ; -M: word disassemble word-xt 2array disassemble ; +M: word disassemble word-code 2array disassemble ; M: quotation disassemble [ dup infer define-temp ] with-compilation-unit disassemble ; diff --git a/basis/tools/disassembler/gdb/gdb.factor b/basis/tools/disassembler/gdb/gdb.factor old mode 100755 new mode 100644 index c4c724b696..dda666ce6a --- a/basis/tools/disassembler/gdb/gdb.factor +++ b/basis/tools/disassembler/gdb/gdb.factor @@ -1,9 +1,9 @@ -! Copyright (C) 2008 Slava Pestov, Jorge Acereda Macia. +! Copyright (C) 2008, 2010 Slava Pestov, Jorge Acereda Macia. ! See http://factorcode.org/license.txt for BSD license. USING: io.files io.files.temp io words alien kernel math.parser -alien.syntax io.launcher assocs arrays sequences -namespaces make system math io.encodings.ascii -accessors tools.disassembler ; +alien.syntax io.launcher assocs arrays sequences namespaces make +system math io.encodings.ascii accessors tools.disassembler +tools.disassembler.private ; IN: tools.disassembler.gdb SINGLETON: gdb-disassembler diff --git a/basis/tools/disassembler/udis/udis-tests.factor b/basis/tools/disassembler/udis/udis-tests.factor index 9ad3dbbcc2..df3ef41365 100644 --- a/basis/tools/disassembler/udis/udis-tests.factor +++ b/basis/tools/disassembler/udis/udis-tests.factor @@ -2,8 +2,8 @@ IN: tools.disassembler.udis.tests USING: tools.disassembler.udis tools.test alien.c-types system combinators kernel ; { - { [ os linux? cpu x86.64? and ] [ [ 656 ] [ "ud" heap-size ] unit-test ] } - { [ os macosx? cpu x86.32? and ] [ [ 592 ] [ "ud" heap-size ] unit-test ] } - { [ os macosx? cpu x86.64? and ] [ [ 656 ] [ "ud" heap-size ] unit-test ] } + { [ os linux? cpu x86.64? and ] [ [ 656 ] [ ud heap-size ] unit-test ] } + { [ os macosx? cpu x86.32? and ] [ [ 592 ] [ ud heap-size ] unit-test ] } + { [ os macosx? cpu x86.64? and ] [ [ 656 ] [ ud heap-size ] unit-test ] } [ ] } cond \ No newline at end of file diff --git a/basis/tools/disassembler/udis/udis.factor b/basis/tools/disassembler/udis/udis.factor old mode 100755 new mode 100644 index effb2d6f0e..82c47a5c84 --- a/basis/tools/disassembler/udis/udis.factor +++ b/basis/tools/disassembler/udis/udis.factor @@ -1,11 +1,11 @@ -! Copyright (C) 2008 Slava Pestov, Jorge Acereda Macia. +! Copyright (C) 2008, 2010 Slava Pestov, Jorge Acereda Macia. ! See http://factorcode.org/license.txt for BSD license. USING: tools.disassembler namespaces combinators alien alien.syntax alien.c-types lexer parser kernel sequences layouts math math.order alien.libraries math.parser system make fry arrays libc destructors -tools.disassembler.utils splitting alien.data -classes.struct ; +tools.disassembler.utils tools.disassembler.private splitting +alien.data classes.struct ; IN: tools.disassembler.udis << @@ -105,7 +105,7 @@ FUNCTION: char* ud_lookup_mnemonic ( int c ) ; dup UD_SYN_INTEL ud_set_syntax ; : with-ud ( quot: ( ud -- ) -- ) - [ [ [ ] dip call ] with-destructors ] with-words-xt ; inline + [ [ [ ] dip call ] with-destructors ] with-word-entry-points ; inline SINGLETON: udis-disassembler diff --git a/basis/tools/disassembler/utils/utils.factor b/basis/tools/disassembler/utils/utils.factor index fb936cf08a..60e094ac34 100644 --- a/basis/tools/disassembler/utils/utils.factor +++ b/basis/tools/disassembler/utils/utils.factor @@ -2,13 +2,13 @@ USING: accessors arrays binary-search kernel math math.order math.parser namespaces sequences sorting splitting vectors vocabs words ; IN: tools.disassembler.utils -SYMBOL: words-xt +SYMBOL: word-entry-points SYMBOL: smallest-xt SYMBOL: greatest-xt -: (words-xt) ( -- assoc ) - vocabs [ words ] map concat [ [ word-xt ] keep 3array ] map - [ [ first ] bi@ <=> ] sort >vector ; +: (word-entry-points) ( -- assoc ) + vocabs [ words ] map concat [ [ word-code ] keep 3array ] map + [ first ] sort-with ; : complete-address ( n seq -- str ) [ first - ] [ third name>> ] bi @@ -18,7 +18,7 @@ SYMBOL: greatest-xt dup [ smallest-xt get < ] [ greatest-xt get > ] bi or [ drop f ] [ - words-xt get over [ swap first <=> ] curry search nip + word-entry-points get over [ swap first <=> ] curry search nip 2dup second <= [ [ complete-address ] [ drop f ] if* ] [ @@ -33,9 +33,11 @@ SYMBOL: greatest-xt : resolve-call ( str -- str' ) "0x" split1-last [ resolve-xt "0x" glue ] when* ; -: with-words-xt ( quot -- ) - [ (words-xt) - [ words-xt set ] - [ first first smallest-xt set ] - [ last second greatest-xt set ] tri - ] prepose with-scope ; inline +: with-word-entry-points ( quot -- ) + [ + (word-entry-points) + [ word-entry-points set ] + [ first first smallest-xt set ] + [ last second greatest-xt set ] tri + call + ] with-scope ; inline diff --git a/basis/tools/errors/model/model.factor b/basis/tools/errors/model/model.factor index c874363fe6..b41d236fd7 100644 --- a/basis/tools/errors/model/model.factor +++ b/basis/tools/errors/model/model.factor @@ -14,5 +14,5 @@ SINGLETON: updater M: updater errors-changed drop f (error-list-model) get-global set-model ; -[ updater add-error-observer ] "ui.tools.error-list" add-init-hook +[ updater add-error-observer ] "ui.tools.error-list" add-startup-hook diff --git a/basis/tools/files/files.factor b/basis/tools/files/files.factor old mode 100755 new mode 100644 diff --git a/basis/tools/files/unix/unix.factor b/basis/tools/files/unix/unix.factor old mode 100755 new mode 100644 diff --git a/basis/tools/files/windows/windows.factor b/basis/tools/files/windows/windows.factor old mode 100755 new mode 100644 diff --git a/basis/tools/memory/memory-docs.factor b/basis/tools/memory/memory-docs.factor index f729e8945f..b18396538f 100644 --- a/basis/tools/memory/memory-docs.factor +++ b/basis/tools/memory/memory-docs.factor @@ -13,11 +13,8 @@ ARTICLE: "tools.memory" "Object memory tools" data-room code-room } -"There are a pair of combinators, analogous to " { $link each } " and " { $link filter } ", which operate on the entire collection of objects in the object heap:" -{ $subsections - each-object - instances -} +"A combinator to get objects from the heap:" +{ $subsections instances } "You can check an object's the heap memory usage:" { $subsections size } "The garbage collector can be invoked manually:" diff --git a/basis/tools/memory/memory.factor b/basis/tools/memory/memory.factor index c147426a6f..6746031a3d 100644 --- a/basis/tools/memory/memory.factor +++ b/basis/tools/memory/memory.factor @@ -4,8 +4,7 @@ USING: accessors arrays assocs classes classes.struct combinators combinators.smart continuations fry generalizations generic grouping io io.styles kernel make math math.parser math.statistics memory namespaces parser prettyprint sequences -sorting specialized-arrays splitting strings system vm words ; -SPECIALIZED-ARRAY: gc-event +sorting splitting strings system vm words ; IN: tools.memory string ( n -- str ) - commas " µs" append ; +: nanos>string ( n -- str ) + 1000 /i commas " µs" append ; : copying-room. ( copying-sizes -- ) { @@ -101,7 +100,7 @@ SYMBOL: gc-events : collect-gc-events ( quot -- ) enable-gc-events [ ] [ disable-gc-events drop ] cleanup - disable-gc-events byte-array>gc-event-array gc-events set ; inline + disable-gc-events [ gc-event memory>struct ] map gc-events set ; inline > ] [ times>> { - [ sum micros>string ] - [ mean >integer micros>string ] - [ median >integer micros>string ] - [ infimum micros>string ] - [ supremum micros>string ] + [ sum nanos>string ] + [ mean >integer nanos>string ] + [ median >integer nanos>string ] + [ infimum nanos>string ] + [ supremum nanos>string ] } cleave ] bi ] bi @@ -173,7 +172,7 @@ PRIVATE> : gc-event. ( event -- ) { { "Event type:" [ op>> gc-op-string ] } - { "Total time:" [ total-time>> micros>string ] } + { "Total time:" [ total-time>> nanos>string ] } { "Space reclaimed:" [ space-reclaimed kilobytes ] } } object-table. ; @@ -189,10 +188,10 @@ PRIVATE> { "Cards scanned:" [ [ cards-scanned>> ] map-sum commas ] } { "Decks scanned:" [ [ decks-scanned>> ] map-sum commas ] } { "Code blocks scanned:" [ [ code-blocks-scanned>> ] map-sum commas ] } - { "Total time:" [ [ total-time>> ] map-sum micros>string ] } - { "Card scan time:" [ [ card-scan-time>> ] map-sum micros>string ] } - { "Code block scan time:" [ [ code-scan-time>> ] map-sum micros>string ] } - { "Data heap sweep time:" [ [ data-sweep-time>> ] map-sum micros>string ] } - { "Code heap sweep time:" [ [ code-sweep-time>> ] map-sum micros>string ] } - { "Compaction time:" [ [ compaction-time>> ] map-sum micros>string ] } + { "Total time:" [ [ total-time>> ] map-sum nanos>string ] } + { "Card scan time:" [ [ card-scan-time>> ] map-sum nanos>string ] } + { "Code block scan time:" [ [ code-scan-time>> ] map-sum nanos>string ] } + { "Data heap sweep time:" [ [ data-sweep-time>> ] map-sum nanos>string ] } + { "Code heap sweep time:" [ [ code-sweep-time>> ] map-sum nanos>string ] } + { "Compaction time:" [ [ compaction-time>> ] map-sum nanos>string ] } } object-table. ; diff --git a/basis/tools/profiler/profiler-tests.factor b/basis/tools/profiler/profiler-tests.factor index 7f44a6138c..8f3260d649 100644 --- a/basis/tools/profiler/profiler-tests.factor +++ b/basis/tools/profiler/profiler-tests.factor @@ -60,7 +60,15 @@ IN: tools.profiler.tests [ [ gensym execute ] profile ] [ T{ undefined } = ] must-fail-with -: crash-bug-1 ( -- x ) "hi" "bye" ; +: crash-bug-1 ( -- x ) "hi" ; : crash-bug-2 ( -- ) 100000 [ crash-bug-1 drop ] times ; [ ] [ [ crash-bug-2 ] profile ] unit-test + +[ 1 ] [ + [ + [ [ ] (( -- )) define-temp ] with-compilation-unit + dup execute( -- ) + ] profile + counter>> +] unit-test diff --git a/basis/tools/profiler/profiler.factor b/basis/tools/profiler/profiler.factor index 626fdab826..8279a90514 100644 --- a/basis/tools/profiler/profiler.factor +++ b/basis/tools/profiler/profiler.factor @@ -1,9 +1,10 @@ ! Copyright (C) 2007, 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors words sequences math prettyprint kernel arrays io -io.styles namespaces assocs kernel.private strings combinators -sorting math.parser vocabs definitions tools.profiler.private -tools.crossref continuations generic compiler.units sets classes fry ; +USING: accessors words sequences math prettyprint kernel arrays +io io.styles namespaces assocs kernel.private strings +combinators sorting math.parser vocabs definitions +tools.profiler.private tools.crossref continuations generic +compiler.units compiler.crossref sets classes fry ; IN: tools.profiler : profile ( quot -- ) diff --git a/basis/tools/scaffold/scaffold.factor b/basis/tools/scaffold/scaffold.factor old mode 100755 new mode 100644 index 089bad3158..936d388b01 --- a/basis/tools/scaffold/scaffold.factor +++ b/basis/tools/scaffold/scaffold.factor @@ -98,7 +98,7 @@ M: bad-developer-name summary [ main-file-string ] dip utf8 set-file-contents ; : scaffold-main ( vocab-root vocab -- ) - tuck ".factor" vocab-root/vocab/suffix>path scaffolding? [ + [ ".factor" vocab-root/vocab/suffix>path ] keep swap scaffolding? [ set-scaffold-main-file ] [ 2drop diff --git a/basis/tools/scaffold/windows/windows.factor b/basis/tools/scaffold/windows/windows.factor old mode 100755 new mode 100644 diff --git a/basis/tools/test/test.factor b/basis/tools/test/test.factor index 009789a739..559b1357c8 100644 --- a/basis/tools/test/test.factor +++ b/basis/tools/test/test.factor @@ -121,9 +121,6 @@ SYNTAX: TEST: vocab-tests [ run-test-file ] each ] [ drop ] if ; -: traceback-button. ( failure -- ) - "[" write [ "Traceback" ] dip continuation>> write-object "]" print ; - PRIVATE> TEST: unit-test @@ -137,7 +134,7 @@ M: test-failure error. ( error -- ) [ error-location print nl ] [ asset>> [ experiment. nl ] when* ] [ error>> error. ] - [ traceback-button. ] + [ continuation>> traceback-link. ] } cleave ; : :test-failures ( -- ) test-failures get errors. ; diff --git a/basis/tools/threads/threads.factor b/basis/tools/threads/threads.factor index 18dd8ce2b7..ea85fb1129 100644 --- a/basis/tools/threads/threads.factor +++ b/basis/tools/threads/threads.factor @@ -14,8 +14,8 @@ IN: tools.threads ] with-cell [ sleep-entry>> [ - key>> micros [-] number>string write - " us" write + key>> nano-count [-] number>string write + " nanos" write ] when* ] with-cell ; diff --git a/basis/tools/time/time-docs.factor b/basis/tools/time/time-docs.factor index 9e892c33ec..d28202f844 100644 --- a/basis/tools/time/time-docs.factor +++ b/basis/tools/time/time-docs.factor @@ -9,8 +9,7 @@ ARTICLE: "timing" "Timing code and collecting statistics" { $subsections dispatch-stats. gc-events. gc-stats. gc-summary. } "A lower-level word puts timings on the stack, intead of printing:" { $subsections benchmark } -"You can also read the system clock directly:" -{ $subsections micros } +"You can also read the system clock directly; see " { $link "system" } "." { $see-also "profiling" "calendar" } ; ABOUT: "timing" @@ -25,7 +24,7 @@ HELP: time { $values { "quot" quotation } } { $description "Runs a quotation, gathering statistics about method dispatch and garbage collection, and then prints the total run time." } ; -{ benchmark micros time } related-words +{ benchmark system-micros time } related-words HELP: collect-gc-events { $values { "quot" quotation } } diff --git a/basis/tools/time/time-tests.factor b/basis/tools/time/time-tests.factor new file mode 100644 index 0000000000..00c774663c --- /dev/null +++ b/basis/tools/time/time-tests.factor @@ -0,0 +1,4 @@ +IN: tools.time.tests +USING: tools.time tools.test compiler ; + +[ ] [ [ [ ] time ] compile-call ] unit-test diff --git a/basis/tools/time/time.factor b/basis/tools/time/time.factor index 3724a741b7..0bd97f563d 100644 --- a/basis/tools/time/time.factor +++ b/basis/tools/time/time.factor @@ -5,10 +5,10 @@ tools.dispatch ; IN: tools.time : benchmark ( quot -- runtime ) - micros [ call micros ] dip - ; inline + nano-count [ call nano-count ] dip - ; inline : time. ( time -- ) - "Running time: " write 1000000 /f pprint " seconds" print ; + "Running time: " write 1000000000 /f pprint " seconds" print ; : time-banner. ( -- ) "Additional information was collected." print diff --git a/basis/tr/tr.factor b/basis/tr/tr.factor index f75adcbf04..690103edf5 100644 --- a/basis/tr/tr.factor +++ b/basis/tr/tr.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: byte-arrays strings sequences sequences.private ascii fry kernel words parser lexer assocs math math.order summary ; @@ -17,7 +17,7 @@ M: bad-tr summary [ [ ascii? ] all? ] both? [ bad-tr ] unless ; : compute-tr ( quot from to -- mapping ) - [ 128 ] 3dip zip + [ 128 iota ] 3dip zip '[ [ _ call( x -- y ) _ at ] keep or ] B{ } map-as ; inline : tr-hints ( word -- ) diff --git a/basis/tuple-arrays/tuple-arrays.factor b/basis/tuple-arrays/tuple-arrays.factor index 92e7541616..1bc6270524 100644 --- a/basis/tuple-arrays/tuple-arrays.factor +++ b/basis/tuple-arrays/tuple-arrays.factor @@ -10,7 +10,7 @@ IN: tuple-arrays MACRO: boa-unsafe ( class -- quot ) tuple-layout '[ _ ] ; -MACRO: infer-in ( class -- quot ) infer in>> '[ _ ] ; +MACRO: infer-in ( class -- quot ) inputs '[ _ ] ; : tuple-arity ( class -- quot ) '[ _ boa ] infer-in ; inline @@ -28,7 +28,7 @@ MACRO: infer-in ( class -- quot ) infer in>> '[ _ ] ; MACRO: write-tuple ( class -- quot ) [ '[ [ _ boa ] undo ] ] - [ tuple-arity [ '[ [ _ ] dip set-nth-unsafe ] ] map '[ _ cleave ] ] + [ tuple-arity iota [ '[ [ _ ] dip set-nth-unsafe ] ] map '[ _ cleave ] ] bi '[ _ dip @ ] ; PRIVATE> diff --git a/basis/typed/typed.factor b/basis/typed/typed.factor index ec96902d72..0b3ac9d5f8 100644 --- a/basis/typed/typed.factor +++ b/basis/typed/typed.factor @@ -3,7 +3,7 @@ USING: accessors arrays classes classes.tuple combinators combinators.short-circuit definitions effects fry hints math kernel kernel.private namespaces parser quotations sequences slots words locals -locals.parser macros stack-checker.state ; +locals.parser macros stack-checker.dependencies ; IN: typed ERROR: type-mismatch-error word expected-types ; diff --git a/basis/ui/backend/backend.factor b/basis/ui/backend/backend.factor old mode 100755 new mode 100644 diff --git a/basis/ui/backend/cocoa/cocoa.factor b/basis/ui/backend/cocoa/cocoa.factor old mode 100755 new mode 100644 index 9759dbfcc5..8eeca89c2f --- a/basis/ui/backend/cocoa/cocoa.factor +++ b/basis/ui/backend/cocoa/cocoa.factor @@ -225,9 +225,9 @@ CLASS: { : install-app-delegate ( -- ) NSApp FactorApplicationDelegate install-delegate ; -SYMBOL: cocoa-init-hook +SYMBOL: cocoa-startup-hook -cocoa-init-hook [ +cocoa-startup-hook [ [ "MiniFactor.nib" load-nib install-app-delegate ] ] initialize @@ -235,7 +235,7 @@ M: cocoa-ui-backend (with-ui) "UI" assert.app [ [ init-clipboard - cocoa-init-hook get call( -- ) + cocoa-startup-hook get call( -- ) start-ui f io-thread-running? set-global init-thread-timer diff --git a/basis/ui/backend/cocoa/tools/tools.factor b/basis/ui/backend/cocoa/tools/tools.factor index d04bcededa..00c1ad3583 100644 --- a/basis/ui/backend/cocoa/tools/tools.factor +++ b/basis/ui/backend/cocoa/tools/tools.factor @@ -101,4 +101,4 @@ FUNCTION: void NSUpdateDynamicServices ; install-app-delegate "Factor.nib" load-nib register-services -] cocoa-init-hook set-global +] cocoa-startup-hook set-global diff --git a/basis/ui/backend/windows/windows.factor b/basis/ui/backend/windows/windows.factor old mode 100755 new mode 100644 index a6d73ca80f..fdd3c06c29 --- a/basis/ui/backend/windows/windows.factor +++ b/basis/ui/backend/windows/windows.factor @@ -170,6 +170,8 @@ PRIVATE> : lo-word ( wparam -- lo ) *short ; inline : hi-word ( wparam -- hi ) -16 shift lo-word ; inline : >lo-hi ( WORD -- array ) [ lo-word ] [ hi-word ] bi 2array ; +: GET_APPCOMMAND_LPARAM ( lParam -- appCommand ) + hi-word FAPPCOMMAND_MASK lo-word bitnot bitand ; inline : crlf>lf ( str -- str' ) CHAR: \r swap remove ; @@ -495,6 +497,13 @@ SYMBOL: nc-buttons ReleaseCapture win32-error=0/f mouse-captured off ; +: handle-app-command ( hWnd uMsg wParam lParam -- ) + GET_APPCOMMAND_LPARAM + { + { APPCOMMAND_BROWSER_BACKWARD [ pick window left-action send-action ] } + { APPCOMMAND_BROWSER_FORWARD [ pick window right-action send-action ] } + } case 3drop ; + : handle-wm-buttondown ( hWnd uMsg wParam lParam -- ) [ over set-capture @@ -571,6 +580,8 @@ H{ } clone wm-handlers set-global [ handle-wm-set-focus 0 ] WM_SETFOCUS add-wm-handler [ handle-wm-kill-focus 0 ] WM_KILLFOCUS add-wm-handler +[ handle-app-command 0 ] WM_APPCOMMAND add-wm-handler + [ handle-wm-buttondown 0 ] WM_LBUTTONDOWN add-wm-handler [ handle-wm-buttondown 0 ] WM_MBUTTONDOWN add-wm-handler [ handle-wm-buttondown 0 ] WM_RBUTTONDOWN add-wm-handler diff --git a/basis/ui/backend/x11/x11.factor b/basis/ui/backend/x11/x11.factor old mode 100755 new mode 100644 diff --git a/basis/ui/debugger/debugger.factor b/basis/ui/debugger/debugger.factor old mode 100755 new mode 100644 diff --git a/basis/ui/event-loop/event-loop.factor b/basis/ui/event-loop/event-loop.factor old mode 100755 new mode 100644 diff --git a/basis/ui/gadgets/buttons/buttons-docs.factor b/basis/ui/gadgets/buttons/buttons-docs.factor index cee38dbd78..f39d45b978 100644 --- a/basis/ui/gadgets/buttons/buttons-docs.factor +++ b/basis/ui/gadgets/buttons/buttons-docs.factor @@ -33,10 +33,10 @@ HELP: button-pen { { $snippet "plain" } " - the button is inactive" } { { $snippet "rollover" } " - the button is under the mouse" } { { $snippet "pressed" } " - the button is under the mouse and a mouse button is held down" } - { { $snippet "selected" } " - the button is selected (see " { $link checkbox } } - { { $snippet "selected" } " - the button is selected and a mouse button is being held down (see " { $link checkbox } } + { { $snippet "selected" } " - the button is selected (see " { $link checkbox } ")" } + { { $snippet "pressed-selected" } " - the button is selected and a mouse button is being held down (see " { $link checkbox } ")" } } -"The " { $link } " and " { $link } " words create " { $link button } " instances with specific " { $link button-pen } "." } ; +"The " { $link } " and " { $link } " words create " { $link button } " instances with specific " { $link button-pen } "s." } ; HELP: { $values { "target" object } { "gesture" "a gesture" } { "command" "a command" } { "button" "a new " { $link button } } } diff --git a/basis/ui/gadgets/editors/editors.factor b/basis/ui/gadgets/editors/editors.factor old mode 100755 new mode 100644 diff --git a/basis/ui/gadgets/gadgets-tests.factor b/basis/ui/gadgets/gadgets-tests.factor index d7f77d9e54..ea16abb9ba 100644 --- a/basis/ui/gadgets/gadgets-tests.factor +++ b/basis/ui/gadgets/gadgets-tests.factor @@ -123,7 +123,7 @@ M: mock-gadget ungraft* over >>model "g" get over add-gadget drop swap 1 + number>string set - ] each ; + ] each-integer ; : status-flags ( -- seq ) { "g" "1" "2" "3" } [ get graft-state>> ] map prune ; diff --git a/basis/ui/gadgets/gadgets.factor b/basis/ui/gadgets/gadgets.factor index 12d0ef580d..8eb11a7753 100644 --- a/basis/ui/gadgets/gadgets.factor +++ b/basis/ui/gadgets/gadgets.factor @@ -11,7 +11,6 @@ CONSTANT: horizontal { 1 0 } CONSTANT: vertical { 0 1 } TUPLE: gadget < rect -id pref-dim parent children @@ -29,7 +28,7 @@ model ; M: gadget equal? 2drop f ; -M: gadget hashcode* nip [ [ \ gadget counter ] unless* ] change-id id>> ; +M: gadget hashcode* nip identity-hashcode ; M: gadget model-changed 2drop ; diff --git a/basis/ui/gadgets/grid-lines/grid-lines.factor b/basis/ui/gadgets/grid-lines/grid-lines.factor old mode 100755 new mode 100644 diff --git a/basis/ui/gadgets/packs/packs-tests.factor b/basis/ui/gadgets/packs/packs-tests.factor index b49f46c05a..7ca83ce465 100644 --- a/basis/ui/gadgets/packs/packs-tests.factor +++ b/basis/ui/gadgets/packs/packs-tests.factor @@ -1,14 +1,14 @@ USING: ui.gadgets.packs ui.gadgets.packs.private ui.gadgets.labels ui.gadgets ui.gadgets.debug ui.render ui.baseline-alignment kernel namespaces tools.test math.parser -sequences math.rectangles accessors ; +sequences math.rectangles accessors math ; IN: ui.gadgets.packs.tests [ t ] [ { 0 0 } { 100 100 } clip set - 100 [ number>string ><-> XML] ; + : common-report ( -- xml ) target-os get target-cpu get short-host-name build-dir - current-git-id get + current-git-id get git-link [XML

Build report for <->/<->

@@ -67,7 +71,7 @@ IN: mason.report benchmark-time-file html-help-time-file } [ - dup eval-file milli-seconds>time + dup eval-file nanos>time [XML XML] ] map [XML

Timings

<-><->
<->
XML] ; @@ -82,9 +86,16 @@ IN: mason.report : benchmarks-table ( assoc -- xml ) [ - 1000000 /f + 1,000,000,000 /f [XML <-><-> XML] - ] { } assoc>map [XML

Benchmarks

<->
XML] ; + ] { } assoc>map + [XML +

Benchmarks

+ + + <-> +
BenchmarkTime (seconds)
+ XML] ; : successful-report ( -- ) [ diff --git a/extra/mason/test/test.factor b/extra/mason/test/test.factor index d50c77f71b..034d86b9c6 100644 --- a/extra/mason/test/test.factor +++ b/extra/mason/test/test.factor @@ -51,9 +51,6 @@ M: method-body word-vocabulary "method-generic" word-prop word-vocabulary ; compiler-error-messages-file do-step ; -: benchmark-ms ( quot -- ms ) - benchmark 1000 /i ; inline - : check-boot-image ( -- ) "" to-refresh drop 2dup [ empty? not ] either? [ @@ -67,12 +64,12 @@ M: method-body word-vocabulary "method-generic" word-prop word-vocabulary ; ".." [ bootstrap-time get boot-time-file to-file check-boot-image - [ do-load ] benchmark-ms load-time-file to-file - [ generate-help ] benchmark-ms html-help-time-file to-file - [ do-tests ] benchmark-ms test-time-file to-file - [ do-help-lint ] benchmark-ms help-lint-time-file to-file - [ do-benchmarks ] benchmark-ms benchmark-time-file to-file + [ do-load ] benchmark load-time-file to-file + [ generate-help ] benchmark html-help-time-file to-file + [ do-tests ] benchmark test-time-file to-file + [ do-help-lint ] benchmark help-lint-time-file to-file + [ do-benchmarks ] benchmark benchmark-time-file to-file do-compile-errors ] with-directory ; -MAIN: do-all \ No newline at end of file +MAIN: do-all diff --git a/extra/math/affine-transforms/affine-transforms.factor b/extra/math/affine-transforms/affine-transforms.factor index 7d63bbfac8..e8315cdf20 100644 --- a/extra/math/affine-transforms/affine-transforms.factor +++ b/extra/math/affine-transforms/affine-transforms.factor @@ -41,7 +41,7 @@ CONSTANT: identity-transform T{ affine-transform f { 1.0 0.0 } { 0.0 1.0 } { 0.0 [ [ y>> second ] [ x>> second neg ] bi 2array ] [ [ y>> first neg ] [ x>> first ] bi 2array ] [ |a| ] tri - tuck [ v/n ] 2bi@ ; + [ v/n ] curry bi@ ; : inverse-axes ( a -- a^-1 ) (inverted-axes) { 0.0 0.0 } ; diff --git a/extra/math/analysis/analysis.factor b/extra/math/analysis/analysis.factor old mode 100755 new mode 100644 index 6d01744290..e4052836b4 --- a/extra/math/analysis/analysis.factor +++ b/extra/math/analysis/analysis.factor @@ -18,7 +18,7 @@ CONSTANT: gamma-p6 } : gamma-z ( x n -- seq ) - [ + recip ] with map 1.0 0 pick set-nth ; + [ + recip ] with { } map-integers 1.0 0 pick set-nth ; : (gamma-lanczos6) ( x -- log[gamma[x+1]] ) #! log(gamma(x+1) diff --git a/extra/math/binpack/binpack.factor b/extra/math/binpack/binpack.factor index 4bd1bc1b81..5f1ec0c017 100644 --- a/extra/math/binpack/binpack.factor +++ b/extra/math/binpack/binpack.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 John Benediktsson ! See http://factorcode.org/license.txt for BSD license -USING: sequences kernel arrays vectors accessors assocs sorting math math.functions ; +USING: sequences kernel arrays vectors accessors assocs shuffle sorting locals math math.functions ; IN: math.binpack @@ -9,10 +9,12 @@ IN: math.binpack [ [ values sum ] map ] keep zip sort-keys values first push ; -: binpack ( assoc n -- bins ) - [ sort-values dup length ] dip - tuck / ceiling [ ] map - tuck [ (binpack) ] curry each ; +:: binpack ( assoc n -- bins ) + assoc sort-values :> values + values length :> #values + n #values n / ceiling [ ] map :> bins + values [ bins (binpack) ] each + bins ; : binpack* ( items n -- bins ) [ dup zip ] dip binpack [ keys ] map ; diff --git a/extra/math/finance/finance.factor b/extra/math/finance/finance.factor index 5954b08c9b..f1c608bad9 100644 --- a/extra/math/finance/finance.factor +++ b/extra/math/finance/finance.factor @@ -7,7 +7,7 @@ IN: math.finance m~ ; -SIMD: c:float SPECIALIZED-ARRAY: float-4 IN: math.matrices.simd.tests diff --git a/extra/math/matrices/simd/simd.factor b/extra/math/matrices/simd/simd.factor index 97290964eb..4e1fd0e96c 100644 --- a/extra/math/matrices/simd/simd.factor +++ b/extra/math/matrices/simd/simd.factor @@ -4,7 +4,6 @@ math math.combinatorics math.functions math.matrices.simd math.vectors math.vectors.simd sequences sequences.private specialized-arrays typed ; QUALIFIED-WITH: alien.c-types c -SIMD: c:float SPECIALIZED-ARRAY: float-4 IN: math.matrices.simd diff --git a/extra/math/quadratic/quadratic.factor b/extra/math/quadratic/quadratic.factor index e4642a863b..892b846e9e 100644 --- a/extra/math/quadratic/quadratic.factor +++ b/extra/math/quadratic/quadratic.factor @@ -3,9 +3,9 @@ USING: kernel locals math math.functions ; IN: math.quadratic -: monic ( c b a -- c' b' ) tuck [ / ] 2bi@ ; +: monic ( c b a -- c' b' ) [ / ] curry bi@ ; -: discriminant ( c b -- b d ) tuck sq 4 / swap - sqrt ; +: discriminant ( c b -- b d ) [ nip ] [ sq 4 / swap - sqrt ] 2bi ; : critical ( b d -- -b/2 d ) [ -2 / ] dip ; diff --git a/extra/math/text/english/english.factor b/extra/math/text/english/english.factor old mode 100755 new mode 100644 index 422036d5cc..5b2af13489 --- a/extra/math/text/english/english.factor +++ b/extra/math/text/english/english.factor @@ -83,7 +83,7 @@ SYMBOL: and-needed? first 3digits>text ] [ [ set-conjunction "" ] [ length ] [ ] tri - [ (recombine) ] curry each + [ (recombine) ] curry each-integer ] if ; : (number>text) ( n -- str ) diff --git a/extra/math/text/utils/utils-docs.factor b/extra/math/text/utils/utils-docs.factor old mode 100755 new mode 100644 diff --git a/extra/math/text/utils/utils-tests.factor b/extra/math/text/utils/utils-tests.factor old mode 100755 new mode 100644 diff --git a/extra/math/text/utils/utils.factor b/extra/math/text/utils/utils.factor old mode 100755 new mode 100644 diff --git a/extra/maze/deploy.factor b/extra/maze/deploy.factor old mode 100755 new mode 100644 diff --git a/extra/maze/maze.factor b/extra/maze/maze.factor index c0623d96b6..5d0d55b64e 100644 --- a/extra/maze/maze.factor +++ b/extra/maze/maze.factor @@ -44,7 +44,7 @@ SYMBOL: visited line-width 2 - glLineWidth line-width 2 - glPointSize 1.0 1.0 1.0 1.0 glColor4d - dup [ drop t ] with map visited set + dup iota [ drop t ] with map visited set GL_LINE_STRIP glBegin { 0 0 } dup vertex (draw-maze) glEnd ; @@ -61,7 +61,7 @@ M: maze draw-gadget* [ n draw-maze ] draw-canvas ; M: maze pref-dim* drop { 400 400 } ; -: maze-window ( -- ) - [ "Maze" open-window ] with-ui ; +MAIN-WINDOW: maze-window { { title "Maze" } } + >>gadgets ; MAIN: maze-window diff --git a/extra/memory/pools/pools.factor b/extra/memory/pools/pools.factor index 33d1fbedcb..a053c05853 100644 --- a/extra/memory/pools/pools.factor +++ b/extra/memory/pools/pools.factor @@ -1,6 +1,6 @@ ! (c)2009 Joe Groff bsd license USING: accessors arrays bit-arrays classes -classes.tuple.private fry kernel locals parser +classes.tuple.private fry kernel locals math parser sequences sequences.private vectors words ; IN: memory.pools @@ -10,7 +10,7 @@ TUPLE: pool : ( size class -- pool ) [ nip new ] - [ [ iota ] dip '[ _ new ] V{ } replicate-as ] 2bi + [ '[ _ new ] V{ } replicate-as ] 2bi pool boa ; : pool-size ( pool -- size ) @@ -20,7 +20,7 @@ TUPLE: pool :: copy-tuple ( from to -- to ) from tuple-size :> size - size [| n | n from array-nth n to set-array-nth ] each + size [| n | n from array-nth n to set-array-nth ] each-integer to ; inline : (pool-new) ( pool -- object ) diff --git a/extra/merger/merger.factor b/extra/merger/merger.factor index ee9207e4ca..a990dd30c4 100644 --- a/extra/merger/merger.factor +++ b/extra/merger/merger.factor @@ -4,7 +4,11 @@ ui.gadgets ui.gadgets.buttons ui.gadgets.labeled ui.gadgets.tracks ui.gadgets.labels ui.gadgets.glass math.rectangles cocoa.dialogs ; IN: merger -: main ( -- ) [ + +MAIN-WINDOW: merger-window { + { title "Merging" } + { pref-dim { 300 220 } } + } vertical { "From:" "To:" } f f 2array [ @@ -25,7 +29,5 @@ IN: merger ] with-directory ] keep hide-glass ] [ drop ] if ] - "merge" swap 0.4 track-add { 300 220 } >>pref-dim "Merging" open-window -] with-ui ; - -MAIN: main \ No newline at end of file + "merge" swap 0.4 track-add + >>gadgets ; diff --git a/extra/method-chains/method-chains-docs.factor b/extra/method-chains/method-chains-docs.factor new file mode 100644 index 0000000000..3e8e0e97bf --- /dev/null +++ b/extra/method-chains/method-chains-docs.factor @@ -0,0 +1,22 @@ +! (c)2009 Joe Groff bsd license +USING: help.markup help.syntax ; +IN: method-chains + +HELP: AFTER: +{ $syntax "AFTER: class generic + implementation ;" } +{ $description "Defines a method on " { $snippet "generic" } " for " { $snippet "class" } " which executes the new " { $snippet "implementation" } " code after invoking the parent class method on " { $snippet "generic" } "." } ; + +HELP: BEFORE: +{ $syntax "BEFORE: class generic + implementation ;" } +{ $description "Defines a method on " { $snippet "generic" } " for " { $snippet "class" } " which executes the new " { $snippet "implementation" } " code, then invokes the parent class method on " { $snippet "generic" } "." } ; + +ARTICLE: "method-chains" "Method chaining syntax" +"The " { $vocab-link "method-chains" } " vocabulary provides syntax for extending method implementations in class hierarchies." +{ $subsections + POSTPONE: AFTER: + POSTPONE: BEFORE: +} ; + +ABOUT: "method-chains" diff --git a/extra/method-chains/summary.txt b/extra/method-chains/summary.txt new file mode 100644 index 0000000000..dc80f82d97 --- /dev/null +++ b/extra/method-chains/summary.txt @@ -0,0 +1 @@ +BEFORE: and AFTER: syntax for extending methods in class hierarchies diff --git a/extra/minneapolis-talk/deploy.factor b/extra/minneapolis-talk/deploy.factor old mode 100755 new mode 100644 diff --git a/extra/minneapolis-talk/minneapolis-talk.factor b/extra/minneapolis-talk/minneapolis-talk.factor old mode 100755 new mode 100644 diff --git a/basis/models/illusion/authors.txt b/extra/models/illusion/authors.txt similarity index 100% rename from basis/models/illusion/authors.txt rename to extra/models/illusion/authors.txt diff --git a/basis/models/illusion/illusion.factor b/extra/models/illusion/illusion.factor similarity index 100% rename from basis/models/illusion/illusion.factor rename to extra/models/illusion/illusion.factor diff --git a/basis/models/illusion/summary.txt b/extra/models/illusion/summary.txt similarity index 100% rename from basis/models/illusion/summary.txt rename to extra/models/illusion/summary.txt diff --git a/extra/mongodb/benchmark/benchmark.factor b/extra/mongodb/benchmark/benchmark.factor index ad8c501605..399b5c4e8c 100644 --- a/extra/mongodb/benchmark/benchmark.factor +++ b/extra/mongodb/benchmark/benchmark.factor @@ -224,15 +224,15 @@ CONSTANT: DOC-LARGE H{ { "base_url" "http://www.example.com/test-me" } [ index>> bchar ] keep lasterror>> bchar trial-size ] dip - 1000000 / /i - "%-18s: {batch:%s,index:%s;errchk:%s} %10s docs/s" + 1000000000 / [ /i ] [ result get batch>> [ [ batch-size /i ] dip ] when /i ] 2bi + "%-18s: {batch:%s,index:%s;errchk:%s} %10s docs/s %10s ops/s" sprintf print flush ; : print-separator ( -- ) - "----------------------------------------------------------------" print flush ; inline + "---------------------------------------------------------------------------------" print flush ; inline : print-separator-bold ( -- ) - "================================================================" print flush ; inline + "=================================================================================" print flush ; inline : print-header ( -- ) trial-size diff --git a/extra/mongodb/driver/driver.factor b/extra/mongodb/driver/driver.factor index 294672523c..78d0b62734 100644 --- a/extra/mongodb/driver/driver.factor +++ b/extra/mongodb/driver/driver.factor @@ -165,9 +165,7 @@ M: mdb-collection create-collection : fix-query-collection ( mdb-query -- mdb-query ) [ check-collection ] change-collection ; inline -GENERIC: get-more ( mdb-cursor -- mdb-cursor seq ) - -M: mdb-cursor get-more +: get-more ( mdb-cursor -- mdb-cursor seq ) [ [ query>> dup [ collection>> ] [ return#>> ] bi ] [ id>> ] bi swap >>query send-query ] [ f f ] if* ; @@ -177,21 +175,20 @@ PRIVATE> : ( collection assoc -- mdb-query-msg ) ; inline -GENERIC# limit 1 ( mdb-query-msg limit# -- mdb-query-msg ) - -M: mdb-query-msg limit +: limit ( mdb-query-msg limit# -- mdb-query-msg ) >>return# ; inline -GENERIC# skip 1 ( mdb-query-msg skip# -- mdb-query-msg ) - -M: mdb-query-msg skip +: skip ( mdb-query-msg skip# -- mdb-query-msg ) >>skip# ; inline : asc ( key -- spec ) 1 2array ; inline : desc ( key -- spec ) -1 2array ; inline : sort ( mdb-query-msg sort-quot -- mdb-query-msg ) - output>array [ 1array >hashtable ] map >>orderby ; inline + output>array >hashtable >>orderby ; inline + +: filter-fields ( mdb-query-msg filterseq -- mdb-query-msg ) + [ asc ] map >hashtable >>returnfields ; inline : key-spec ( spec-quot -- spec-assoc ) output>array >hashtable ; inline @@ -209,21 +206,15 @@ M: mdb-query-msg find M: mdb-cursor find get-more ; -GENERIC: explain. ( mdb-query-msg -- ) - -M: mdb-query-msg explain. +: explain. ( mdb-query-msg -- ) t >>explain find nip . ; -GENERIC: find-one ( mdb-query-msg -- result/f ) - -M: mdb-query-msg find-one +: find-one ( mdb-query-msg -- result/f ) fix-query-collection 1 >>return# send-query-plain objects>> dup empty? [ drop f ] [ first ] if ; -GENERIC: count ( mdb-query-msg -- result ) - -M: mdb-query-msg count +: count ( mdb-query-msg -- result ) [ collection>> "count" H{ } clone [ set-at ] keep ] keep query>> [ over [ "query" ] dip set-at ] when* [ cmd-collection ] dip find-one @@ -251,18 +242,15 @@ M: mdb-collection validate. PRIVATE> -GENERIC: save ( collection assoc -- ) -M: assoc save +: save ( collection assoc -- ) [ check-collection ] dip send-message-check-error ; -GENERIC: save-unsafe ( collection assoc -- ) -M: assoc save-unsafe +: save-unsafe ( collection assoc -- ) [ check-collection ] dip send-message ; -GENERIC: ensure-index ( index-spec -- ) -M: index-spec ensure-index +: ensure-index ( index-spec -- ) [ [ uuid1 "_id" ] dip set-at ] keep [ { [ [ name>> "name" ] dip set-at ] [ [ ns>> index-ns "ns" ] dip set-at ] @@ -285,24 +273,23 @@ M: index-spec ensure-index : >upsert ( mdb-update-msg -- mdb-update-msg ) 1 >>upsert? ; -GENERIC: update ( mdb-update-msg -- ) -M: mdb-update-msg update +: update ( mdb-update-msg -- ) send-message-check-error ; -GENERIC: update-unsafe ( mdb-update-msg -- ) -M: mdb-update-msg update-unsafe +: update-unsafe ( mdb-update-msg -- ) send-message ; -GENERIC: delete ( collection selector -- ) -M: assoc delete +: delete ( collection selector -- ) [ check-collection ] dip send-message-check-error ; -GENERIC: delete-unsafe ( collection selector -- ) -M: assoc delete-unsafe +: delete-unsafe ( collection selector -- ) [ check-collection ] dip send-message ; +: kill-cursor ( mdb-cursor -- ) + id>> send-message ; + : load-index-list ( -- index-list ) index-collection H{ } clone find nip ; diff --git a/extra/mongodb/msg/msg.factor b/extra/mongodb/msg/msg.factor index dd8bae8438..ada0ab42d0 100644 --- a/extra/mongodb/msg/msg.factor +++ b/extra/mongodb/msg/msg.factor @@ -29,7 +29,7 @@ TUPLE: mdb-query-msg < mdb-msg { return# integer initial: 0 } { query assoc } { returnfields assoc } -{ orderby sequence } +{ orderby assoc } explain hint ; TUPLE: mdb-insert-msg < mdb-msg @@ -94,7 +94,7 @@ M: sequence ( collection sequence -- mdb-insert-msg ) M: assoc ( collection assoc -- mdb-insert-msg ) [ mdb-insert-msg new ] 2dip [ >>collection ] dip - V{ } clone tuck push + [ V{ } clone ] dip suffix! >>objects OP_Insert >>opcode ; diff --git a/extra/mongodb/operations/operations.factor b/extra/mongodb/operations/operations.factor index 7e99c52aac..108f610940 100644 --- a/extra/mongodb/operations/operations.factor +++ b/extra/mongodb/operations/operations.factor @@ -107,7 +107,7 @@ USE: tools.walker :: build-query-object ( query -- selector ) H{ } clone :> selector - query { [ orderby>> [ "orderby" selector set-at ] when* ] + query { [ orderby>> [ "$orderby" selector set-at ] when* ] [ explain>> [ "$explain" selector set-at ] when* ] [ hint>> [ "$hint" selector set-at ] when* ] [ query>> "query" selector set-at ] diff --git a/extra/mongodb/tuple/persistent/persistent.factor b/extra/mongodb/tuple/persistent/persistent.factor index fc521eca3e..9ea66fba52 100644 --- a/extra/mongodb/tuple/persistent/persistent.factor +++ b/extra/mongodb/tuple/persistent/persistent.factor @@ -50,13 +50,13 @@ TUPLE: cond-value value quot ; CONSTRUCTOR: cond-value ( value quot -- cond-value ) ; -: write-mdb-persistent ( value quot: ( tuple -- assoc ) -- value' ) +: write-mdb-persistent ( value quot -- value' ) over [ call( tuple -- assoc ) ] dip [ [ tuple-collection name>> ] [ >toid ] bi ] keep [ add-storable ] dip - [ tuple-collection name>> ] [ id>> ] bi ; inline + [ tuple-collection name>> ] [ id>> ] bi ; -: write-field ( value quot: ( tuple -- assoc ) -- value' ) +: write-field ( value quot -- value' ) { { [ dup value>> mdb-special-value? ] [ value>> ] } { [ dup value>> mdb-persistent? ] @@ -66,7 +66,7 @@ CONSTRUCTOR: cond-value ( value quot -- cond-value ) ; { [ dup value>> [ hashtable? ] [ linked-assoc? ] bi or ] [ [ value>> ] [ quot>> ] bi '[ _ write-field ] assoc-map ] } [ value>> ] - } cond ; inline recursive + } cond ; : write-tuple-fields ( mirror tuple assoc quot: ( tuple -- assoc ) -- ) swap ! m t q q a diff --git a/extra/mongodb/tuple/state/state.factor b/extra/mongodb/tuple/state/state.factor index ec1b8865ab..bbae2b0399 100644 --- a/extra/mongodb/tuple/state/state.factor +++ b/extra/mongodb/tuple/state/state.factor @@ -10,7 +10,7 @@ CONSTANT: MDB_TUPLE_INFO "_mfd_t_info" PRIVATE> : ( tuple -- tuple-info ) - class V{ } clone tuck + class [ V{ } clone ] dip over [ [ name>> ] dip push ] [ [ vocabulary>> ] dip push ] 2bi ; inline diff --git a/extra/multi-methods/multi-methods.factor b/extra/multi-methods/multi-methods.factor old mode 100755 new mode 100644 index de131df3c6..6bed6d5f32 --- a/extra/multi-methods/multi-methods.factor +++ b/extra/multi-methods/multi-methods.factor @@ -21,7 +21,7 @@ SYMBOL: total : canonicalize-specializer-1 ( specializer -- specializer' ) [ [ class? ] filter - [ length [ 1 + neg ] map ] keep zip + [ length iota [ 1 + neg ] map ] keep zip [ length args [ max ] change ] keep ] [ @@ -111,7 +111,7 @@ SYMBOL: total swap "predicate" word-prop append ; : multi-predicate ( classes -- quot ) - dup length + dup length iota [ picker 2array ] 2map [ drop object eq? not ] assoc-filter [ [ t ] ] [ diff --git a/extra/multi-methods/tests/definitions.factor b/extra/multi-methods/tests/definitions.factor index a483a492b3..b0ab2c1bc3 100644 --- a/extra/multi-methods/tests/definitions.factor +++ b/extra/multi-methods/tests/definitions.factor @@ -6,14 +6,14 @@ DEFER: fake \ fake H{ } clone "multi-methods" set-word-prop << (( -- )) \ fake set-stack-effect >> -[ "fake-{ }" ] [ { } \ fake method-word-name ] unit-test - -[ H{ { "multi-method-generic" fake } { "multi-method-specializer" { } } } ] -[ { } \ fake method-word-props ] unit-test - -[ t ] [ { } \ fake method-body? ] unit-test - [ + [ "fake-{ }" ] [ { } \ fake method-word-name ] unit-test + + [ H{ { "multi-method-generic" fake } { "multi-method-specializer" { } } } ] + [ { } \ fake method-word-props ] unit-test + + [ t ] [ { } \ fake method-body? ] unit-test + [ { } [ ] ] [ \ fake methods prepare-methods [ sort-methods ] dip ] unit-test [ t ] [ { } \ fake multi-dispatch-quot callable? ] unit-test diff --git a/extra/nehe/2/2.factor b/extra/nehe/2/2.factor index 1a77b501f0..d28bbdb904 100644 --- a/extra/nehe/2/2.factor +++ b/extra/nehe/2/2.factor @@ -1,5 +1,5 @@ USING: arrays kernel math opengl opengl.gl opengl.glu -opengl.demo-support ui ui.gadgets ui.render ; +opengl.demo-support ui ui.gadgets ui.render literals accessors ; IN: nehe.2 TUPLE: nehe2-gadget < gadget ; @@ -10,9 +10,6 @@ CONSTANT: height 256 : ( -- gadget ) nehe2-gadget new ; -M: nehe2-gadget pref-dim* ( gadget -- dim ) - drop width height 2array ; - M: nehe2-gadget draw-gadget* ( gadget -- ) drop GL_PROJECTION glMatrixMode @@ -42,5 +39,5 @@ M: nehe2-gadget draw-gadget* ( gadget -- ) -1.0 -1.0 0.0 glVertex3f ] do-state ; -: run2 ( -- ) - "NeHe Tutorial 2" open-window ; +MAIN-WINDOW: run2 { { title "NeHe Tutorial 2" } { pref-dim { $ width $ height } } } + >>gadgets ; diff --git a/extra/nehe/3/3.factor b/extra/nehe/3/3.factor index 228107618b..1a3181dfba 100644 --- a/extra/nehe/3/3.factor +++ b/extra/nehe/3/3.factor @@ -1,5 +1,5 @@ USING: arrays kernel math opengl opengl.gl opengl.glu -opengl.demo-support ui ui.gadgets ui.render ; +opengl.demo-support ui ui.gadgets ui.render literals accessors ; IN: nehe.3 TUPLE: nehe3-gadget < gadget ; @@ -10,9 +10,6 @@ CONSTANT: height 256 : ( -- gadget ) nehe3-gadget new ; -M: nehe3-gadget pref-dim* ( gadget -- dim ) - drop width height 2array ; - M: nehe3-gadget draw-gadget* ( gadget -- ) drop GL_PROJECTION glMatrixMode @@ -46,5 +43,5 @@ M: nehe3-gadget draw-gadget* ( gadget -- ) -1.0 -1.0 0.0 glVertex3f ] do-state ; -: run3 ( -- ) - "NeHe Tutorial 3" open-window ; +MAIN-WINDOW: run3 { { title "NeHe Tutorial 3" } { pref-dim { $ width $ height } } } + >>gadgets ; diff --git a/extra/nehe/4/4.factor b/extra/nehe/4/4.factor index 63d334510a..0cddcfcaa3 100644 --- a/extra/nehe/4/4.factor +++ b/extra/nehe/4/4.factor @@ -1,6 +1,6 @@ USING: arrays kernel math opengl opengl.gl opengl.glu opengl.demo-support ui ui.gadgets ui.render threads accessors -calendar ; +calendar literals ; IN: nehe.4 TUPLE: nehe4-gadget < gadget rtri rquad thread quit? ; @@ -14,9 +14,6 @@ CONSTANT: height 256 0.0 >>rtri 0.0 >>rquad ; -M: nehe4-gadget pref-dim* ( gadget -- dim ) - drop width height 2array ; - M: nehe4-gadget draw-gadget* ( gadget -- ) GL_PROJECTION glMatrixMode glLoadIdentity @@ -71,5 +68,5 @@ M: nehe4-gadget graft* ( gadget -- ) M: nehe4-gadget ungraft* ( gadget -- ) t >>quit? drop ; -: run4 ( -- ) - "NeHe Tutorial 4" open-window ; +MAIN-WINDOW: run4 { { title "NeHe Tutorial 4" } { pref-dim { $ width $ height } } } + >>gadgets ; diff --git a/extra/nehe/5/5.factor b/extra/nehe/5/5.factor old mode 100755 new mode 100644 index 60662b9e0f..e6f5c6e6ba --- a/extra/nehe/5/5.factor +++ b/extra/nehe/5/5.factor @@ -1,6 +1,6 @@ USING: arrays kernel math opengl opengl.gl opengl.glu opengl.demo-support ui ui.gadgets ui.render threads accessors -calendar ; +calendar literals ; IN: nehe.5 TUPLE: nehe5-gadget < gadget rtri rquad thread quit? ; @@ -13,9 +13,6 @@ CONSTANT: height 256 0.0 >>rtri 0.0 >>rquad ; -M: nehe5-gadget pref-dim* ( gadget -- dim ) - drop width height 2array ; - M: nehe5-gadget draw-gadget* ( gadget -- ) GL_PROJECTION glMatrixMode glLoadIdentity @@ -123,6 +120,5 @@ M: nehe5-gadget graft* ( gadget -- ) M: nehe5-gadget ungraft* ( gadget -- ) t >>quit? drop ; - -: run5 ( -- ) - "NeHe Tutorial 5" open-window ; +MAIN-WINDOW: run5 { { title "NeHe Tutorial 5" } { pref-dim { $ width $ height } } } + >>gadgets ; diff --git a/extra/nehe/deploy.factor b/extra/nehe/deploy.factor old mode 100755 new mode 100644 diff --git a/extra/nehe/nehe.factor b/extra/nehe/nehe.factor index 70ab0f0f5d..a4c2aedf23 100644 --- a/extra/nehe/nehe.factor +++ b/extra/nehe/nehe.factor @@ -1,15 +1,13 @@ USING: ui.gadgets.buttons ui.gadgets.packs ui.gadgets ui -nehe.2 nehe.3 nehe.4 nehe.5 kernel ; +nehe.2 nehe.3 nehe.4 nehe.5 kernel accessors ; IN: nehe -: nehe-window ( -- ) - [ - - "Nehe 2" [ drop run2 ] add-gadget - "Nehe 3" [ drop run3 ] add-gadget - "Nehe 4" [ drop run4 ] add-gadget - "Nehe 5" [ drop run5 ] add-gadget - "Nehe examples" open-window - ] with-ui ; +MAIN-WINDOW: nehe-window { { title "Nehe Examples" } } + + "Nehe 2" [ drop run2 ] add-gadget + "Nehe 3" [ drop run3 ] add-gadget + "Nehe 4" [ drop run4 ] add-gadget + "Nehe 5" [ drop run5 ] add-gadget + >>gadgets ; MAIN: nehe-window diff --git a/extra/noise/noise-tests.factor b/extra/noise/noise-tests.factor new file mode 100644 index 0000000000..e216637c51 --- /dev/null +++ b/extra/noise/noise-tests.factor @@ -0,0 +1,4 @@ +IN: noise.tests +USING: noise tools.test sequences math ; + +[ t ] [ { 100 100 } perlin-noise-map-coords [ [ 100 <= ] all? ] all? ] unit-test diff --git a/extra/noise/noise.factor b/extra/noise/noise.factor index 91e040d35f..9204fa55f1 100644 --- a/extra/noise/noise.factor +++ b/extra/noise/noise.factor @@ -4,7 +4,6 @@ math.libm math.matrices.simd math.vectors math.vectors.conversion math.vectors.s memoize random random.mersenne-twister sequences sequences.private specialized-arrays typed ; QUALIFIED-WITH: alien.c-types c -SIMDS: c:float c:int c:short c:ushort c:uchar ; SPECIALIZED-ARRAYS: c:float c:uchar float-4 uchar-16 ; IN: noise @@ -121,7 +120,7 @@ TYPED:: perlin-noise ( table: byte-array point: float-4 -- value: float ) faded trilerp ; MEMO: perlin-noise-map-coords ( dim -- coords ) - first2 [| x y | x [ y 0.0 0.0 float-4-boa ] float-4-array{ } map-as ] with map concat ; + first2 iota [| x y | x iota [ y 0.0 0.0 float-4-boa ] float-4-array{ } map-as ] with map concat ; TYPED:: perlin-noise-map ( table: byte-array transform: matrix4 coords: float-4-array -- map: float-array ) coords [| coord | table transform coord m4.v perlin-noise ] data-map( float-4 -- c:float ) diff --git a/extra/openal/openal.factor b/extra/openal/openal.factor index bccdec1420..85b150ce09 100644 --- a/extra/openal/openal.factor +++ b/extra/openal/openal.factor @@ -3,7 +3,7 @@ USING: kernel accessors arrays alien system combinators alien.syntax namespaces alien.c-types sequences vocabs.loader shuffle openal.backend alien.libraries generalizations -specialized-arrays ; +specialized-arrays alien.destructors ; FROM: alien.c-types => float short ; SPECIALIZED-ARRAY: uint IN: openal @@ -183,6 +183,75 @@ FUNCTION: void alDopplerVelocity ( ALfloat value ) ; FUNCTION: void alSpeedOfSound ( ALfloat value ) ; FUNCTION: void alDistanceModel ( ALenum distanceModel ) ; +C-TYPE: ALCdevice +C-TYPE: ALCcontext +TYPEDEF: char ALCboolean +TYPEDEF: char ALCchar +TYPEDEF: int ALCenum +TYPEDEF: int ALCint +TYPEDEF: int ALCsizei +TYPEDEF: uint ALCuint + +CONSTANT: ALC_FALSE 0 +CONSTANT: ALC_TRUE 1 +CONSTANT: ALC_FREQUENCY HEX: 1007 +CONSTANT: ALC_REFRESH HEX: 1008 +CONSTANT: ALC_SYNC HEX: 1009 +CONSTANT: ALC_MONO_SOURCES HEX: 1010 +CONSTANT: ALC_STEREO_SOURCES HEX: 1011 + +CONSTANT: ALC_NO_ERROR 0 + +CONSTANT: ALC_INVALID_DEVICE HEX: A001 +CONSTANT: ALC_INVALID_CONTEXT HEX: A002 +CONSTANT: ALC_INVALID_ENUM HEX: A003 +CONSTANT: ALC_INVALID_VALUE HEX: A004 +CONSTANT: ALC_OUT_OF_MEMORY HEX: A005 + +CONSTANT: ALC_DEFAULT_DEVICE_SPECIFIER HEX: 1004 +CONSTANT: ALC_DEVICE_SPECIFIER HEX: 1005 +CONSTANT: ALC_EXTENSIONS HEX: 1006 + +CONSTANT: ALC_MAJOR_VERSION HEX: 1000 +CONSTANT: ALC_MINOR_VERSION HEX: 1001 + +CONSTANT: ALC_ATTRIBUTES_SIZE HEX: 1002 +CONSTANT: ALC_ALL_ATTRIBUTES HEX: 1003 +CONSTANT: ALC_DEFAULT_ALL_DEVICES_SPECIFIER HEX: 1012 +CONSTANT: ALC_ALL_DEVICES_SPECIFIER HEX: 1013 +CONSTANT: ALC_CAPTURE_DEVICE_SPECIFIER HEX: 310 +CONSTANT: ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER HEX: 311 +CONSTANT: ALC_CAPTURE_SAMPLES HEX: 312 + +FUNCTION: ALCdevice* alcOpenDevice ( ALCchar* deviceSpecifier ) ; +FUNCTION: ALCboolean alcCloseDevice ( ALCdevice* deviceHandle ) ; + +: alcCloseDevice* ( deviceHandle -- ) + alcCloseDevice drop ; + +FUNCTION: ALCcontext* alcCreateContext ( ALCdevice* deviceHandle, ALCint* attrList ) ; +FUNCTION: ALCboolean alcMakeContextCurrent ( ALCcontext* context ) ; +FUNCTION: void alcProcessContext ( ALCcontext* context ) ; +FUNCTION: void alcSuspendContext ( ALCcontext* context ) ; +FUNCTION: void alcDestroyContext ( ALCcontext* context ) ; +FUNCTION: ALCcontext* alcGetCurrentContext ( ) ; +FUNCTION: ALCdevice* alcGetContextsDevice ( ALCcontext* context ) ; +FUNCTION: ALCboolean alcIsExtensionPresent ( ALCdevice* deviceHandle, ALCchar* extName ) ; +FUNCTION: void* alcGetProcAddress ( ALCdevice* deviceHandle, ALCchar* funcName ) ; +FUNCTION: ALCenum alcGetEnumValue ( ALCdevice* deviceHandle, ALCchar* enumName ) ; +FUNCTION: ALCenum alcGetError ( ALCdevice* deviceHandle ) ; +FUNCTION: ALCchar* alcGetString ( ALCdevice* deviceHandle, ALCenum token ) ; +FUNCTION: void alcGetIntegerv ( ALCdevice* deviceHandle, ALCenum token, ALCsizei size, ALCint* dest ) ; + +FUNCTION: ALCdevice* alcCaptureOpenDevice ( ALCchar* deviceName, ALCuint freq, ALCenum fmt, ALCsizei bufsize ) ; +FUNCTION: ALCboolean alcCaptureCloseDevice ( ALCdevice* device ) ; +FUNCTION: void alcCaptureStart ( ALCdevice* device ) ; +FUNCTION: void alcCaptureStop ( ALCdevice* device ) ; +FUNCTION: void alcCaptureSamples ( ALCdevice* device, void* buf, ALCsizei samps ) ; + +DESTRUCTOR: alcCloseDevice* +DESTRUCTOR: alcDestroyContext + LIBRARY: alut CONSTANT: ALUT_API_MAJOR_VERSION 1 diff --git a/extra/opengl/demo-support/demo-support.factor b/extra/opengl/demo-support/demo-support.factor old mode 100755 new mode 100644 diff --git a/extra/parser-combinators/parser-combinators-docs.factor b/extra/parser-combinators/parser-combinators-docs.factor old mode 100755 new mode 100644 diff --git a/extra/parser-combinators/parser-combinators-tests.factor b/extra/parser-combinators/parser-combinators-tests.factor old mode 100755 new mode 100644 diff --git a/extra/parser-combinators/parser-combinators.factor b/extra/parser-combinators/parser-combinators.factor old mode 100755 new mode 100644 index 7a73561e56..c2e3e34727 --- a/extra/parser-combinators/parser-combinators.factor +++ b/extra/parser-combinators/parser-combinators.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2004 Chris Double. ! See http://factorcode.org/license.txt for BSD license. USING: lists lists.lazy promises kernel sequences strings math -arrays splitting quotations combinators namespaces +arrays splitting quotations combinators namespaces locals unicode.case unicode.categories sequences.deep accessors ; IN: parser-combinators @@ -58,9 +58,11 @@ C: token-parser : case-insensitive-token ( string -- parser ) t ; -M: token-parser parse ( input parser -- list ) - [ string>> ] [ ignore-case?>> ] bi - [ tuck ] dip ?string-head +M:: token-parser parse ( input parser -- list ) + parser string>> :> str + parser ignore-case?>> :> case? + + str input str case? ?string-head [ ] [ 2drop nil ] if ; : 1token ( n -- parser ) 1string token ; @@ -319,7 +321,7 @@ LAZY: <(+)> ( parser -- parser ) <& &> ; : nonempty-list-of ( items separator -- parser ) - [ over &> <*> <&:> ] keep tuck pack ; + [ over &> <*> <&:> ] keep [ nip ] 2keep pack ; : list-of ( items separator -- parser ) #! Given a parser for the separator and for the diff --git a/extra/parser-combinators/simple/simple-docs.factor b/extra/parser-combinators/simple/simple-docs.factor old mode 100755 new mode 100644 diff --git a/extra/parser-combinators/simple/simple.factor b/extra/parser-combinators/simple/simple.factor old mode 100755 new mode 100644 diff --git a/extra/partial-continuations/partial-continuations-tests.factor b/extra/partial-continuations/partial-continuations-tests.factor index d6fdefd1aa..fb7f00f629 100644 --- a/extra/partial-continuations/partial-continuations-tests.factor +++ b/extra/partial-continuations/partial-continuations-tests.factor @@ -1,12 +1,12 @@ USING: namespaces math partial-continuations tools.test -kernel sequences ; +kernel sequences fry ; IN: partial-continuations.tests SYMBOL: sum : range ( r from to -- n ) over - 1 + rot [ - -rot [ over + pick call drop ] each 2drop f + '[ over + @ drop ] each-integer drop f ] bshift 2nip ; inline [ 55 ] [ diff --git a/extra/partial-continuations/partial-continuations.factor b/extra/partial-continuations/partial-continuations.factor old mode 100755 new mode 100644 diff --git a/extra/poker/poker-docs.factor b/extra/poker/poker-docs.factor index fef47b859c..ecdcf3f591 100644 --- a/extra/poker/poker-docs.factor +++ b/extra/poker/poker-docs.factor @@ -1,46 +1,16 @@ -USING: help.markup help.syntax strings ; +USING: help.markup help.syntax math sequences strings ; IN: poker -HELP: -{ $values { "str" string } { "hand" "a new " { $link hand } } } -{ $description "Creates a new poker hand containing the cards specified in " { $snippet "str" } "." } -{ $examples - { $example "USING: kernel math.order poker prettyprint ;" - "\"AC KC QC JC TC\" \"7C 6D 5H 4S 2C\" [ ] bi@ <=> ." "+lt+" } - { $example "USING: kernel poker prettyprint ;" - "\"TC 9C 8C 7C 6C\" \"TH 9H 8H 7H 6H\" [ ] bi@ = ." "t" } -} -{ $notes "Cards may be specified in any order. Hands are directly comparable to each other on the basis of their computed value. Two hands are considered equal when they would tie in a game (despite being composed of different cards)." } ; - -HELP: best-hand -{ $values { "str" string } { "hand" "a new " { $link hand } } } -{ $description "Creates a new poker hand containing the best possible combination of the cards specified in " { $snippet "str" } "." } +HELP: best-holdem-hand +{ $values { "hand" sequence } { "n" integer } { "cards" sequence } } +{ $description "Creates a new poker hand containing the best possible combination of the cards specified in " { $snippet "seq" } "." } { $examples { $example "USING: kernel poker prettyprint ;" - "\"AS KD JC KH 2D 2S KC\" best-hand >value ." "\"Full House\"" } + "HAND{ AS KD JC KH 2D 2S KC } best-holdem-hand drop value>hand-name ." + """"Full House"""" + } } ; -HELP: >cards -{ $values { "hand" hand } { "str" string } } -{ $description "Outputs a string representation of a hand's cards." } -{ $examples - { $example "USING: poker prettyprint ;" - "\"AC KC QC JC TC\" >cards ." "\"AC KC QC JC TC\"" } -} ; - -HELP: >value -{ $values { "hand" hand } { "str" string } } -{ $description "Outputs a string representation of a hand's value." } -{ $examples - { $example "USING: poker prettyprint ;" - "\"AC KC QC JC TC\" >value ." "\"Straight Flush\"" } -} -{ $notes "This should not be used as a basis for hand comparison." } ; - HELP: -{ $values { "deck" "a new " { $link deck } } } -{ $description "Creates a standard deck of 52 cards." } ; - -HELP: shuffle -{ $values { "deck" deck } { "deck" "a shuffled " { $link deck } } } -{ $description "Shuffles the cards in " { $snippet "deck" } ", in-place, using the Fisher-Yates algorithm." } ; +{ $values { "deck" sequence } } +{ $description "Returns a vector containing a standard, shuffled deck of 52 cards." } ; diff --git a/extra/poker/poker-tests.factor b/extra/poker/poker-tests.factor index 6b05178462..fc10a13659 100644 --- a/extra/poker/poker-tests.factor +++ b/extra/poker/poker-tests.factor @@ -1,30 +1,28 @@ -USING: accessors kernel math.order poker poker.private tools.test ; +USING: accessors kernel math math.order poker poker.private +tools.test ; IN: poker.tests [ 134236965 ] [ "KD" >ckf ] unit-test [ 529159 ] [ "5s" >ckf ] unit-test [ 33589533 ] [ "jc" >ckf ] unit-test -[ 7462 ] [ "7C 5D 4H 3S 2C" value>> ] unit-test -[ 1601 ] [ "KD QS JC TH 9S" value>> ] unit-test -[ 11 ] [ "AC AD AH AS KC" value>> ] unit-test -[ 9 ] [ "6C 5C 4C 3C 2C" value>> ] unit-test -[ 1 ] [ "AC KC QC JC TC" value>> ] unit-test +[ 7462 ] [ "7C 5D 4H 3S 2C" string>value ] unit-test +[ 1601 ] [ "KD QS JC TH 9S" string>value ] unit-test +[ 11 ] [ "AC AD AH AS KC" string>value ] unit-test +[ 9 ] [ "6C 5C 4C 3C 2C" string>value ] unit-test +[ 1 ] [ "AC KC QC JC TC" string>value ] unit-test -[ "High Card" ] [ "7C 5D 4H 3S 2C" >value ] unit-test -[ "Straight" ] [ "KD QS JC TH 9S" >value ] unit-test -[ "Four of a Kind" ] [ "AC AD AH AS KC" >value ] unit-test -[ "Straight Flush" ] [ "6C 5C 4C 3C 2C" >value ] unit-test +[ "High Card" ] [ "7C 5D 4H 3S 2C" string>hand-name ] unit-test +[ "Straight" ] [ "KD QS JC TH 9S" string>hand-name ] unit-test +[ "Four of a Kind" ] [ "AC AD AH AS KC" string>hand-name ] unit-test +[ "Straight Flush" ] [ "6C 5C 4C 3C 2C" string>hand-name ] unit-test -[ "6C 5C 4C 3C 2C" ] [ "6C 5C 4C 3C 2C" >cards ] unit-test +[ t ] [ "7C 5D 4H 3S 2C" "KD QS JC TH 9S" [ string>value ] bi@ > ] unit-test +[ t ] [ "AC AD AH AS KC" "KD QS JC TH 9S" [ string>value ] bi@ < ] unit-test +[ t ] [ "7C 5D 4H 3S 2C" "7D 5D 4D 3C 2S" [ string>value ] bi@ = ] unit-test -[ +gt+ ] [ "7C 5D 4H 3S 2C" "KD QS JC TH 9S" [ ] bi@ <=> ] unit-test -[ +lt+ ] [ "AC AD AH AS KC" "KD QS JC TH 9S" [ ] bi@ <=> ] unit-test -[ +eq+ ] [ "7C 5D 4H 3S 2C" "7D 5D 4D 3C 2S" [ ] bi@ <=> ] unit-test +[ t ] [ "7C 5D 4H 3S 2C" "2C 3S 4H 5D 7C" [ string>value ] bi@ = ] unit-test -[ t ] [ "7C 5D 4H 3S 2C" "2C 3S 4H 5D 7C" [ ] bi@ = ] unit-test +[ t ] [ "7C 5D 4H 3S 2C" "7D 5D 4D 3C 2S" [ string>value ] bi@ = ] unit-test -[ t ] [ "7C 5D 4H 3S 2C" "7D 5D 4D 3C 2S" [ ] bi@ = ] unit-test -[ f ] [ "7C 5D 4H 3S 2C" "7D 5D 4D 3C 2S" [ ] bi@ eq? ] unit-test - -[ 190 ] [ "AS KD JC KH 2D 2S KC" best-hand value>> ] unit-test +[ 190 ] [ "AS KD JC KH 2D 2S KC" string>value ] unit-test diff --git a/extra/poker/poker.factor b/extra/poker/poker.factor index a5a5a93628..59f50509e4 100644 --- a/extra/poker/poker.factor +++ b/extra/poker/poker.factor @@ -1,9 +1,11 @@ ! Copyright (c) 2009 Aaron Schaefer. All rights reserved. +! Copyright (c) 2009 Doug Coleman. ! The contents of this file are licensed under the Simplified BSD License ! A copy of the license is available at http://factorcode.org/license.txt -USING: accessors arrays ascii binary-search combinators kernel locals math - math.bitwise math.combinatorics math.order poker.arrays random sequences - sequences.product splitting ; +USING: accessors arrays ascii assocs binary-search combinators +fry kernel locals math math.bitwise math.combinatorics +math.order math.statistics poker.arrays random sequences +sequences.product splitting grouping lexer strings ; IN: poker ! The algorithm used is based on Cactus Kev's Poker Hand Evaluator with @@ -108,11 +110,13 @@ CONSTANT: VALUE_STR { "Straight Flush" "Four of a Kind" "Full House" "Flush" :: (>ckf) ( rank suit -- n ) rank rank suit rank card-bitfield ; -: >ckf ( str -- n ) - #! Cactus Kev Format - >upper 1 cut (>ckf) ; +#! Cactus Kev Format +GENERIC: >ckf ( string -- n ) -: parse-cards ( str -- seq ) +M: string >ckf >upper 1 cut (>ckf) ; +M: integer >ckf ; + +: parse-cards ( string -- seq ) " " split [ >ckf ] map ; : flush? ( cards -- ? ) @@ -148,10 +152,10 @@ CONSTANT: VALUE_STR { "Straight Flush" "Four of a Kind" "Full House" "Flush" ] if ] if ; -: >card-rank ( card -- str ) +: >card-rank ( card -- string ) -8 shift HEX: F bitand RANK_STR nth ; -: >card-suit ( card -- str ) +: >card-suit ( card -- string ) { { [ dup 15 bit? ] [ drop "C" ] } { [ dup 14 bit? ] [ drop "D" ] } @@ -159,7 +163,7 @@ CONSTANT: VALUE_STR { "Straight Flush" "Four of a Kind" "Full House" "Flush" [ drop "S" ] } cond ; -: hand-rank ( value -- rank ) +: value>rank ( value -- rank ) { { [ dup 6185 > ] [ drop HIGH_CARD ] } ! 1277 high card { [ dup 3325 > ] [ drop ONE_PAIR ] } ! 2860 one pair @@ -172,38 +176,92 @@ CONSTANT: VALUE_STR { "Straight Flush" "Four of a Kind" "Full House" "Flush" [ drop STRAIGHT_FLUSH ] ! 10 straight-flushes } cond ; -: card>string ( card -- str ) +: card>string ( n -- string ) [ >card-rank ] [ >card-suit ] bi append ; PRIVATE> -TUPLE: hand - { cards sequence } - { value integer initial: 9999 } ; - -M: hand <=> [ value>> ] compare ; -M: hand equal? - over hand? [ [ value>> ] bi@ = ] [ 2drop f ] if ; - -: ( str -- hand ) - parse-cards dup hand-value hand boa ; - -: best-hand ( str -- hand ) - parse-cards 5 hand new - [ dup hand-value hand boa min ] reduce-combinations ; - -: >cards ( hand -- str ) - cards>> [ card>string ] map " " join ; - -: >value ( hand -- str ) - value>> hand-rank VALUE_STR nth ; - -TUPLE: deck - { cards sequence } ; - : ( -- deck ) - RANK_STR SUIT_STR 2array [ concat >ckf ] product-map deck boa ; + RANK_STR SUIT_STR 2array + [ concat >ckf ] V{ } product-map-as randomize ; -: shuffle ( deck -- deck ) - [ randomize ] change-cards ; +: best-holdem-hand ( hand -- n cards ) + 5 [ [ hand-value ] [ ] bi ] { } map>assoc-combinations + infimum first2 ; +: value>string ( n -- string ) + value>rank VALUE_STR nth ; + +: hand>card-names ( hand -- string ) + [ card>string ] map ; + +: string>value ( string -- value ) + parse-cards best-holdem-hand drop ; + +ERROR: no-card card deck ; + +: draw-specific-card ( card deck -- card ) + [ >ckf ] dip + 2dup index [ swap remove-nth! drop ] [ no-card ] if* ; + +: start-hands ( seq -- seq' deck ) + [ '[ [ _ draw-specific-card ] map ] map ] keep ; + +:: holdem-hand% ( hole1 deck community n -- x ) + community length 5 swap - 2 + :> #samples + n [ + drop + deck #samples sample :> sampled + sampled 2 cut :> ( hole2 community2 ) + hole1 community community2 3append :> hand1 + hole2 community community2 3append :> hand2 + hand1 hand2 [ best-holdem-hand 2array ] bi@ <=> +lt+ = + ] count ; + +:: compare-holdem-hands ( holes deck n -- seq ) + n [ + holes deck 5 sample '[ + [ _ append best-holdem-hand drop ] keep + ] { } map>assoc infimum second + ] replicate histogram ; + +: (best-omaha-hand) ( seq -- pair ) + 4 cut + [ 2 all-combinations ] [ 3 all-combinations ] bi* + 2array [ concat [ best-holdem-hand drop ] keep ] { } product-map>assoc ; + +: best-omaha-hand ( seq -- n cards ) (best-omaha-hand) infimum first2 ; + +:: compare-omaha-hands ( holes deck n -- seq ) + n [ + holes deck 5 sample '[ + [ _ append best-omaha-hand drop ] keep + ] { } map>assoc infimum second + ] replicate histogram ; + +ERROR: bad-suit-symbol ch ; + +: symbol>suit ( ch -- ch' ) + ch>upper + H{ + { CHAR: ♠ CHAR: S } + { CHAR: ♦ CHAR: D } + { CHAR: ♥ CHAR: H } + { CHAR: ♣ CHAR: C } + { CHAR: S CHAR: S } + { CHAR: D CHAR: D } + { CHAR: H CHAR: H } + { CHAR: C CHAR: C } + } ?at [ bad-suit-symbol ] unless ; + +: card> ( string -- card ) + 1 over [ symbol>suit ] change-nth >ckf ; + +: value>hand-name ( value -- string ) + value>rank VALUE_STR nth ; + +: string>hand-name ( string -- string' ) + string>value value>hand-name ; + +SYNTAX: HAND{ + "}" parse-tokens [ card> ] { } map-as suffix! ; diff --git a/extra/project-euler/001/001.factor b/extra/project-euler/001/001.factor index d59b910344..5bf44eddc6 100644 --- a/extra/project-euler/001/001.factor +++ b/extra/project-euler/001/001.factor @@ -47,14 +47,14 @@ PRIVATE> : euler001b ( -- answer ) - 1000 [0,b) [ [ 5 mod ] [ 3 mod ] bi [ 0 = ] either? ] filter sum ; + 1000 iota [ [ 5 mod ] [ 3 mod ] bi [ 0 = ] either? ] filter sum ; ! [ euler001b ] 100 ave-time ! 0 ms ave run time - 0.06 SD (100 trials) : euler001c ( -- answer ) - 1000 [0,b) [ { 3 5 } [ divisor? ] with any? ] filter sum ; + 1000 iota [ { 3 5 } [ divisor? ] with any? ] filter sum ; ! [ euler001c ] 100 ave-time ! 0 ms ave run time - 0.06 SD (100 trials) diff --git a/extra/project-euler/002/002.factor b/extra/project-euler/002/002.factor index 9995e434e7..63d6eac8b4 100644 --- a/extra/project-euler/002/002.factor +++ b/extra/project-euler/002/002.factor @@ -31,7 +31,7 @@ PRIVATE> V{ 0 } clone 1 rot (fib-upto) ; : euler002 ( -- answer ) - 4000000 fib-upto [ even? ] filter sum ; + 4,000,000 fib-upto [ even? ] filter sum ; ! [ euler002 ] 100 ave-time ! 0 ms ave run time - 0.22 SD (100 trials) @@ -41,11 +41,11 @@ PRIVATE> ! ------------------- : fib-upto* ( n -- seq ) - 0 1 [ pick over >= ] [ tuck + dup ] produce [ 3drop ] dip + 0 1 [ pick over >= ] [ [ nip ] 2keep + dup ] produce [ 3drop ] dip but-last-slice { 0 1 } prepend ; : euler002a ( -- answer ) - 4000000 fib-upto* [ even? ] filter sum ; + 4,000,000 fib-upto* [ even? ] filter sum ; ! [ euler002a ] 100 ave-time ! 0 ms ave run time - 0.2 SD (100 trials) @@ -54,7 +54,7 @@ PRIVATE> ] map + length iota [ 0 ] map ] keep [ append ] 2map ; : pad-back ( matrix -- matrix ) [ - length [ 0 ] map + length iota [ 0 ] map ] keep [ append ] 2map ; : diagonal/ ( -- matrix ) diff --git a/extra/project-euler/014/014.factor b/extra/project-euler/014/014.factor index 49680177d5..cbf45c9e32 100644 --- a/extra/project-euler/014/014.factor +++ b/extra/project-euler/014/014.factor @@ -47,7 +47,7 @@ PRIVATE> [ [ dup 1 > ] [ dup , next-collatz ] while , ] { } make ; : euler014 ( -- answer ) - 1000000 [1,b] 0 [ collatz longest ] reduce first ; + 1000000 [1,b] { } [ collatz longest ] reduce first ; ! [ euler014 ] time ! 52868 ms run / 483 ms GC time @@ -64,7 +64,7 @@ PRIVATE> PRIVATE> : euler014a ( -- answer ) - 500000 1000000 [a,b] 1 [ + 500000 1000000 [a,b] { 1 } [ dup worth-calculating? [ collatz longest ] [ drop ] if ] reduce first ; diff --git a/extra/project-euler/024/024.factor b/extra/project-euler/024/024.factor old mode 100755 new mode 100644 index f6b4d497c0..71e44ccb1e --- a/extra/project-euler/024/024.factor +++ b/extra/project-euler/024/024.factor @@ -1,6 +1,7 @@ ! Copyright (c) 2008 Aaron Schaefer. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel math.combinatorics math.parser project-euler.common ; +USING: kernel math.combinatorics math.parser project-euler.common +sequences ; IN: project-euler.024 ! http://projecteuler.net/index.php?section=problems&id=24 @@ -23,7 +24,7 @@ IN: project-euler.024 ! -------- : euler024 ( -- answer ) - 999999 10 permutation 10 digits>integer ; + 999999 10 iota permutation 10 digits>integer ; ! [ euler024 ] 100 ave-time ! 0 ms ave run time - 0.27 SD (100 trials) diff --git a/extra/project-euler/027/027.factor b/extra/project-euler/027/027.factor index f97d8e9e0d..0c697236aa 100644 --- a/extra/project-euler/027/027.factor +++ b/extra/project-euler/027/027.factor @@ -46,7 +46,7 @@ IN: project-euler.027 : euler030 ( -- answer ) - 325537 [0,b) [ dup sum-fifth-powers = ] filter sum 1 - ; + 325537 iota [ dup sum-fifth-powers = ] filter sum 1 - ; ! [ euler030 ] 100 ave-time ! 1700 ms ave run time - 64.84 SD (100 trials) diff --git a/extra/project-euler/032/032.factor b/extra/project-euler/032/032.factor old mode 100755 new mode 100644 index 814f8a5a63..8fb7a2bfaa --- a/extra/project-euler/032/032.factor +++ b/extra/project-euler/032/032.factor @@ -28,7 +28,7 @@ IN: project-euler.032 : source-032 ( -- seq ) 9 factorial iota [ - 9 permutation [ 1 + ] map 10 digits>integer + 9 iota permutation [ 1 + ] map 10 digits>integer ] map ; : 1and4 ( n -- ? ) diff --git a/extra/project-euler/035/035.factor b/extra/project-euler/035/035.factor old mode 100755 new mode 100644 diff --git a/extra/project-euler/037/037.factor b/extra/project-euler/037/037.factor old mode 100755 new mode 100644 diff --git a/extra/project-euler/038/038.factor b/extra/project-euler/038/038.factor old mode 100755 new mode 100644 diff --git a/extra/project-euler/039/039.factor b/extra/project-euler/039/039.factor old mode 100755 new mode 100644 diff --git a/extra/project-euler/040/040.factor b/extra/project-euler/040/040.factor old mode 100755 new mode 100644 diff --git a/extra/project-euler/043/043.factor b/extra/project-euler/043/043.factor index cf49557506..4991d65a89 100644 --- a/extra/project-euler/043/043.factor +++ b/extra/project-euler/043/043.factor @@ -40,13 +40,13 @@ IN: project-euler.043 : interesting? ( seq -- ? ) { - [ 17 8 rot subseq-divisible? ] - [ 13 7 rot subseq-divisible? ] - [ 11 6 rot subseq-divisible? ] - [ 7 5 rot subseq-divisible? ] - [ 5 4 rot subseq-divisible? ] - [ 3 3 rot subseq-divisible? ] - [ 2 2 rot subseq-divisible? ] + [ [ 17 8 ] dip subseq-divisible? ] + [ [ 13 7 ] dip subseq-divisible? ] + [ [ 11 6 ] dip subseq-divisible? ] + [ [ 7 5 ] dip subseq-divisible? ] + [ [ 5 4 ] dip subseq-divisible? ] + [ [ 3 3 ] dip subseq-divisible? ] + [ [ 2 2 ] dip subseq-divisible? ] } 1&& ; PRIVATE> @@ -82,7 +82,7 @@ PRIVATE> [ unclip 1 head prefix concat ] map [ all-unique? ] filter ; : add-missing-digit ( seq -- seq ) - dup natural-sort 10 swap diff prepend ; + dup natural-sort 10 iota swap diff prepend ; : interesting-pandigitals ( -- seq ) 17 candidates { 13 11 7 5 3 2 } [ diff --git a/extra/project-euler/046/046.factor b/extra/project-euler/046/046.factor old mode 100755 new mode 100644 diff --git a/extra/project-euler/052/052.factor b/extra/project-euler/052/052.factor index 037cc87288..ae603c81fd 100644 --- a/extra/project-euler/052/052.factor +++ b/extra/project-euler/052/052.factor @@ -24,7 +24,7 @@ IN: project-euler.052 digits natural-sort ] map all-equal? ; diff --git a/extra/project-euler/053/053.factor b/extra/project-euler/053/053.factor index faca6a8ad5..2e2d317401 100644 --- a/extra/project-euler/053/053.factor +++ b/extra/project-euler/053/053.factor @@ -27,7 +27,7 @@ IN: project-euler.053 ! -------- : euler053 ( -- answer ) - 23 100 [a,b] [ dup [ nCk 1000000 > ] with count ] map-sum ; + 23 100 [a,b] [ dup iota [ nCk 1000000 > ] with count ] map-sum ; ! [ euler053 ] 100 ave-time ! 52 ms ave run time - 4.44 SD (100 trials) diff --git a/extra/project-euler/054/054.factor b/extra/project-euler/054/054.factor index 5cf42737fb..dedd769059 100644 --- a/extra/project-euler/054/054.factor +++ b/extra/project-euler/054/054.factor @@ -76,7 +76,7 @@ IN: project-euler.054 PRIVATE> : euler054 ( -- answer ) - source-054 [ [ ] map first2 before? ] count ; + source-054 [ [ string>value ] map first2 before? ] count ; ! [ euler054 ] 100 ave-time ! 34 ms ave run time - 2.65 SD (100 trials) diff --git a/extra/project-euler/055/055.factor b/extra/project-euler/055/055.factor index 09663d241f..1d8967ff6c 100644 --- a/extra/project-euler/055/055.factor +++ b/extra/project-euler/055/055.factor @@ -61,7 +61,7 @@ IN: project-euler.055 PRIVATE> : euler055 ( -- answer ) - 10000 [0,b) [ lychrel? ] count ; + 10000 iota [ lychrel? ] count ; ! [ euler055 ] 100 ave-time ! 478 ms ave run time - 30.63 SD (100 trials) diff --git a/extra/project-euler/057/057.factor b/extra/project-euler/057/057.factor index 97789944fe..4e35c9da58 100644 --- a/extra/project-euler/057/057.factor +++ b/extra/project-euler/057/057.factor @@ -36,7 +36,7 @@ IN: project-euler.057 >fraction [ number>string length ] bi@ > ; inline : euler057 ( -- answer ) - 0 1000 [0,b) [ drop 2 + recip dup 1 + longer-numerator? ] count nip ; + 0 1000 iota [ drop 2 + recip dup 1 + longer-numerator? ] count nip ; ! [ euler057 ] 100 ave-time ! 1728 ms ave run time - 80.81 SD (100 trials) diff --git a/extra/project-euler/062/062-tests.factor b/extra/project-euler/062/062-tests.factor new file mode 100644 index 0000000000..d8e0b9682e --- /dev/null +++ b/extra/project-euler/062/062-tests.factor @@ -0,0 +1,4 @@ +USING: project-euler.062 tools.test ; +IN: project-euler.062.tests + +[ 127035954683 ] [ euler062 ] unit-test diff --git a/extra/project-euler/062/062.factor b/extra/project-euler/062/062.factor new file mode 100644 index 0000000000..037cdc1af5 --- /dev/null +++ b/extra/project-euler/062/062.factor @@ -0,0 +1,54 @@ +! Copyright (c) 2009 Guillaume Nargeot. +! See http://factorcode.org/license.txt for BSD license. +USING: arrays assocs hashtables kernel math math.functions +project-euler.common sequences sorting ; +IN: project-euler.062 + +! http://projecteuler.net/index.php?section=problems&id=062 + +! DESCRIPTION +! ----------- + +! The cube, 41063625 (345^3), can be permuted to produce two +! other cubes: 56623104 (384^3) and 66430125 (405^3). In +! fact, 41063625 is the smallest cube which has exactly three +! permutations of its digits which are also cube. + +! Find the smallest cube for which exactly five permutations of +! its digits are cube. + + +! SOLUTION +! -------- + +key ( n -- k ) cube number>digits natural-sort ; inline +: has-entry? ( n assoc -- ? ) [ >key ] dip key? ; inline + +: (euler062) ( n assoc -- n ) + 2dup has-entry? [ + 2dup [ >key ] dip + [ dup 0 swap [ 1 + ] change-nth ] change-at + 2dup [ >key ] dip at first 5 = + [ + [ >key ] dip at second + ] [ + [ 1 + ] dip (euler062) + ] if + ] [ + 2dup 1 pick cube 2array -rot + [ >key ] dip set-at [ 1 + ] dip + (euler062) + ] if ; + +PRIVATE> + +: euler062 ( -- answer ) + 1 1 (euler062) ; + +! [ euler062 ] 100 ave-time +! 78 ms ave run time - 0.9 SD (100 trials) + +SOLUTION: euler062 diff --git a/extra/project-euler/062/authors.txt b/extra/project-euler/062/authors.txt new file mode 100644 index 0000000000..6eb6698c00 --- /dev/null +++ b/extra/project-euler/062/authors.txt @@ -0,0 +1 @@ +Guillaume Nargeot diff --git a/extra/project-euler/075/075.factor b/extra/project-euler/075/075.factor old mode 100755 new mode 100644 diff --git a/extra/project-euler/081/081.factor b/extra/project-euler/081/081.factor index 35bc1f1067..cc5e93d7a8 100644 --- a/extra/project-euler/081/081.factor +++ b/extra/project-euler/081/081.factor @@ -60,7 +60,7 @@ IN: project-euler.081 3dup minimal-path-sum-to '[ _ + ] change-matrix ; : (euler081) ( matrix -- n ) - dup first length [0,b) dup cartesian-product + dup first length iota dup cartesian-product [ first2 pick update-minimal-path-sum ] each last last ; diff --git a/extra/project-euler/089/089-tests.factor b/extra/project-euler/089/089-tests.factor new file mode 100644 index 0000000000..9b26b347b0 --- /dev/null +++ b/extra/project-euler/089/089-tests.factor @@ -0,0 +1,4 @@ +USING: project-euler.089 tools.test ; +IN: project-euler.089.tests + +[ 743 ] [ euler089 ] unit-test diff --git a/extra/project-euler/089/089.factor b/extra/project-euler/089/089.factor new file mode 100644 index 0000000000..34b40a7aa6 --- /dev/null +++ b/extra/project-euler/089/089.factor @@ -0,0 +1,48 @@ +! Copyright (c) 2009 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: io.encodings.ascii io.files kernel math +project-euler.common roman sequences ; +IN: project-euler.089 + +! http://projecteuler.net/index.php?section=problems&id=089 + +! DESCRIPTION +! ----------- + +! The rules for writing Roman numerals allow for many ways of writing +! each number (see FAQ: Roman Numerals). However, there is always a +! "best" way of writing a particular number. + +! For example, the following represent all of the legitimate ways of +! writing the number sixteen: + +! IIIIIIIIIIIIIIII +! VIIIIIIIIIII +! VVIIIIII +! XIIIIII +! VVVI +! XVI + +! The last example being considered the most efficient, as it uses +! the least number of numerals. + +! The 11K text file, roman.txt (right click and 'Save Link/Target As...'), +! contains one thousand numbers written in valid, but not necessarily +! minimal, Roman numerals; that is, they are arranged in descending units +! and obey the subtractive pair rule (see FAQ for the definitive rules +! for this problem). + +! Find the number of characters saved by writing each of these in their minimal form. + +! SOLUTION +! -------- + +: euler089 ( -- n ) + "resource:extra/project-euler/089/roman.txt" ascii file-lines + [ ] [ [ roman> >roman ] map ] bi + [ [ length ] map-sum ] bi@ - ; + +! [ euler089 ] 100 ave-time +! 14 ms ave run time - 0.27 SD (100 trials) + +SOLUTION: euler089 diff --git a/extra/project-euler/089/authors.txt b/extra/project-euler/089/authors.txt new file mode 100644 index 0000000000..7c1b2f2279 --- /dev/null +++ b/extra/project-euler/089/authors.txt @@ -0,0 +1 @@ +Doug Coleman diff --git a/extra/project-euler/089/roman.txt b/extra/project-euler/089/roman.txt new file mode 100644 index 0000000000..721ab99915 --- /dev/null +++ b/extra/project-euler/089/roman.txt @@ -0,0 +1,1000 @@ +MMMMDCLXXII +MMDCCCLXXXIII +MMMDLXVIIII +MMMMDXCV +DCCCLXXII +MMCCCVI +MMMCDLXXXVII +MMMMCCXXI +MMMCCXX +MMMMDCCCLXXIII +MMMCCXXXVII +MMCCCLXXXXIX +MDCCCXXIIII +MMCXCVI +CCXCVIII +MMMCCCXXXII +MDCCXXX +MMMDCCCL +MMMMCCLXXXVI +MMDCCCXCVI +MMMDCII +MMMCCXII +MMMMDCCCCI +MMDCCCXCII +MDCXX +CMLXXXVII +MMMXXI +MMMMCCCXIV +MLXXII +MCCLXXVIIII +MMMMCCXXXXI +MMDCCCLXXII +MMMMXXXI +MMMDCCLXXX +MMDCCCLXXIX +MMMMLXXXV +MCXXI +MDCCCXXXVII +MMCCCLXVII +MCDXXXV +CCXXXIII +CMXX +MMMCLXIV +MCCCLXXXVI +DCCCXCVIII +MMMDCCCCXXXIV +CDXVIIII +MMCCXXXV +MDCCCXXXII +MMMMD +MMDCCLXIX +MMMMCCCLXXXXVI +MMDCCXLII +MMMDCCCVIIII +DCCLXXXIIII +MDCCCCXXXII +MMCXXVII +DCCCXXX +CCLXIX +MMMXI +MMMMCMLXXXXVIII +MMMMDLXXXVII +MMMMDCCCLX +MMCCLIV +CMIX +MMDCCCLXXXIIII +CLXXXII +MMCCCCXXXXV +MMMMDLXXXVIIII +MMMDCCCXXI +MMDCCCCLXXVI +MCCCCLXX +MMCDLVIIII +MMMDCCCLIX +MMMMCCCCXIX +MMMDCCCLXXV +XXXI +CDLXXXIII +MMMCXV +MMDCCLXIII +MMDXXX +MMMMCCCLVII +MMMDCI +MMMMCDLXXXIIII +MMMMCCCXVI +CCCLXXXVIII +MMMMCML +MMMMXXIV +MMMCCCCXXX +DCCX +MMMCCLX +MMDXXXIII +CCCLXIII +MMDCCXIII +MMMCCCXLIV +CLXXXXI +CXVI +MMMMCXXXIII +CLXX +DCCCXVIII +MLXVII +DLXXXX +MMDXXI +MMMMDLXXXXVIII +MXXII +LXI +DCCCCXLIII +MMMMDV +MMMMXXXIV +MDCCCLVIII +MMMCCLXXII +MMMMDCCXXXVI +MMMMLXXXIX +MDCCCLXXXI +MMMMDCCCXV +MMMMCCCCXI +MMMMCCCLIII +MDCCCLXXI +MMCCCCXI +MLXV +MMCDLXII +MMMMDXXXXII +MMMMDCCCXL +MMMMCMLVI +CCLXXXIV +MMMDCCLXXXVI +MMCLII +MMMCCCCXV +MMLXXXIII +MMMV +MMMV +DCCLXII +MMDCCCCXVI +MMDCXLVIII +CCLIIII +CCCXXV +MMDCCLXXXVIIII +MMMMDCLXXVIII +MMMMDCCCXCI +MMMMCCCXX +MMCCXLV +MMMDCCCLXIX +MMCCLXIIII +MMMDCCCXLIX +MMMMCCCLXIX +CMLXXXXI +MCMLXXXIX +MMCDLXI +MMDCLXXVIII +MMMMDCCLXI +MCDXXV +DL +CCCLXXII +MXVIIII +MCCCCLXVIII +CIII +MMMDCCLXXIIII +MMMDVIII +MMMMCCCLXXXXVII +MMDXXVII +MMDCCLXXXXV +MMMMCXLVI +MMMDCCLXXXII +MMMDXXXVI +MCXXII +CLI +DCLXXXIX +MMMCLI +MDCLXIII +MMMMDCCXCVII +MMCCCLXXXV +MMMDCXXVIII +MMMCDLX +MMMCMLII +MMMIV +MMMMDCCCLVIII +MMMDLXXXVIII +MCXXIV +MMMMLXXVI +CLXXIX +MMMCCCCXXVIIII +DCCLXXXV +MMMDCCCVI +LI +CLXXXVI +MMMMCCCLXXVI +MCCCLXVI +CCXXXIX +MMDXXXXI +MMDCCCXLI +DCCCLXXXVIII +MMMMDCCCIV +MDCCCCXV +MMCMVI +MMMMCMLXXXXV +MMDCCLVI +MMMMCCXLVIII +DCCCCIIII +MMCCCCIII +MMMDCCLXXXVIIII +MDCCCLXXXXV +DVII +MMMV +DCXXV +MMDCCCXCV +DCVIII +MMCDLXVI +MCXXVIII +MDCCXCVIII +MMDCLX +MMMDCCLXIV +MMCDLXXVII +MMDLXXXIIII +MMMMCCCXXII +MMMDCCCXLIIII +DCCCCLXVII +MMMCLXXXXIII +MCCXV +MMMMDCXI +MMMMDCLXXXXV +MMMCCCLII +MMCMIX +MMDCCXXV +MMDLXXXVI +MMMMDCXXVIIII +DCCCCXXXVIIII +MMCCXXXIIII +MMDCCLXXVIII +MDCCLXVIIII +MMCCLXXXV +MMMMDCCCLXXXVIII +MMCMXCI +MDXLII +MMMMDCCXIV +MMMMLI +DXXXXIII +MMDCCXI +MMMMCCLXXXIII +MMMDCCCLXXIII +MDCLVII +MMCD +MCCCXXVII +MMMMDCCIIII +MMMDCCXLVI +MMMCLXXXVII +MMMCCVIIII +MCCCCLXXIX +DL +DCCCLXXVI +MMDXCI +MMMMDCCCCXXXVI +MMCII +MMMDCCCXXXXV +MMMCDXLV +MMDCXXXXIV +MMD +MDCCCLXXXX +MMDCXLIII +MMCCXXXII +MMDCXXXXVIIII +DCCCLXXI +MDXCVIIII +MMMMCCLXXVIII +MDCLVIIII +MMMCCCLXXXIX +MDCLXXXV +MDLVIII +MMMMCCVII +MMMMDCXIV +MMMCCCLXIIII +MMIIII +MMMMCCCLXXIII +CCIII +MMMCCLV +MMMDXIII +MMMCCCXC +MMMDCCCXXI +MMMMCCCCXXXII +CCCLVI +MMMCCCLXXXVI +MXVIIII +MMMCCCCXIIII +CLXVII +MMMCCLXX +CCCCLXIV +MMXXXXII +MMMMCCLXXXX +MXL +CCXVI +CCCCLVIIII +MMCCCII +MCCCLVIII +MMMMCCCX +MCDLXXXXIV +MDCCCXIII +MMDCCCXL +MMMMCCCXXIII +DXXXIV +CVI +MMMMDCLXXX +DCCCVII +MMCMLXIIII +MMMDCCCXXXIII +DCCC +MDIII +MMCCCLXVI +MMMCCCCLXXI +MMDCCCCXVIII +CCXXXVII +CCCXXV +MDCCCXII +MMMCMV +MMMMCMXV +MMMMDCXCI +DXXI +MMCCXLVIIII +MMMMCMLII +MDLXXX +MMDCLXVI +CXXI +MMMDCCCLIIII +MMMCXXI +MCCIII +MMDCXXXXI +CCXCII +MMMMDXXXV +MMMCCCLXV +MMMMDLXV +MMMCCCCXXXII +MMMCCCVIII +DCCCCLXXXXII +MMCLXIV +MMMMCXI +MLXXXXVII +MMMCDXXXVIII +MDXXII +MLV +MMMMDLXVI +MMMCXII +XXXIII +MMMMDCCCXXVI +MMMLXVIIII +MMMLX +MMMCDLXVII +MDCCCLVII +MMCXXXVII +MDCCCCXXX +MMDCCCLXIII +MMMMDCXLIX +MMMMCMXLVIII +DCCCLXXVIIII +MDCCCLIII +MMMCMLXI +MMMMCCLXI +MMDCCCLIII +MMMDCCCVI +MMDXXXXIX +MMCLXXXXV +MMDXXX +MMMXIII +DCLXXIX +DCCLXII +MMMMDCCLXVIII +MDCCXXXXIII +CCXXXII +MMMMDCXXV +MMMCCCXXVIII +MDCVIII +MMMCLXXXXIIII +CLXXXI +MDCCCCXXXIII +MMMMDCXXX +MMMDCXXIV +MMMCCXXXVII +MCCCXXXXIIII +CXVIII +MMDCCCCIV +MMMMCDLXXV +MMMDLXIV +MDXCIII +MCCLXXXI +MMMDCCCXXIV +MCXLIII +MMMDCCCI +MCCLXXX +CCXV +MMDCCLXXI +MMDLXXXIII +MMMMDCXVII +MMMCMLXV +MCLXVIII +MMMMCCLXXVI +MMMDCCLXVIIII +MMMMDCCCIX +DLXXXXIX +DCCCXXII +MMMMIII +MMMMCCCLXXVI +DCCCXCIII +DXXXI +MXXXIIII +CCXII +MMMDCCLXXXIIII +MMMCXX +MMMCMXXVII +DCCCXXXX +MMCDXXXVIIII +MMMMDCCXVIII +LV +MMMDCCCCVI +MCCCII +MMCMLXVIIII +MDCCXI +MMMMDLXVII +MMCCCCLXI +MMDCCV +MMMCCCXXXIIII +MMMMDI +MMMDCCCXCV +MMDCCLXXXXI +MMMDXXVI +MMMDCCCLVI +MMDCXXX +MCCCVII +MMMMCCCLXII +MMMMXXV +MMCMXXV +MMLVI +MMDXXX +MMMMCVII +MDC +MCCIII +MMMMDCC +MMCCLXXV +MMDCCCXXXXVI +MMMMCCCLXV +CDXIIII +MLXIIII +CCV +MMMCMXXXI +CCCCLXVI +MDXXXII +MMMMCCCLVIII +MMV +MMMCLII +MCMLI +MMDCCXX +MMMMCCCCXXXVI +MCCLXXXI +MMMCMVI +DCCXXX +MMMMCCCLXV +DCCCXI +MMMMDCCCXIV +CCCXXI +MMDLXXV +CCCCLXXXX +MCCCLXXXXII +MMDCIX +DCCXLIIII +DXIV +MMMMCLII +CDLXI +MMMCXXVII +MMMMDCCCCLXIII +MMMDCLIIII +MCCCCXXXXII +MMCCCLX +CCCCLIII +MDCCLXXVI +MCMXXIII +MMMMDLXXVIII +MMDCCCCLX +MMMCCCLXXXX +MMMCDXXVI +MMMDLVIII +CCCLXI +MMMMDCXXII +MMDCCCXXI +MMDCCXIII +MMMMCLXXXVI +MDCCCCXXVI +MDV +MMDCCCCLXXVI +MMMMCCXXXVII +MMMDCCLXXVIIII +MMMCCCCLXVII +DCCXLI +MMCLXXXVIII +MCCXXXVI +MMDCXLVIII +MMMMCXXXII +MMMMDCCLXVI +MMMMCMLI +MMMMCLXV +MMMMDCCCXCIV +MCCLXXVII +LXXVIIII +DCCLII +MMMCCCXCVI +MMMCLV +MMDCCCXXXXVIII +DCCCXV +MXC +MMDCCLXXXXVII +MMMMCML +MMDCCCLXXVIII +DXXI +MCCCXLI +DCLXXXXI +MMCCCLXXXXVIII +MDCCCCLXXVIII +MMMMDXXV +MMMDCXXXVI +MMMCMXCVII +MMXVIIII +MMMDCCLXXIV +MMMCXXV +DXXXVIII +MMMMCLXVI +MDXII +MMCCCLXX +CCLXXI +DXIV +MMMCLIII +DLII +MMMCCCXLIX +MMCCCCXXVI +MMDCXLIII +MXXXXII +CCCLXXXV +MDCLXXVI +MDCXII +MMMCCCLXXXIII +MMDCCCCLXXXII +MMMMCCCLXXXV +MMDCXXI +DCCCXXX +MMMDCCCCLII +MMMDCCXXII +MMMMCDXCVIII +MMMCCLXVIIII +MMXXV +MMMMCDXIX +MMMMCCCX +MMMCCCCLXVI +MMMMDCLXXVIIII +MMMMDCXXXXIV +MMMCMXII +MMMMXXXIII +MMMMDLXXXII +DCCCLIV +MDXVIIII +MMMCLXXXXV +CCCCXX +MMDIX +MMCMLXXXVIII +DCCXLIII +DCCLX +D +MCCCVII +MMMMCCCLXXXIII +MDCCCLXXIIII +MMMDCCCCLXXXVII +MMMMCCCVII +MMMDCCLXXXXVI +CDXXXIV +MCCLXVIII +MMMMDLX +MMMMDXII +MMMMCCCCLIIII +MCMLXXXXIII +MMMMDCCCIII +MMDCLXXXIII +MDCCCXXXXIV +XXXXVII +MMMDCCCXXXII +MMMDCCCXLII +MCXXXV +MDCXXVIIII +MMMCXXXXIIII +MMMMCDXVII +MMMDXXIII +MMMMCCCCLXI +DCLXXXXVIIII +LXXXXI +CXXXIII +MCDX +MCCLVII +MDCXXXXII +MMMCXXIV +MMMMLXXXX +MMDCCCCXLV +MLXXX +MMDCCCCLX +MCDLIII +MMMCCCLXVII +MMMMCCCLXXIV +MMMDCVIII +DCCCCXXIII +MMXCI +MMDCCIV +MMMMDCCCXXXIV +CCCLXXI +MCCLXXXII +MCMIII +CCXXXI +DCCXXXVIII +MMMMDCCXLVIIII +MMMMCMXXXV +DCCCLXXV +DCCXCI +MMMMDVII +MMMMDCCCLXVIIII +CCCXCV +MMMMDCCXX +MCCCCII +MMMCCCXC +MMMCCCII +MMDCCLXXVII +MMDCLIIII +CCXLIII +MMMDCXVIII +MMMCCCIX +MCXV +MMCCXXV +MLXXIIII +MDCCXXVI +MMMCCCXX +MMDLXX +MMCCCCVI +MMDCCXX +MMMMDCCCCXCV +MDCCCXXXII +MMMMDCCCCXXXX +XCIV +MMCCCCLX +MMXVII +MLXXI +MMMDXXVIII +MDCCCCII +MMMCMLVII +MMCLXXXXVIII +MDCCCCLV +MCCCCLXXIIII +MCCCLII +MCDXLVI +MMMMDXVIII +DCCLXXXIX +MMMDCCLXIV +MDCCCCXLIII +CLXXXXV +MMMMCCXXXVI +MMMDCCCXXI +MMMMCDLXXVII +MCDLIII +MMCCXLVI +DCCCLV +MCDLXX +DCLXXVIII +MMDCXXXIX +MMMMDCLX +MMDCCLI +MMCXXXV +MMMCCXII +MMMMCMLXII +MMMMCCV +MCCCCLXIX +MMMMCCIII +CLXVII +MCCCLXXXXIIII +MMMMDCVIII +MMDCCCLXI +MMLXXIX +CMLXIX +MMDCCCXLVIIII +DCLXII +MMMCCCXLVII +MDCCCXXXV +MMMMDCCXCVI +DCXXX +XXVI +MMLXIX +MMCXI +DCXXXVII +MMMMCCCXXXXVIII +MMMMDCLXI +MMMMDCLXXIIII +MMMMVIII +MMMMDCCCLXII +MDCXCI +MMCCCXXIIII +CCCCXXXXV +MMDCCCXXI +MCVI +MMDCCLXVIII +MMMMCXL +MLXVIII +CMXXVII +CCCLV +MDCCLXXXIX +MMMCCCCLXV +MMDCCLXII +MDLXVI +MMMCCCXVIII +MMMMCCLXXXI +MMCXXVII +MMDCCCLXVIII +MMMCXCII +MMMMDCLVIII +MMMMDCCCXXXXII +MMDCCCCLXXXXVI +MDCCXL +MDCCLVII +MMMMDCCCLXXXVI +DCCXXXIII +MMMMDCCCCLXXXV +MMCCXXXXVIII +MMMCCLXXVIII +MMMDCLXXVIII +DCCCI +MMMMLXXXXVIIII +MMMCCCCLXXII +MMCLXXXVII +CCLXVI +MCDXLIII +MMCXXVIII +MDXIV +CCCXCVIII +CLXXVIII +MMCXXXXVIIII +MMMDCLXXXIV +CMLVIII +MCDLIX +MMMMDCCCXXXII +MMMMDCXXXIIII +MDCXXI +MMMDCXLV +MCLXXVIII +MCDXXII +IV +MCDLXXXXIII +MMMMDCCLXV +CCLI +MMMMDCCCXXXVIII +DCLXII +MCCCLXVII +MMMMDCCCXXXVI +MMDCCXLI +MLXI +MMMCDLXVIII +MCCCCXCIII +XXXIII +MMMDCLXIII +MMMMDCL +DCCCXXXXIIII +MMDLVII +DXXXVII +MCCCCXXIIII +MCVII +MMMMDCCXL +MMMMCXXXXIIII +MCCCCXXIV +MMCLXVIII +MMXCIII +MDCCLXXX +MCCCLIIII +MMDCLXXI +MXI +MCMLIV +MMMCCIIII +DCCLXXXVIIII +MDCLIV +MMMDCXIX +CMLXXXI +DCCLXXXVII +XXV +MMMXXXVI +MDVIIII +CLXIII +MMMCDLVIIII +MMCCCCVII +MMMLXX +MXXXXII +MMMMCCCLXVIII +MMDCCCXXVIII +MMMMDCXXXXI +MMMMDCCCXXXXV +MMMXV +MMMMCCXVIIII +MMDCCXIIII +MMMXXVII +MDCCLVIIII +MMCXXIIII +MCCCLXXIV +DCLVIII +MMMLVII +MMMCXLV +MMXCVII +MMMCCCLXXXVII +MMMMCCXXII +DXII +MMMDLV +MCCCLXXVIII +MMMCLIIII +MMMMCLXXXX +MMMCLXXXIIII +MDCXXIII +MMMMCCXVI +MMMMDLXXXIII +MMMDXXXXIII +MMMMCCCCLV +MMMDLXXXI +MMMCCLXXVI +MMMMXX +MMMMDLVI +MCCCCLXXX +MMMXXII +MMXXII +MMDCCCCXXXI +MMMDXXV +MMMDCLXXXVIIII +MMMDLXXXXVII +MDLXIIII +CMXC +MMMXXXVIII +MDLXXXVIII +MCCCLXXVI +MMCDLIX +MMDCCCXVIII +MDCCCXXXXVI +MMMMCMIV +MMMMDCIIII +MMCCXXXV +XXXXVI +MMMMCCXVII +MMCCXXIV +MCMLVIIII +MLXXXIX +MMMMLXXXIX +CLXXXXIX +MMMDCCCCLVIII +MMMMCCLXXIII +MCCCC +DCCCLIX +MMMCCCLXXXII +MMMCCLXVIIII +MCLXXXV +CDLXXXVII +DCVI +MMX +MMCCXIII +MMMMDCXX +MMMMXXVIII +DCCCLXII +MMMMCCCXLIII +MMMMCLXV +DXCI +MMMMCLXXX +MMMDCCXXXXI +MMMMXXXXVI +DCLX +MMMCCCXI +MCCLXXX +MMCDLXXII +DCCLXXI +MMMCCCXXXVI +MCCCCLXXXVIIII +CDLVIII +DCCLVI +MMMMDCXXXVIII +MMCCCLXXXIII +MMMMDCCLXXV +MMMXXXVI +CCCLXXXXIX +CV +CCCCXIII +CCCCXVI +MDCCCLXXXIIII +MMDCCLXXXII +MMMMCCCCLXXXI +MXXV +MMCCCLXXVIIII +MMMCCXII +MMMMCCXXXIII +MMCCCLXXXVI +MMMDCCCLVIIII +MCCXXXVII +MDCLXXV +XXXV +MMDLI +MMMCCXXX +MMMMCXXXXV +CCCCLIX +MMMMDCCCLXXIII +MMCCCXVII +DCCCXVI +MMMCCCXXXXV +MDCCCCXCV +CLXXXI +MMMMDCCLXX +MMMDCCCIII +MMCLXXVII +MMMDCCXXIX +MMDCCCXCIIII +MMMCDXXIIII +MMMMXXVIII +MMMMDCCCCLXVIII +MDCCCXX +MMMMCDXXI +MMMMDLXXXIX +CCXVI +MDVIII +MMCCLXXI +MMMDCCCLXXI +MMMCCCLXXVI +MMCCLXI +MMMMDCCCXXXIV +DLXXXVI +MMMMDXXXII +MMMXXIIII +MMMMCDIV +MMMMCCCXLVIII +MMMMCXXXVIII +MMMCCCLXVI +MDCCXVIII +MMCXX +CCCLIX +MMMMDCCLXXII +MDCCCLXXV +MMMMDCCCXXIV +DCCCXXXXVIII +MMMDCCCCXXXVIIII +MMMMCCXXXV +MDCLXXXIII +MMCCLXXXIV +MCLXXXXIIII +DXXXXIII +MCCCXXXXVIII +MMCLXXIX +MMMMCCLXIV +MXXII +MMMCXIX +MDCXXXVII +MMDCCVI +MCLXXXXVIII +MMMCXVI +MCCCLX +MMMCDX +CCLXVIIII +MMMCCLX +MCXXVIII +LXXXII +MCCCCLXXXI +MMMI +MMMCCCLXIV +MMMCCCXXVIIII +CXXXVIII +MMCCCXX +MMMCCXXVIIII +MCCLXVI +MMMCCCCXXXXVI +MMDCCXCIX +MCMLXXI +MMCCLXVIII +CDLXXXXIII +MMMMDCCXXII +MMMMDCCLXXXVII +MMMDCCLIV +MMCCLXIII +MDXXXVII +DCCXXXIIII +MCII +MMMDCCCLXXI +MMMLXXIII +MDCCCLIII +MMXXXVIII +MDCCXVIIII +MDCCCCXXXVII +MMCCCXVI +MCMXXII +MMMCCCLVIII +MMMMDCCCXX +MCXXIII +MMMDLXI +MMMMDXXII +MDCCCX +MMDXCVIIII +MMMDCCCCVIII +MMMMDCCCCXXXXVI +MMDCCCXXXV +MMCXCIV +MCMLXXXXIII +MMMCCCLXXVI +MMMMDCLXXXV +CMLXIX +DCXCII +MMXXVIII +MMMMCCCXXX +XXXXVIIII \ No newline at end of file diff --git a/extra/project-euler/100/100.factor b/extra/project-euler/100/100.factor index 72584d833e..55a108aa68 100644 --- a/extra/project-euler/100/100.factor +++ b/extra/project-euler/100/100.factor @@ -5,19 +5,18 @@ IN: project-euler.100 ! http://projecteuler.net/index.php?section=problems&id=100 -! DESCRIPTION -! ----------- +! DESCRIPTION ! ----------- ! If a box contains twenty-one coloured discs, composed of fifteen blue discs -! and six red discs, and two discs were taken at random, it can be seen that -! the probability of taking two blue discs, P(BB) = (15/21)*(14/20) = 1/2. +! and six red discs, and two discs were taken at random, it can be seen that +! the probability of taking two blue discs, P(BB) = (15/21)*(14/20) = 1/2. ! The next such arrangement, for which there is exactly 50% chance of taking -! two blue discs at random, is a box containing eighty-five blue discs and -! thirty-five red discs. +! two blue discs at random, is a box containing eighty-five blue discs and +! thirty-five red discs. ! By finding the first arrangement to contain over 10^12 = 1,000,000,000,000 -! discs in total, determine the number of blue discs that the box would contain. +! discs in total, determine the number of blue discs that the box would contain. ! SOLUTION @@ -26,7 +25,7 @@ IN: project-euler.100 : euler100 ( -- answer ) 1 1 [ dup dup 1 - * 2 * 10 24 ^ <= ] - [ tuck 6 * swap - 2 - ] while nip ; + [ [ 6 * swap - 2 - ] keep swap ] while nip ; ! TODO: solution needs generalization diff --git a/extra/project-euler/117/117.factor b/extra/project-euler/117/117.factor index 0d4ec78226..60daa7224e 100644 --- a/extra/project-euler/117/117.factor +++ b/extra/project-euler/117/117.factor @@ -31,7 +31,7 @@ IN: project-euler.117 [ 4 short tail* sum ] keep push ; : (euler117) ( n -- m ) - V{ 1 } clone tuck [ next ] curry times last ; + [ V{ 1 } clone ] dip over [ next ] curry times last ; PRIVATE> diff --git a/extra/project-euler/150/150.factor b/extra/project-euler/150/150.factor index e6278a1e17..6e64d6ad30 100644 --- a/extra/project-euler/150/150.factor +++ b/extra/project-euler/150/150.factor @@ -55,9 +55,9 @@ IN: project-euler.150 :: (euler150) ( m -- n ) sums-triangle :> table - m [| x | - x 1 + [| y | - m x - [0,b) [| z | + m iota [| x | + x 1 + iota [| y | + m x - iota [| z | x z + table nth-unsafe [ y z + 1 + swap nth-unsafe ] [ y swap nth-unsafe ] bi - diff --git a/extra/project-euler/151/151.factor b/extra/project-euler/151/151.factor index ccdb76d80e..b8db55e886 100644 --- a/extra/project-euler/151/151.factor +++ b/extra/project-euler/151/151.factor @@ -62,7 +62,7 @@ DEFER: (euler151) { { 0 0 1 0 } [ { 0 0 0 1 } (euler151) 1 + ] } { { 0 1 0 0 } [ { 0 0 1 1 } (euler151) 1 + ] } { { 1 0 0 0 } [ { 0 1 1 1 } (euler151) 1 + ] } - [ [ dup length [ pick-sheet ] with map sum ] [ sum ] bi / ] + [ [ dup length iota [ pick-sheet ] with map sum ] [ sum ] bi / ] } case ] cache ; : euler151 ( -- answer ) diff --git a/extra/project-euler/164/164.factor b/extra/project-euler/164/164.factor index af8b7e49c0..be5d40df9b 100644 --- a/extra/project-euler/164/164.factor +++ b/extra/project-euler/164/164.factor @@ -18,7 +18,7 @@ IN: project-euler.164 ; : advance ( lag -- ) - [ { 0 31 } swap nths sum 1000000 rem ] keep push-circular ; + [ { 0 31 } swap nths sum 1000000 rem ] keep circular-push ; : next ( lag -- n ) [ first ] [ advance ] bi ; diff --git a/extra/project-euler/188/188-tests.factor b/extra/project-euler/188/188-tests.factor old mode 100755 new mode 100644 diff --git a/extra/project-euler/188/188.factor b/extra/project-euler/188/188.factor old mode 100755 new mode 100644 diff --git a/extra/project-euler/ave-time/ave-time-docs.factor b/extra/project-euler/ave-time/ave-time-docs.factor index f2d6b89afc..1fb41b61c0 100644 --- a/extra/project-euler/ave-time/ave-time-docs.factor +++ b/extra/project-euler/ave-time/ave-time-docs.factor @@ -9,14 +9,6 @@ HELP: collect-benchmarks $nl "A nicer word for interactive use is " { $link ave-time } "." } ; -HELP: nth-place -{ $values { "x" float } { "n" integer } { "y" float } } -{ $description "Rounds a floating point number to " { $snippet "n" } " decimal places." } -{ $examples - "This word is useful for display purposes when showing 15 decimal places is not desired:" - { $unchecked-example "3.141592653589793 3 nth-place number>string" "\"3.142\"" } -} ; - HELP: ave-time { $values { "quot" quotation } { "n" integer } } { $description "Runs a quotation " { $snippet "n" } " times, then prints the average run time and standard deviation." } diff --git a/extra/project-euler/ave-time/ave-time-tests.factor b/extra/project-euler/ave-time/ave-time-tests.factor new file mode 100644 index 0000000000..86b0048968 --- /dev/null +++ b/extra/project-euler/ave-time/ave-time-tests.factor @@ -0,0 +1,5 @@ +IN: project-euler.ave-time.tests +USING: tools.test math arrays project-euler.ave-time ; + +{ 0 3 } [ 1 2 [ + ] 10 collect-benchmarks ] must-infer-as +[ 1 2 t ] [ 1 2 [ + ] 10 collect-benchmarks array? ] unit-test diff --git a/extra/project-euler/ave-time/ave-time.factor b/extra/project-euler/ave-time/ave-time.factor index dc521d4d70..ec190fed18 100644 --- a/extra/project-euler/ave-time/ave-time.factor +++ b/extra/project-euler/ave-time/ave-time.factor @@ -1,24 +1,16 @@ ! Copyright (c) 2007, 2008 Aaron Schaefer. ! See http://factorcode.org/license.txt for BSD license. -USING: continuations fry io kernel make math math.functions -math.parser math.statistics memory tools.time ; +USING: combinators.smart formatting fry io kernel macros math +math.functions math.statistics memory sequences tools.time ; IN: project-euler.ave-time -: nth-place ( x n -- y ) - 10^ [ * round >integer ] keep /f ; - -: collect-benchmarks ( quot n -- seq ) - [ - [ datastack ] - [ - '[ _ gc benchmark 1000 / , ] tuck - '[ _ _ with-datastack drop ] - ] - [ 1 - ] tri* swap times call - ] { } make ; inline +MACRO: collect-benchmarks ( quot n -- seq ) + swap '[ _ [ [ [ _ nullary ] preserving ] gc benchmark 1000 / ] replicate ] ; : ave-time ( quot n -- ) - [ collect-benchmarks ] keep swap - [ std 2 nth-place ] [ mean round >integer ] bi [ - # " ms ave run time - " % # " SD (" % # " trials)" % - ] "" make print flush ; inline + [ + collect-benchmarks + [ mean round >integer ] + [ std ] bi + ] keep + "%d ms ave run time - %.2f SD (%d trials)\n" printf flush ; inline diff --git a/extra/project-euler/common/common.factor b/extra/project-euler/common/common.factor index 9eb9e968ca..a84f4fa48b 100644 --- a/extra/project-euler/common/common.factor +++ b/extra/project-euler/common/common.factor @@ -39,7 +39,7 @@ IN: project-euler.common > [ leaf-insert ] [ node-insert ] if ; -: leaf-at-point ( point leaf -- value/f ? ) - tuck point>> = [ value>> t ] [ drop f f ] if ; +:: leaf-at-point ( point leaf -- value/f ? ) + point leaf point>> = + [ leaf value>> t ] [ f f ] if ; : node-at-point ( point node -- value/f ? ) descend at-point ; @@ -103,15 +104,15 @@ DEFER: in-rect* : node-in-rect* ( values rect node -- values ) [ (node-in-rect*) ] with each-quadrant ; -: leaf-in-rect* ( values rect leaf -- values ) - tuck { [ nip point>> ] [ point>> swap contains-point? ] } 2&& - [ value>> over push ] [ drop ] if ; +:: leaf-in-rect* ( values rect leaf -- values ) + { [ leaf point>> ] [ leaf point>> rect contains-point? ] } 0&& + [ values leaf value>> suffix! ] [ values ] if ; : in-rect* ( values rect tree -- values ) dup leaf?>> [ leaf-in-rect* ] [ node-in-rect* ] if ; -: leaf-erase ( point leaf -- ) - tuck point>> = [ f >>point f >>value ] when drop ; +:: leaf-erase ( point leaf -- ) + point leaf point>> = [ leaf f >>point f >>value drop ] when ; : node-erase ( point node -- ) descend erase ; diff --git a/extra/random/blum-blum-shub/blum-blum-shub-tests.factor b/extra/random/blum-blum-shub/blum-blum-shub-tests.factor index 4b0dee642e..0a397ddc6d 100644 --- a/extra/random/blum-blum-shub/blum-blum-shub-tests.factor +++ b/extra/random/blum-blum-shub/blum-blum-shub-tests.factor @@ -22,7 +22,7 @@ IN: blum-blum-shub.tests [ 3716213681 ] [ - 100 T{ blum-blum-shub f 200352954495 846054538649 } clone tuck [ + T{ blum-blum-shub f 200352954495 846054538649 } clone 100 over [ random-32* drop ] curry times random-32* diff --git a/extra/random/blum-blum-shub/blum-blum-shub.factor b/extra/random/blum-blum-shub/blum-blum-shub.factor old mode 100755 new mode 100644 diff --git a/extra/redis/redis.factor b/extra/redis/redis.factor index 466fdc9937..51d0c21a94 100644 --- a/extra/redis/redis.factor +++ b/extra/redis/redis.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2009 Bruno Deferrari ! See http://factorcode.org/license.txt for BSD license. -USING: accessors io io.encodings.8-bit io.sockets -io.streams.duplex kernel redis.command-writer -redis.response-parser splitting ; +USING: accessors io io.sockets io.streams.duplex kernel +redis.command-writer redis.response-parser splitting +io.encodings.8-bit.latin1 ; IN: redis #! Connection diff --git a/extra/reports/noise/noise.factor b/extra/reports/noise/noise.factor old mode 100755 new mode 100644 index 9eb2804b42..cc6c9ee33f --- a/extra/reports/noise/noise.factor +++ b/extra/reports/noise/noise.factor @@ -49,15 +49,12 @@ IN: reports.noise { nkeep 5 } { npick 6 } { nrot 5 } - { ntuck 6 } { nwith 4 } { over 2 } { pick 4 } { rot 3 } - { spin 3 } { swap 1 } { swapd 3 } - { tuck 2 } { with 1/2 } { bi 1/2 } diff --git a/extra/rot13/rot13.factor b/extra/rot13/rot13.factor index 6663381522..c8f08bcf30 100644 --- a/extra/rot13/rot13.factor +++ b/extra/rot13/rot13.factor @@ -3,7 +3,7 @@ USING: kernel math sequences strings io combinators ascii ; IN: rot13 -: rotate ( ch base -- ch ) tuck - 13 + 26 mod + ; +: rotate ( ch base -- ch ) [ - 13 + 26 mod ] [ + ] bi ; : rot-letter ( ch -- ch ) { diff --git a/extra/s3/s3-docs.factor b/extra/s3/s3-docs.factor index dda3e7f200..6f9c10010d 100644 --- a/extra/s3/s3-docs.factor +++ b/extra/s3/s3-docs.factor @@ -108,13 +108,14 @@ $nl "To use the api you must set the variables " { $link key-id } " and " { $link secret-key } " to your Amazon S3 key and secret key respectively. Once " "this is done you can call any of the words below." -{ $subsection buckets } -{ $subsection create-bucket } -{ $subsection delete-bucket } -{ $subsection keys } -{ $subsection get-object } -{ $subsection put-object } -{ $subsection delete-object } +{ $subsections buckets + create-bucket + delete-bucket + keys + get-object + put-object + delete-object +} ; -ABOUT: "s3" \ No newline at end of file +ABOUT: "s3" diff --git a/extra/sequences/abbrev/abbrev.factor b/extra/sequences/abbrev/abbrev.factor index 6770a48a3a..2dc2247783 100644 --- a/extra/sequences/abbrev/abbrev.factor +++ b/extra/sequences/abbrev/abbrev.factor @@ -12,7 +12,7 @@ IN: sequences.abbrev [ prefixes ] keep 1array '[ _ ] H{ } map>assoc ; : assoc-merge ( assoc1 assoc2 -- assoc3 ) - tuck '[ over _ at dup [ append ] [ drop ] if ] assoc-map assoc-union ; + [ '[ over _ at dup [ append ] [ drop ] if ] assoc-map ] keep swap assoc-union ; PRIVATE> diff --git a/extra/sequences/modified/modified.factor b/extra/sequences/modified/modified.factor index d552f2dc77..73fcc651bd 100644 --- a/extra/sequences/modified/modified.factor +++ b/extra/sequences/modified/modified.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. -USING: accessors arrays kernel math math.order +USING: accessors arrays kernel locals math math.order sequences sequences.private shuffle ; IN: sequences.modified @@ -21,7 +21,7 @@ TUPLE: 1modified < modified seq ; M: modified length seq>> length ; M: modified set-length seq>> set-length ; -M: 1modified virtual-seq seq>> ; +M: 1modified virtual-exemplar seq>> ; TUPLE: scaled < 1modified c ; C: scaled @@ -32,9 +32,9 @@ C: scaled M: scaled modified-nth ( n seq -- elt ) [ seq>> nth ] [ c>> * ] bi ; -M: scaled modified-set-nth ( elt n seq -- elt ) +M:: scaled modified-set-nth ( elt n seq -- elt ) ! don't set c to 0! - tuck [ c>> / ] 2dip seq>> set-nth ; + elt seq c>> / n seq seq>> set-nth ; TUPLE: offset < 1modified n ; C: offset @@ -45,8 +45,8 @@ C: offset M: offset modified-nth ( n seq -- elt ) [ seq>> nth ] [ n>> + ] bi ; -M: offset modified-set-nth ( elt n seq -- ) - tuck [ n>> - ] 2dip seq>> set-nth ; +M:: offset modified-set-nth ( elt n seq -- ) + elt seq n>> - n seq seq>> set-nth ; TUPLE: summed < modified seqs ; C: summed @@ -71,7 +71,8 @@ M: summed modified-set-nth ( elt n seq -- ) immutable ; M: summed set-length ( n seq -- ) seqs>> [ set-length ] with each ; -M: summed virtual-seq ( summed -- seq ) [ ] { } map-as ; +M: summed virtual-exemplar ( summed -- seq ) + seqs>> [ f ] [ first ] if-empty ; : <2summed> ( seq seq -- summed-seq ) 2array ; : <3summed> ( seq seq seq -- summed-seq ) 3array ; diff --git a/extra/sequences/repeating/repeating.factor b/extra/sequences/repeating/repeating.factor index 77fddd5510..7157e3f025 100644 --- a/extra/sequences/repeating/repeating.factor +++ b/extra/sequences/repeating/repeating.factor @@ -16,6 +16,6 @@ M: repeating set-length (>>len) ; M: repeating virtual@ ( n seq -- n' seq' ) circular>> ; -M: repeating virtual-seq circular>> ; +M: repeating virtual-exemplar circular>> ; INSTANCE: repeating virtual-sequence diff --git a/extra/set-n/set-n.factor b/extra/set-n/set-n.factor index 04731b0e27..80d8bf2246 100644 --- a/extra/set-n/set-n.factor +++ b/extra/set-n/set-n.factor @@ -1,9 +1,9 @@ -USING: accessors assocs fry generalizations kernel math -namespaces parser sequences words ; +USING: accessors assocs fry generalizations kernel locals math +namespaces parser sequences shuffle words ; IN: set-n : get* ( var n -- val ) namestack dup length rot - head assoc-stack ; : set* ( val var n -- ) 1 + namestack [ length swap - ] keep nth set-at ; ! dynamic lambda -SYNTAX: :| (:) dup in>> dup length [ spin '[ _ narray _ swap zip _ bind ] ] 2curry dip define-declared ; \ No newline at end of file +SYNTAX: :| (:) dup in>> dup length [ spin '[ _ narray _ swap zip _ bind ] ] 2curry dip define-declared ; diff --git a/extra/site-watcher/site-watcher.factor b/extra/site-watcher/site-watcher.factor index 535c8cd626..dcae438679 100644 --- a/extra/site-watcher/site-watcher.factor +++ b/extra/site-watcher/site-watcher.factor @@ -10,7 +10,7 @@ SYMBOL: site-watcher-frequency 5 minutes site-watcher-frequency set-global SYMBOL: running-site-watcher -[ f running-site-watcher set-global ] "site-watcher" add-init-hook +[ f running-site-watcher set-global ] "site-watcher" add-startup-hook > ] [ out>> ] bi ; + test-compilation infer [ in>> ] [ out>> ] bi [ length ] bi@ ; [ 2 1 ] [ T{ ast-block f diff --git a/extra/smalltalk/selectors/selectors.factor b/extra/smalltalk/selectors/selectors.factor index 2ea1e99afd..6094986345 100644 --- a/extra/smalltalk/selectors/selectors.factor +++ b/extra/smalltalk/selectors/selectors.factor @@ -1,6 +1,6 @@ -! Copyright (C) 2009 Slava Pestov. +! Copyright (C) 2009, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: combinators effects generic generic.standard +USING: arrays combinators effects generic generic.standard kernel sequences words lexer ; IN: smalltalk.selectors @@ -15,9 +15,9 @@ SYMBOLS: unary binary keyword ; : selector>effect ( selector -- effect ) dup selector-type { - { unary [ drop 0 ] } - { binary [ drop 1 ] } - { keyword [ [ CHAR: : = ] count ] } + { unary [ drop { } ] } + { binary [ drop { "x" } ] } + { keyword [ [ CHAR: : = ] count "x" ] } } case "receiver" suffix { "result" } ; : selector>generic ( selector -- generic ) diff --git a/extra/space-invaders/space-invaders.factor b/extra/space-invaders/space-invaders.factor old mode 100755 new mode 100644 index 07b5608a76..17e277fb6a --- a/extra/space-invaders/space-invaders.factor +++ b/extra/space-invaders/space-invaders.factor @@ -14,7 +14,9 @@ USING: io.files io.pathnames kernel + locals math + math.order openal opengl.gl sequences @@ -40,12 +42,11 @@ CONSTANT: game-height 256 #! Point is a {x y}. first2 game-width 3 * * swap 3 * + ; -: set-bitmap-pixel ( color point array -- ) - #! 'color' is a {r g b}. Point is {x y}. - [ bitmap-index ] dip ! color index array - [ [ first ] 2dip set-nth ] 3keep - [ [ second ] 2dip [ 1 + ] dip set-nth ] 3keep - [ third ] 2dip [ 2 + ] dip set-nth ; +:: set-bitmap-pixel ( bitmap point color -- ) + point bitmap-index :> index + color first index bitmap set-nth + color second index 1 + bitmap set-nth + color third index 2 + bitmap set-nth ; : get-bitmap-pixel ( point array -- color ) #! Point is a {x y}. color is a {r g b} @@ -71,16 +72,16 @@ CONSTANT: SOUND-UFO-HIT 8 : init-sounds ( cpu -- ) init-openal [ 9 gen-sources swap (>>sounds) ] keep - [ SOUND-SHOT "resource:extra/space-invaders/resources/Shot.wav" init-sound ] keep - [ SOUND-UFO "resource:extra/space-invaders/resources/Ufo.wav" init-sound ] keep + [ SOUND-SHOT "vocab:space-invaders/resources/Shot.wav" init-sound ] keep + [ SOUND-UFO "vocab:space-invaders/resources/Ufo.wav" init-sound ] keep [ sounds>> SOUND-UFO swap nth AL_LOOPING AL_TRUE set-source-param ] keep - [ SOUND-BASE-HIT "resource:extra/space-invaders/resources/BaseHit.wav" init-sound ] keep - [ SOUND-INVADER-HIT "resource:extra/space-invaders/resources/InvHit.Wav" init-sound ] keep - [ SOUND-WALK1 "resource:extra/space-invaders/resources/Walk1.wav" init-sound ] keep - [ SOUND-WALK2 "resource:extra/space-invaders/resources/Walk2.wav" init-sound ] keep - [ SOUND-WALK3 "resource:extra/space-invaders/resources/Walk3.wav" init-sound ] keep - [ SOUND-WALK4 "resource:extra/space-invaders/resources/Walk4.wav" init-sound ] keep - [ SOUND-UFO-HIT "resource:extra/space-invaders/resources/UfoHit.wav" init-sound ] keep + [ SOUND-BASE-HIT "vocab:space-invaders/resources/BaseHit.wav" init-sound ] keep + [ SOUND-INVADER-HIT "vocab:space-invaders/resources/InvHit.Wav" init-sound ] keep + [ SOUND-WALK1 "vocab:space-invaders/resources/Walk1.wav" init-sound ] keep + [ SOUND-WALK2 "vocab:space-invaders/resources/Walk2.wav" init-sound ] keep + [ SOUND-WALK3 "vocab:space-invaders/resources/Walk3.wav" init-sound ] keep + [ SOUND-WALK4 "vocab:space-invaders/resources/Walk4.wav" init-sound ] keep + [ SOUND-UFO-HIT "vocab:space-invaders/resources/UfoHit.wav" init-sound ] keep f swap (>>looping?) ; : cpu-init ( cpu -- cpu ) @@ -139,8 +140,8 @@ M: space-invaders read-port ( port cpu -- byte ) #! Setting this value affects the value read from port 3 (>>port2o) ; -: bit-newly-set? ( old-value new-value bit -- bool ) - tuck bit? [ bit? not ] dip and ; +:: bit-newly-set? ( old-value new-value bit -- bool ) + new-value bit bit? [ old-value bit bit? not ] dip and ; : port3-newly-set? ( new-value cpu bit -- bool ) [ port3o>> swap ] dip bit-newly-set? ; @@ -317,19 +318,15 @@ CONSTANT: red { 255 0 0 } : plot-bitmap-pixel ( bitmap point color -- ) #! point is a {x y}. color is a {r g b}. - spin set-bitmap-pixel ; - -: within ( n a b -- bool ) - #! n >= a and n <= b - rot tuck swap <= [ swap >= ] dip and ; + set-bitmap-pixel ; : get-point-color ( point -- color ) #! Return the color to use for the given x/y position. first2 { - { [ dup 184 238 within pick 0 223 within and ] [ 2drop green ] } - { [ dup 240 247 within pick 16 133 within and ] [ 2drop green ] } - { [ dup 247 215 - 247 184 - within pick 0 223 within and ] [ 2drop red ] } + { [ dup 184 238 between? pick 0 223 between? and ] [ 2drop green ] } + { [ dup 240 247 between? pick 16 133 between? and ] [ 2drop green ] } + { [ dup 247 215 - 247 184 - between? pick 0 223 between? and ] [ 2drop red ] } [ 2drop white ] } cond ; @@ -359,12 +356,12 @@ M: space-invaders update-video ( value addr cpu -- ) 3drop ] if ; -: sync-frame ( millis -- millis ) +: sync-frame ( micros -- micros ) #! Sleep until the time for the next frame arrives. - 1000 60 / >fixnum + system:millis - dup 0 > - [ milliseconds threads:sleep ] [ drop threads:yield ] if system:millis ; + 1000 60 / >fixnum + system:system-micros - dup 0 > + [ milliseconds threads:sleep ] [ drop threads:yield ] if system:system-micros ; -: invaders-process ( millis gadget -- ) +: invaders-process ( micros gadget -- ) #! Run a space invaders gadget inside a #! concurrent process. Messages can be sent to #! signal key presses, etc. @@ -380,7 +377,7 @@ M: space-invaders update-video ( value addr cpu -- ) M: invaders-gadget graft* ( gadget -- ) dup cpu>> init-sounds f over (>>quit?) - [ system:millis swap invaders-process ] curry + [ system:system-micros swap invaders-process ] curry "Space invaders" threads:spawn drop ; M: invaders-gadget ungraft* ( gadget -- ) diff --git a/extra/spheres/spheres.factor b/extra/spheres/spheres.factor old mode 100755 new mode 100644 index b7431caef8..819dbe892e --- a/extra/spheres/spheres.factor +++ b/extra/spheres/spheres.factor @@ -196,9 +196,6 @@ M: spheres-world end-world [ plane-program>> [ delete-gl-program ] when* ] } cleave ; -M: spheres-world pref-dim* - drop { 640 480 } ; - :: (draw-sphere) ( program center radius -- ) program "center" glGetAttribLocation center first3 glVertexAttrib3f program "radius" glGetAttribLocation radius glVertexAttrib1f @@ -299,17 +296,13 @@ M: spheres-world draw-world* ] } cleave ; -: spheres-window ( -- ) - [ - f T{ world-attributes - { world-class spheres-world } - { title "Spheres" } - { pixel-format-attributes { - windowed - double-buffered - T{ depth-bits { value 16 } } - } } - } open-window - ] with-ui ; - -MAIN: spheres-window +MAIN-WINDOW: spheres-window { + { world-class spheres-world } + { title "Spheres" } + { pixel-format-attributes { + windowed + double-buffered + T{ depth-bits { value 16 } } + } } + { pref-dim { 640 480 } } + } ; diff --git a/extra/spider/spider.factor b/extra/spider/spider.factor index 4ce998294b..c8ea4734d2 100644 --- a/extra/spider/spider.factor +++ b/extra/spider/spider.factor @@ -57,7 +57,7 @@ fetched-in parsed-html links processed-in fetched-at ; [ filter-base-links ] 2keep depth>> 1 + swap [ add-nonmatching ] - [ tuck [ apply-filters ] 2dip add-todo ] 2bi ; + [ dup '[ _ apply-filters ] curry 2dip add-todo ] 2bi ; : normalize-hrefs ( base links -- links' ) [ derive-url ] with map ; diff --git a/extra/spider/unique-deque/unique-deque.factor b/extra/spider/unique-deque/unique-deque.factor index 9003b56b15..f660674b63 100644 --- a/extra/spider/unique-deque/unique-deque.factor +++ b/extra/spider/unique-deque/unique-deque.factor @@ -30,7 +30,7 @@ TUPLE: unique-deque assoc deque ; : peek-url ( unique-deque -- todo-url ) deque>> peek-front ; -:: slurp-deque-when ( deque quot1 quot2: ( value -- ) -- ) +:: slurp-deque-when ( deque quot1: ( value -- ) quot2: ( value -- ) -- ) deque deque-empty? [ deque pop-front dup quot1 call [ quot2 call t ] [ drop f ] if diff --git a/extra/sudoku/deploy.factor b/extra/sudoku/deploy.factor old mode 100755 new mode 100644 diff --git a/extra/sudoku/sudoku-tests.factor b/extra/sudoku/sudoku-tests.factor new file mode 100644 index 0000000000..60babf03a0 --- /dev/null +++ b/extra/sudoku/sudoku-tests.factor @@ -0,0 +1,4 @@ +IN: sudoku.tests +USING: tools.test sudoku ; + +[ ] [ sudoku-demo ] unit-test diff --git a/extra/sudoku/sudoku.factor b/extra/sudoku/sudoku.factor old mode 100755 new mode 100644 index 555f1e632a..848d647fe0 --- a/extra/sudoku/sudoku.factor +++ b/extra/sudoku/sudoku.factor @@ -19,7 +19,7 @@ SYMBOL: board : box-any? ( n x y -- ? ) [ 3 /i 3 * ] bi@ - 9 [ [ 3dup ] dip cell-any? ] any? + 9 iota [ [ 3dup ] dip cell-any? ] any? [ 3drop ] dip ; DEFER: search @@ -35,7 +35,7 @@ DEFER: search [ assume ] } cond ; -: solve ( x y -- ) 9 [ 1 + 2over attempt ] each 2drop ; +: solve ( x y -- ) 9 [ 1 + 2over attempt ] each-integer 2drop ; : board. ( board -- ) standard-table-style [ @@ -52,7 +52,7 @@ DEFER: search ] each ] with-row ] each - ] tabular-output ; + ] tabular-output nl ; : solution. ( -- ) solutions inc "Solution:" print board get board. ; diff --git a/extra/tar/tar.factor b/extra/tar/tar.factor old mode 100755 new mode 100644 diff --git a/extra/taxes/usa/fica/fica.factor b/extra/taxes/usa/fica/fica.factor index 251f60e6d7..4541a15eca 100644 --- a/extra/taxes/usa/fica/fica.factor +++ b/extra/taxes/usa/fica/fica.factor @@ -9,6 +9,7 @@ ERROR: fica-base-unknown ; : fica-base-rate ( year -- x ) H{ + { 2009 106800 } { 2008 102000 } { 2007 97500 } } at [ fica-base-unknown ] unless* ; diff --git a/extra/terrain/generation/generation.factor b/extra/terrain/generation/generation.factor index 86f532bada..3ed4af3b1d 100644 --- a/extra/terrain/generation/generation.factor +++ b/extra/terrain/generation/generation.factor @@ -3,7 +3,6 @@ combinators.smart fry grouping images kernel math math.matrices.simd math.order math.vectors noise random sequences math.vectors.simd typed ; FROM: alien.c-types => float uchar ; -SIMDS: float uchar ; IN: terrain.generation CONSTANT: terrain-segment-size { 512 512 } diff --git a/extra/terrain/terrain.factor b/extra/terrain/terrain.factor index f1da877c3e..27bd7df403 100644 --- a/extra/terrain/terrain.factor +++ b/extra/terrain/terrain.factor @@ -6,12 +6,11 @@ math.vectors opengl opengl.capabilities opengl.gl opengl.shaders opengl.textures opengl.textures.private sequences sequences.product specialized-arrays terrain.generation terrain.shaders typed ui ui.gadgets -ui.gadgets.worlds ui.pixel-formats game.worlds method-chains +ui.gadgets.worlds ui.pixel-formats game.worlds math.matrices.simd noise ui.gestures combinators.short-circuit destructors grid-meshes math.vectors.simd ; QUALIFIED-WITH: alien.c-types c SPECIALIZED-ARRAY: c:float -SIMD: c:float IN: terrain CONSTANT: FOV $[ 2.0 sqrt 1 + ] @@ -22,14 +21,14 @@ CONSTANT: VELOCITY-MODIFIER-NORMAL float-4{ 1.0 1.0 1.0 0.0 } CONSTANT: VELOCITY-MODIFIER-FAST float-4{ 2.0 1.0 2.0 0.0 } CONSTANT: BOUNCE float-4{ 1.0 -0.2 1.0 1.0 } CONSTANT: PLAYER-HEIGHT 1/256. -CONSTANT: GRAVITY float-4{ 0.0 -1/4096. 0.0 0.0 } -CONSTANT: JUMP 1/1024. -CONSTANT: MOUSE-SCALE 1/10. -CONSTANT: MOVEMENT-SPEED 1/16384. -CONSTANT: FRICTION float-4{ 0.95 0.99 0.95 1.0 } +CONSTANT: GRAVITY float-4{ 0.0 -1/8192. 0.0 0.0 } +CONSTANT: JUMP 1/2048. +CONSTANT: MOUSE-SCALE 1/20. +CONSTANT: MOVEMENT-SPEED 1/32768. +CONSTANT: FRICTION float-4{ 0.97 0.995 0.97 1.0 } CONSTANT: COMPONENT-SCALE float-4{ 0.5 0.01 0.0005 0.0 } -CONSTANT: SKY-PERIOD 1200 -CONSTANT: SKY-SPEED 0.0005 +CONSTANT: SKY-PERIOD 2400 +CONSTANT: SKY-SPEED 0.00025 CONSTANT: terrain-vertex-size { 512 512 } @@ -56,9 +55,6 @@ TUPLE: terrain-world < game-world float-4{ 0.0 0.0 0.0 1.0 } >>velocity VELOCITY-MODIFIER-NORMAL >>velocity-modifier ; -M: terrain-world tick-length - drop 1000 30 /i ; - : frustum ( dim -- -x x -y y near far ) dup first2 min v/n NEAR-PLANE FOV / v*n first2 [ [ neg ] keep ] bi@ @@ -221,7 +217,7 @@ terrain-world H{ [ tick-player-reverse ] [ tick-player-forward ] if ; -M: terrain-world tick* +M: terrain-world tick-game-world [ dup focused?>> [ handle-input ] [ drop ] if ] [ dup player>> tick-player ] bi ; @@ -237,7 +233,7 @@ M: terrain-world tick* : sky-theta ( world -- theta ) game-loop>> tick-number>> SKY-SPEED * ; -BEFORE: terrain-world begin-world +M: terrain-world begin-game-world "2.0" { "GL_ARB_vertex_buffer_object" "GL_ARB_shader_objects" } require-gl-version-or-extensions GL_DEPTH_TEST glEnable @@ -258,7 +254,7 @@ BEFORE: terrain-world begin-world terrain-vertex-size >>terrain-mesh drop ; -AFTER: terrain-world end-world +M: terrain-world end-game-world { [ terrain-mesh>> dispose ] [ terrain-program>> delete-gl-program ] @@ -291,20 +287,16 @@ M: terrain-world draw-world* ] with-gl-program ] } cleave gl-error ; -M: terrain-world pref-dim* drop { 1024 768 } ; - -: terrain-window ( -- ) - [ - f T{ world-attributes - { world-class terrain-world } - { title "Terrain" } - { pixel-format-attributes { - windowed - double-buffered - T{ depth-bits { value 24 } } - } } - { grab-input? t } - } open-window - ] with-ui ; - -MAIN: terrain-window +GAME: terrain-game { + { world-class terrain-world } + { title "Terrain" } + { pixel-format-attributes { + windowed + double-buffered + T{ depth-bits { value 24 } } + } } + { use-game-input? t } + { grab-input? t } + { pref-dim { 1024 768 } } + { tick-interval-micros $[ 60 fps ] } + } ; diff --git a/extra/tetris/board/board.factor b/extra/tetris/board/board.factor index 1f12dcabe6..2346999bcb 100644 --- a/extra/tetris/board/board.factor +++ b/extra/tetris/board/board.factor @@ -6,7 +6,7 @@ IN: tetris.board TUPLE: board { width integer } { height integer } rows ; : make-rows ( width height -- rows ) - [ drop f ] with map ; + iota [ drop f ] with map ; : ( width height -- board ) 2dup make-rows board boa ; @@ -24,8 +24,8 @@ TUPLE: board { width integer } { height integer } rows ; : block-free? ( board block -- ? ) block not ; : block-in-bounds? ( board block -- ? ) - [ first swap width>> bounds-check? ] 2keep - second swap height>> bounds-check? and ; + [ first swap width>> iota bounds-check? ] + [ second swap height>> iota bounds-check? ] 2bi and ; : location-valid? ( board block -- ? ) 2dup block-in-bounds? [ block-free? ] [ 2drop f ] if ; diff --git a/extra/tetris/deploy.factor b/extra/tetris/deploy.factor old mode 100755 new mode 100644 diff --git a/extra/tetris/game/game.factor b/extra/tetris/game/game.factor index e1b5867f64..a45e655131 100644 --- a/extra/tetris/game/game.factor +++ b/extra/tetris/game/game.factor @@ -35,10 +35,10 @@ CONSTANT: default-height 20 rows>> 1 + 10 / ceiling ; : update-interval ( tetris -- interval ) - level>> 1 - 60 * 1000 swap - ; + level>> 1 - 60 * 1000000 swap - ; : add-block ( tetris block -- ) - over board>> spin current-piece tetromino>> colour>> set-block ; + over [ board>> ] 2dip current-piece tetromino>> colour>> set-block ; : game-over? ( tetris -- ? ) [ board>> ] [ next-piece ] bi piece-valid? not ; @@ -104,10 +104,10 @@ CONSTANT: default-height 20 dup { 0 1 } tetris-move [ move-drop ] [ lock-piece ] if ; : update ( tetris -- ) - millis over last-update>> - + system-micros over last-update>> - over update-interval > [ dup move-down - millis >>last-update + system-micros >>last-update ] when drop ; : ?update ( tetris -- ) diff --git a/extra/tetris/gl/gl.factor b/extra/tetris/gl/gl.factor index 0169249e81..8326da3584 100644 --- a/extra/tetris/gl/gl.factor +++ b/extra/tetris/gl/gl.factor @@ -26,10 +26,10 @@ IN: tetris.gl [ gl-color 2array draw-block ] [ 3drop ] if ; : draw-row ( y row -- ) - dup length -rot [ (draw-row) ] 2curry each ; + [ length iota swap ] keep [ (draw-row) ] 2curry each ; : draw-board ( board -- ) - rows>> dup length swap + rows>> [ length iota ] keep [ dupd nth draw-row ] curry each ; : scale-board ( width height board -- ) diff --git a/extra/tetris/piece/piece.factor b/extra/tetris/piece/piece.factor index 2ebbfc07d6..0a24b2033c 100644 --- a/extra/tetris/piece/piece.factor +++ b/extra/tetris/piece/piece.factor @@ -37,7 +37,7 @@ TUPLE: piece : modulo ( n m -- n ) #! -2 7 mod => -2, -2 7 modulo => 5 - tuck mod over + swap mod ; + [ mod ] [ + ] [ mod ] tri ; : (rotate-piece) ( rotation inc n-states -- rotation' ) [ + ] dip modulo ; diff --git a/extra/tetris/tetris.factor b/extra/tetris/tetris.factor index dbdb666e4a..66df0cdb2d 100644 --- a/extra/tetris/tetris.factor +++ b/extra/tetris/tetris.factor @@ -13,8 +13,9 @@ M: tetris-gadget pref-dim* drop { 200 400 } ; : update-status ( gadget -- ) dup tetris>> [ - "Level: " % dup level>> # - " Score: " % score>> # + [ "Level: " % level>> # ] + [ " Score: " % score>> # ] + [ paused?>> [ " (Paused)" % ] when ] tri ] "" make swap show-status ; M: tetris-gadget draw-gadget* ( gadget -- ) @@ -25,17 +26,24 @@ M: tetris-gadget draw-gadget* ( gadget -- ) : new-tetris ( gadget -- gadget ) [ ] change-tetris ; +: unless-paused ( tetris quot -- ) + over tetris>> paused?>> [ + 2drop + ] [ + call + ] if ; inline + tetris-gadget H{ { T{ button-down f f 1 } [ request-focus ] } - { T{ key-down f f "UP" } [ tetris>> rotate-right ] } - { T{ key-down f f "d" } [ tetris>> rotate-left ] } - { T{ key-down f f "f" } [ tetris>> rotate-right ] } - { T{ key-down f f "e" } [ tetris>> rotate-left ] } ! dvorak d - { T{ key-down f f "u" } [ tetris>> rotate-right ] } ! dvorak f - { T{ key-down f f "LEFT" } [ tetris>> move-left ] } - { T{ key-down f f "RIGHT" } [ tetris>> move-right ] } - { T{ key-down f f "DOWN" } [ tetris>> move-down ] } - { T{ key-down f f " " } [ tetris>> move-drop ] } + { T{ key-down f f "UP" } [ [ tetris>> rotate-right ] unless-paused ] } + { T{ key-down f f "d" } [ [ tetris>> rotate-left ] unless-paused ] } + { T{ key-down f f "f" } [ [ tetris>> rotate-right ] unless-paused ] } + { T{ key-down f f "e" } [ [ tetris>> rotate-left ] unless-paused ] } + { T{ key-down f f "u" } [ [ tetris>> rotate-right ] unless-paused ] } + { T{ key-down f f "LEFT" } [ [ tetris>> move-left ] unless-paused ] } + { T{ key-down f f "RIGHT" } [ [ tetris>> move-right ] unless-paused ] } + { T{ key-down f f "DOWN" } [ [ tetris>> move-down ] unless-paused ] } + { T{ key-down f f " " } [ [ tetris>> move-drop ] unless-paused ] } { T{ key-down f f "p" } [ tetris>> toggle-pause ] } { T{ key-down f f "n" } [ new-tetris drop ] } } set-gestures diff --git a/extra/tokyo/alien/tcbdb/tcbdb.factor b/extra/tokyo/alien/tcbdb/tcbdb.factor old mode 100755 new mode 100644 diff --git a/extra/tokyo/alien/tcfdb/tcfdb.factor b/extra/tokyo/alien/tcfdb/tcfdb.factor old mode 100755 new mode 100644 diff --git a/extra/tokyo/alien/tchdb/tchdb.factor b/extra/tokyo/alien/tchdb/tchdb.factor old mode 100755 new mode 100644 diff --git a/extra/tokyo/alien/tcrdb/tcrdb.factor b/extra/tokyo/alien/tcrdb/tcrdb.factor old mode 100755 new mode 100644 diff --git a/extra/tokyo/alien/tctdb/tctdb.factor b/extra/tokyo/alien/tctdb/tctdb.factor old mode 100755 new mode 100644 diff --git a/extra/tokyo/alien/tcutil/tcutil.factor b/extra/tokyo/alien/tcutil/tcutil.factor old mode 100755 new mode 100644 diff --git a/extra/tokyo/assoc-functor/assoc-functor.factor b/extra/tokyo/assoc-functor/assoc-functor.factor index 122e613387..de160f5598 100644 --- a/extra/tokyo/assoc-functor/assoc-functor.factor +++ b/extra/tokyo/assoc-functor/assoc-functor.factor @@ -45,7 +45,7 @@ M: TYPE >alist ( db -- alist ) [ DBKEYS dup ] keep '[ dup _ at 2array ] map! drop ; M: TYPE set-at ( value key db -- ) - handle>> spin [ object>bytes dup length ] bi@ DBPUT drop ; + handle>> swap rot [ object>bytes dup length ] bi@ DBPUT drop ; M: TYPE delete-at ( key db -- ) handle>> swap object>bytes dup length DBOUT drop ; diff --git a/extra/trees/avl/avl-tests.factor b/extra/trees/avl/avl-tests.factor old mode 100755 new mode 100644 diff --git a/extra/trees/avl/avl.factor b/extra/trees/avl/avl.factor old mode 100755 new mode 100644 index 04c7022077..4903307af1 --- a/extra/trees/avl/avl.factor +++ b/extra/trees/avl/avl.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2007 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. USING: combinators kernel generic math math.functions -math.parser namespaces io sequences trees +math.parser namespaces io sequences trees shuffle assocs parser accessors math.order prettyprint.custom ; IN: trees.avl diff --git a/extra/trees/splay/splay-tests.factor b/extra/trees/splay/splay-tests.factor index c07357fbdf..d858a14795 100644 --- a/extra/trees/splay/splay-tests.factor +++ b/extra/trees/splay/splay-tests.factor @@ -5,10 +5,10 @@ sequences random sets make grouping ; IN: trees.splay.tests : randomize-numeric-splay-tree ( splay-tree -- ) - 100 [ drop 100 random swap at drop ] with each ; + 100 iota [ drop 100 random swap at drop ] with each ; : make-numeric-splay-tree ( n -- splay-tree ) - [ [ conjoin ] curry each ] keep ; + iota [ [ conjoin ] curry each ] keep ; [ t ] [ 100 make-numeric-splay-tree dup randomize-numeric-splay-tree diff --git a/extra/trees/splay/splay.factor b/extra/trees/splay/splay.factor old mode 100755 new mode 100644 index 66ef154b63..67b2f6b624 --- a/extra/trees/splay/splay.factor +++ b/extra/trees/splay/splay.factor @@ -1,7 +1,7 @@ ! Copyright (c) 2005 Mackenzie Straight. ! See http://factorcode.org/license.txt for BSD license. USING: arrays kernel math namespaces sequences assocs parser -trees generic math.order accessors prettyprint.custom ; +trees generic math.order accessors prettyprint.custom shuffle ; IN: trees.splay TUPLE: splay < tree ; diff --git a/extra/trees/trees.factor b/extra/trees/trees.factor old mode 100755 new mode 100644 index 62f4d8fce4..77e5e5bdc0 --- a/extra/trees/trees.factor +++ b/extra/trees/trees.factor @@ -2,7 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: kernel generic math sequences arrays io namespaces prettyprint.private kernel.private assocs random combinators -parser math.order accessors deques make prettyprint.custom ; +parser math.order accessors deques make prettyprint.custom +shuffle ; IN: trees TUPLE: tree root count ; diff --git a/extra/ui/gadgets/lists/lists.factor b/extra/ui/gadgets/lists/lists.factor index 8730c0acc4..06f1de6bc8 100644 --- a/extra/ui/gadgets/lists/lists.factor +++ b/extra/ui/gadgets/lists/lists.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2006, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors math.vectors classes.tuple math.rectangles colors -kernel sequences models opengl math math.order namespaces +kernel locals sequences models opengl math math.order namespaces ui.commands ui.gestures ui.render ui.gadgets ui.gadgets.labels ui.gadgets.scrollers ui.gadgets.presentations ui.gadgets.viewports ui.gadgets.packs ; @@ -78,7 +78,7 @@ M: list focusable-child* drop t ; dup list-empty? [ 2drop ] [ - tuck control-value length rem >>index + [ control-value length rem ] [ (>>index) ] [ ] tri [ relayout-1 ] [ scroll>selected ] bi ] if ; @@ -95,9 +95,9 @@ M: list focusable-child* drop t ; [ index>> ] keep nth-gadget invoke-secondary ] if ; -: select-gadget ( gadget list -- ) - tuck children>> index - [ swap select-index ] [ drop ] if* ; +:: select-gadget ( gadget list -- ) + gadget list children>> index + [ list select-index ] when* ; : clamp-loc ( point max -- point ) vmin { 0 0 } vmax ; diff --git a/extra/ui/gadgets/worlds/null/null.factor b/extra/ui/gadgets/worlds/null/null.factor index 0f116f0d51..eb0e1c1d5c 100644 --- a/extra/ui/gadgets/worlds/null/null.factor +++ b/extra/ui/gadgets/worlds/null/null.factor @@ -7,7 +7,6 @@ M: null-world begin-world drop ; M: null-world end-world drop ; M: null-world draw-world* drop ; M: null-world resize-world drop ; -M: null-world pref-dim* drop { 512 512 } ; : null-window ( title -- world ) @@ -19,6 +18,7 @@ M: null-world pref-dim* drop { 512 512 } ; backing-store T{ depth-bits f 24 } } >>pixel-format-attributes + { 512 512 } >>pref-dim f swap open-window* ; : into-window ( world quot -- world ) diff --git a/extra/ui/render/test/test.factor b/extra/ui/render/test/test.factor old mode 100755 new mode 100644 diff --git a/extra/units/units-tests.factor b/extra/units/units-tests.factor old mode 100755 new mode 100644 index 96497b8bbc..5d0fa1cf1e --- a/extra/units/units-tests.factor +++ b/extra/units/units-tests.factor @@ -10,7 +10,7 @@ IN: units.tests [ t ] [ 5 m 1 m d- 4 m = ] unit-test [ t ] [ 5 m 2 m d* 10 m^2 = ] unit-test [ t ] [ 5 m 2 m d/ 5/2 { } { } = ] unit-test -[ t ] [ 5 m 2 m tuck d/ drop 2 m = ] unit-test +[ t ] [ 2 m 5 m 2 m d/ drop 2 m = ] unit-test [ t ] [ 1 m 2 m 3 m 3array d-product 6 m^3 = ] unit-test [ t ] [ 3 m d-recip 1/3 { } { m } = ] unit-test diff --git a/extra/units/units.factor b/extra/units/units.factor old mode 100755 new mode 100644 index b8e3f45a16..a293d79f78 --- a/extra/units/units.factor +++ b/extra/units/units.factor @@ -28,9 +28,9 @@ M: dimensions-not-equal summary drop "Dimensions do not match" ; dimensioned boa ; : >dimensioned< ( d -- n top bot ) - [ value>> ] [ top>> ] [ bot>> ] tri ; + [ bot>> ] [ top>> ] [ value>> ] tri ; -\ [ >dimensioned< ] define-inverse +\ [ [ dimensioned boa ] undo ] define-inverse : dimensions ( dimensioned -- top bot ) [ top>> ] [ bot>> ] bi ; @@ -65,7 +65,7 @@ M: dimensions-not-equal summary drop "Dimensions do not match" ; : d-sq ( d -- d ) dup d* ; : d-recip ( d -- d' ) - >dimensioned< spin recip dimension-op> ; + >dimensioned< recip dimension-op> ; : d/ ( d d -- d ) d-recip d* ; diff --git a/extra/usa-cities/usa-cities.factor b/extra/usa-cities/usa-cities.factor index 0ee2a114dd..29f710061c 100644 --- a/extra/usa-cities/usa-cities.factor +++ b/extra/usa-cities/usa-cities.factor @@ -48,7 +48,7 @@ MEMO: cities-named ( name -- cities ) MEMO: cities-named-in ( name state -- cities ) cities [ - tuck [ name>> = ] [ state>> = ] 2bi* and + [ name>> = ] [ state>> = ] bi-curry bi* and ] with with filter ; : find-zip-code ( code -- city ) diff --git a/extra/vocabs/git/authors.txt b/extra/vocabs/git/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/extra/vocabs/git/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/extra/vocabs/git/git.factor b/extra/vocabs/git/git.factor new file mode 100644 index 0000000000..eb945b57c7 --- /dev/null +++ b/extra/vocabs/git/git.factor @@ -0,0 +1,28 @@ +! (c)2009 Joe Groff bsd license +USING: fry io io.directories io.encodings.ascii +io.encodings.utf8 io.launcher io.pathnames kernel lexer +namespaces parser sequences splitting vocabs vocabs.loader ; +IN: vocabs.git + + + +ERROR: git-revision-not-found path ; + +: use-vocab-rev ( vocab-name rev -- ) + [ create-vocab vocab-source-path dup ] dip git-object-id + [ [ input-stream get swap parse-stream call( -- ) ] with-git-object-stream ] + [ git-revision-not-found ] if* ; + +SYNTAX: USE-REV: scan scan use-vocab-rev ; diff --git a/extra/webapps/imagebin/imagebin.factor b/extra/webapps/imagebin/imagebin.factor old mode 100755 new mode 100644 diff --git a/extra/webapps/mason/mason.factor b/extra/webapps/mason/mason.factor index 637ffa6dd8..42f15d2873 100644 --- a/extra/webapps/mason/mason.factor +++ b/extra/webapps/mason/mason.factor @@ -83,10 +83,6 @@ CONSTANT: cpus [ validate-os/cpu ] >>init [ current-builder last-report>> "text/html" ] >>display ; -: git-link ( id -- link ) - [ "http://github.com/slavapestov/factor/commit/" prepend ] keep - [XML ><-> XML] ; - : building ( builder string -- xml ) swap current-git-id>> git-link [XML <-> for <-> XML] ; diff --git a/extra/webapps/planet/planet.factor b/extra/webapps/planet/planet.factor old mode 100755 new mode 100644 diff --git a/extra/webapps/todo/todo.factor b/extra/webapps/todo/todo.factor old mode 100755 new mode 100644 diff --git a/extra/window-controls-demo/window-controls-demo.factor b/extra/window-controls-demo/window-controls-demo.factor old mode 100755 new mode 100644 diff --git a/extra/yahoo/yahoo.factor b/extra/yahoo/yahoo.factor old mode 100755 new mode 100644 diff --git a/extra/zoneinfo/africa b/extra/zoneinfo/africa new file mode 100644 index 0000000000..0a6185d6ef --- /dev/null +++ b/extra/zoneinfo/africa @@ -0,0 +1,915 @@ +# @(#)africa 8.18 +#
+
+# This data is by no means authoritative; if you think you know better,
+# go ahead and edit the file (and please send any changes to
+# tz@elsie.nci.nih.gov for general use in the future).
+
+# From Paul Eggert (2006-03-22):
+#
+# A good source for time zone historical data outside the U.S. is
+# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
+# San Diego: ACS Publications, Inc. (2003).
+#
+# Gwillim Law writes that a good source
+# for recent time zone data is the International Air Transport
+# Association's Standard Schedules Information Manual (IATA SSIM),
+# published semiannually.  Law sent in several helpful summaries
+# of the IATA's data after 1990.
+#
+# Except where otherwise noted, Shanks & Pottenger is the source for
+# entries through 1990, and IATA SSIM is the source for entries afterwards.
+#
+# Another source occasionally used is Edward W. Whitman, World Time Differences,
+# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
+# I found in the UCLA library.
+#
+# A reliable and entertaining source about time zones is
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
+#
+# Previous editions of this database used WAT, CAT, SAT, and EAT
+# for +0:00 through +3:00, respectively,
+# but Mark R V Murray reports that
+# `SAST' is the official abbreviation for +2:00 in the country of South Africa,
+# `CAT' is commonly used for +2:00 in countries north of South Africa, and
+# `WAT' is probably the best name for +1:00, as the common phrase for
+# the area that includes Nigeria is ``West Africa''.
+# He has heard of ``Western Sahara Time'' for +0:00 but can find no reference.
+#
+# To make things confusing, `WAT' seems to have been used for -1:00 long ago;
+# I'd guess that this was because people needed _some_ name for -1:00,
+# and at the time, far west Africa was the only major land area in -1:00.
+# This usage is now obsolete, as the last use of -1:00 on the African
+# mainland seems to have been 1976 in Western Sahara.
+#
+# To summarize, the following abbreviations seem to have some currency:
+#	-1:00	WAT	West Africa Time (no longer used)
+#	 0:00	GMT	Greenwich Mean Time
+#	 2:00	CAT	Central Africa Time
+#	 2:00	SAST	South Africa Standard Time
+# and Murray suggests the following abbreviation:
+#	 1:00	WAT	West Africa Time
+# I realize that this leads to `WAT' being used for both -1:00 and 1:00
+# for times before 1976, but this is the best I can think of
+# until we get more information.
+#
+# I invented the following abbreviations; corrections are welcome!
+#	 2:00	WAST	West Africa Summer Time
+#	 2:30	BEAT	British East Africa Time (no longer used)
+#	 2:44:45 BEAUT	British East Africa Unified Time (no longer used)
+#	 3:00	CAST	Central Africa Summer Time (no longer used)
+#	 3:00	SAST	South Africa Summer Time (no longer used)
+#	 3:00	EAT	East Africa Time
+#	 4:00	EAST	East Africa Summer Time (no longer used)
+
+# Algeria
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Algeria	1916	only	-	Jun	14	23:00s	1:00	S
+Rule	Algeria	1916	1919	-	Oct	Sun>=1	23:00s	0	-
+Rule	Algeria	1917	only	-	Mar	24	23:00s	1:00	S
+Rule	Algeria	1918	only	-	Mar	 9	23:00s	1:00	S
+Rule	Algeria	1919	only	-	Mar	 1	23:00s	1:00	S
+Rule	Algeria	1920	only	-	Feb	14	23:00s	1:00	S
+Rule	Algeria	1920	only	-	Oct	23	23:00s	0	-
+Rule	Algeria	1921	only	-	Mar	14	23:00s	1:00	S
+Rule	Algeria	1921	only	-	Jun	21	23:00s	0	-
+Rule	Algeria	1939	only	-	Sep	11	23:00s	1:00	S
+Rule	Algeria	1939	only	-	Nov	19	 1:00	0	-
+Rule	Algeria	1944	1945	-	Apr	Mon>=1	 2:00	1:00	S
+Rule	Algeria	1944	only	-	Oct	 8	 2:00	0	-
+Rule	Algeria	1945	only	-	Sep	16	 1:00	0	-
+Rule	Algeria	1971	only	-	Apr	25	23:00s	1:00	S
+Rule	Algeria	1971	only	-	Sep	26	23:00s	0	-
+Rule	Algeria	1977	only	-	May	 6	 0:00	1:00	S
+Rule	Algeria	1977	only	-	Oct	21	 0:00	0	-
+Rule	Algeria	1978	only	-	Mar	24	 1:00	1:00	S
+Rule	Algeria	1978	only	-	Sep	22	 3:00	0	-
+Rule	Algeria	1980	only	-	Apr	25	 0:00	1:00	S
+Rule	Algeria	1980	only	-	Oct	31	 2:00	0	-
+# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
+# more precise 0:09:21.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Algiers	0:12:12 -	LMT	1891 Mar 15 0:01
+			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
+			0:00	Algeria	WE%sT	1940 Feb 25 2:00
+			1:00	Algeria	CE%sT	1946 Oct  7
+			0:00	-	WET	1956 Jan 29
+			1:00	-	CET	1963 Apr 14
+			0:00	Algeria	WE%sT	1977 Oct 21
+			1:00	Algeria	CE%sT	1979 Oct 26
+			0:00	Algeria	WE%sT	1981 May
+			1:00	-	CET
+
+# Angola
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Luanda	0:52:56	-	LMT	1892
+			0:52:04	-	AOT	1911 May 26 # Angola Time
+			1:00	-	WAT
+
+# Benin
+# Whitman says they switched to 1:00 in 1946, not 1934;
+# go with Shanks & Pottenger.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Porto-Novo	0:10:28	-	LMT	1912
+			0:00	-	GMT	1934 Feb 26
+			1:00	-	WAT
+
+# Botswana
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Gaborone	1:43:40 -	LMT	1885
+			2:00	-	CAT	1943 Sep 19 2:00
+			2:00	1:00	CAST	1944 Mar 19 2:00
+			2:00	-	CAT
+
+# Burkina Faso
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Ouagadougou	-0:06:04 -	LMT	1912
+			 0:00	-	GMT
+
+# Burundi
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Bujumbura	1:57:28	-	LMT	1890
+			2:00	-	CAT
+
+# Cameroon
+# Whitman says they switched to 1:00 in 1920; go with Shanks & Pottenger.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Douala	0:38:48	-	LMT	1912
+			1:00	-	WAT
+
+# Cape Verde
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Atlantic/Cape_Verde -1:34:04 -	LMT	1907			# Praia
+			-2:00	-	CVT	1942 Sep
+			-2:00	1:00	CVST	1945 Oct 15
+			-2:00	-	CVT	1975 Nov 25 2:00
+			-1:00	-	CVT
+
+# Central African Republic
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Bangui	1:14:20	-	LMT	1912
+			1:00	-	WAT
+
+# Chad
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Ndjamena	1:00:12 -	LMT	1912
+			1:00	-	WAT	1979 Oct 14
+			1:00	1:00	WAST	1980 Mar  8
+			1:00	-	WAT
+
+# Comoros
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Indian/Comoro	2:53:04 -	LMT	1911 Jul   # Moroni, Gran Comoro
+			3:00	-	EAT
+
+# Democratic Republic of Congo
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Kinshasa	1:01:12 -	LMT	1897 Nov 9
+			1:00	-	WAT
+Zone Africa/Lubumbashi	1:49:52 -	LMT	1897 Nov 9
+			2:00	-	CAT
+
+# Republic of the Congo
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Brazzaville	1:01:08 -	LMT	1912
+			1:00	-	WAT
+
+# Cote D'Ivoire
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Abidjan	-0:16:08 -	LMT	1912
+			 0:00	-	GMT
+
+# Djibouti
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Djibouti	2:52:36 -	LMT	1911 Jul
+			3:00	-	EAT
+
+###############################################################################
+
+# Egypt
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Egypt	1940	only	-	Jul	15	0:00	1:00	S
+Rule	Egypt	1940	only	-	Oct	 1	0:00	0	-
+Rule	Egypt	1941	only	-	Apr	15	0:00	1:00	S
+Rule	Egypt	1941	only	-	Sep	16	0:00	0	-
+Rule	Egypt	1942	1944	-	Apr	 1	0:00	1:00	S
+Rule	Egypt	1942	only	-	Oct	27	0:00	0	-
+Rule	Egypt	1943	1945	-	Nov	 1	0:00	0	-
+Rule	Egypt	1945	only	-	Apr	16	0:00	1:00	S
+Rule	Egypt	1957	only	-	May	10	0:00	1:00	S
+Rule	Egypt	1957	1958	-	Oct	 1	0:00	0	-
+Rule	Egypt	1958	only	-	May	 1	0:00	1:00	S
+Rule	Egypt	1959	1981	-	May	 1	1:00	1:00	S
+Rule	Egypt	1959	1965	-	Sep	30	3:00	0	-
+Rule	Egypt	1966	1994	-	Oct	 1	3:00	0	-
+Rule	Egypt	1982	only	-	Jul	25	1:00	1:00	S
+Rule	Egypt	1983	only	-	Jul	12	1:00	1:00	S
+Rule	Egypt	1984	1988	-	May	 1	1:00	1:00	S
+Rule	Egypt	1989	only	-	May	 6	1:00	1:00	S
+Rule	Egypt	1990	1994	-	May	 1	1:00	1:00	S
+# IATA (after 1990) says transitions are at 0:00.
+# Go with IATA starting in 1995, except correct 1995 entry from 09-30 to 09-29.
+Rule	Egypt	1995	max	-	Apr	lastFri	 0:00s	1:00	S
+Rule	Egypt	1995	2005	-	Sep	lastThu	23:00s	0	-
+# From Steffen Thorsen (2006-09-19):
+# The Egyptian Gazette, issue 41,090 (2006-09-18), page 1, reports:
+# Egypt will turn back clocks by one hour at the midnight of Thursday
+# after observing the daylight saving time since May.
+# http://news.gom.com.eg/gazette/pdf/2006/09/18/01.pdf
+Rule	Egypt	2006	only	-	Sep	21	23:00s	0	-
+# From Dirk Losch (2007-08-14):
+# I received a mail from an airline which says that the daylight
+# saving time in Egypt will end in the night of 2007-09-06 to 2007-09-07.
+# From Jesper Norgaard Welen (2007-08-15): [The following agree:]
+# http://www.nentjes.info/Bill/bill5.htm 
+# http://www.timeanddate.com/worldclock/city.html?n=53
+# From Steffen Thorsen (2007-09-04): The official information...:
+# http://www.sis.gov.eg/En/EgyptOnline/Miscellaneous/000002/0207000000000000001580.htm
+Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
+# From Abdelrahman Hassan (2007-09-06):
+# Due to the Hijri (lunar Islamic calendar) year being 11 days shorter
+# than the year of the Gregorian calendar, Ramadan shifts earlier each
+# year. This year it will be observed September 13 (September is quite
+# hot in Egypt), and the idea is to make fasting easier for workers by
+# shifting business hours one hour out of daytime heat. Consequently,
+# unless discontinued, next DST may end Thursday 28 August 2008.
+# From Paul Eggert (2007-08-17):
+# For lack of better info, assume the new rule is last Thursday in August.
+Rule	Egypt	2008	max	-	Aug	lastThu	23:00s	0	-
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Cairo	2:05:00 -	LMT	1900 Oct
+			2:00	Egypt	EE%sT
+
+# Equatorial Guinea
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Malabo	0:35:08 -	LMT	1912
+			0:00	-	GMT	1963 Dec 15
+			1:00	-	WAT
+
+# Eritrea
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Asmara	2:35:32 -	LMT	1870
+			2:35:32	-	AMT	1890	      # Asmara Mean Time
+			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
+			3:00	-	EAT
+
+# Ethiopia
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger write that Ethiopia had six narrowly-spaced time zones
+# between 1870 and 1890, and that they merged to 38E50 (2:35:20) in 1890.
+# We'll guess that 38E50 is for Adis Dera.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Addis_Ababa	2:34:48 -	LMT	1870
+			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
+			3:00	-	EAT
+
+# Gabon
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Libreville	0:37:48 -	LMT	1912
+			1:00	-	WAT
+
+# Gambia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Banjul	-1:06:36 -	LMT	1912
+			-1:06:36 -	BMT	1935	# Banjul Mean Time
+			-1:00	-	WAT	1964
+			 0:00	-	GMT
+
+# Ghana
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+# Whitman says DST was observed from 1931 to ``the present'';
+# go with Shanks & Pottenger.
+Rule	Ghana	1936	1942	-	Sep	 1	0:00	0:20	GHST
+Rule	Ghana	1936	1942	-	Dec	31	0:00	0	GMT
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Accra	-0:00:52 -	LMT	1918
+			 0:00	Ghana	%s
+
+# Guinea
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Conakry	-0:54:52 -	LMT	1912
+			 0:00	-	GMT	1934 Feb 26
+			-1:00	-	WAT	1960
+			 0:00	-	GMT
+
+# Guinea-Bissau
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Bissau	-1:02:20 -	LMT	1911 May 26
+			-1:00	-	WAT	1975
+			 0:00	-	GMT
+
+# Kenya
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Nairobi	2:27:16	-	LMT	1928 Jul
+			3:00	-	EAT	1930
+			2:30	-	BEAT	1940
+			2:44:45	-	BEAUT	1960
+			3:00	-	EAT
+
+# Lesotho
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Maseru	1:50:00 -	LMT	1903 Mar
+			2:00	-	SAST	1943 Sep 19 2:00
+			2:00	1:00	SAST	1944 Mar 19 2:00
+			2:00	-	SAST
+
+# Liberia
+# From Paul Eggert (2006-03-22):
+# In 1972 Liberia was the last country to switch
+# from a UTC offset that was not a multiple of 15 or 20 minutes.
+# Howse reports that it was in honor of their president's birthday.
+# Shank & Pottenger report the date as May 1, whereas Howse reports Jan;
+# go with Shanks & Pottenger.
+# For Liberia before 1972, Shanks & Pottenger report -0:44, whereas Howse and
+# Whitman each report -0:44:30; go with the more precise figure.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Monrovia	-0:43:08 -	LMT	1882
+			-0:43:08 -	MMT	1919 Mar # Monrovia Mean Time
+			-0:44:30 -	LRT	1972 May # Liberia Time
+			 0:00	-	GMT
+
+###############################################################################
+
+# Libya
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Libya	1951	only	-	Oct	14	2:00	1:00	S
+Rule	Libya	1952	only	-	Jan	 1	0:00	0	-
+Rule	Libya	1953	only	-	Oct	 9	2:00	1:00	S
+Rule	Libya	1954	only	-	Jan	 1	0:00	0	-
+Rule	Libya	1955	only	-	Sep	30	0:00	1:00	S
+Rule	Libya	1956	only	-	Jan	 1	0:00	0	-
+Rule	Libya	1982	1984	-	Apr	 1	0:00	1:00	S
+Rule	Libya	1982	1985	-	Oct	 1	0:00	0	-
+Rule	Libya	1985	only	-	Apr	 6	0:00	1:00	S
+Rule	Libya	1986	only	-	Apr	 4	0:00	1:00	S
+Rule	Libya	1986	only	-	Oct	 3	0:00	0	-
+Rule	Libya	1987	1989	-	Apr	 1	0:00	1:00	S
+Rule	Libya	1987	1989	-	Oct	 1	0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Tripoli	0:52:44 -	LMT	1920
+			1:00	Libya	CE%sT	1959
+			2:00	-	EET	1982
+			1:00	Libya	CE%sT	1990 May  4
+# The following entries are from Shanks & Pottenger;
+# the IATA SSIM data contain some obvious errors.
+			2:00	-	EET	1996 Sep 30
+			1:00	-	CET	1997 Apr  4
+			1:00	1:00	CEST	1997 Oct  4
+			2:00	-	EET
+
+# Madagascar
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Indian/Antananarivo 3:10:04 -	LMT	1911 Jul
+			3:00	-	EAT	1954 Feb 27 23:00s
+			3:00	1:00	EAST	1954 May 29 23:00s
+			3:00	-	EAT
+
+# Malawi
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Blantyre	2:20:00 -	LMT	1903 Mar
+			2:00	-	CAT
+
+# Mali
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Bamako	-0:32:00 -	LMT	1912
+			 0:00	-	GMT	1934 Feb 26
+			-1:00	-	WAT	1960 Jun 20
+			 0:00	-	GMT
+
+# Mauritania
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
+			 0:00	-	GMT	1934 Feb 26
+			-1:00	-	WAT	1960 Nov 28
+			 0:00	-	GMT
+
+# Mauritius
+
+# From Steffen Thorsen (2008-06-25):
+# Mauritius plans to observe DST from 2008-11-01 to 2009-03-31 on a trial
+# basis....
+# It seems that Mauritius observed daylight saving time from 1982-10-10 to 
+# 1983-03-20 as well, but that was not successful....
+# http://www.timeanddate.com/news/time/mauritius-daylight-saving-time.html
+
+# From Alex Krivenyshev (2008-06-25):
+# http://economicdevelopment.gov.mu/portal/site/Mainhomepage/menuitem.a42b24128104d9845dabddd154508a0c/?content_id=0a7cee8b5d69a110VgnVCM1000000a04a8c0RCRD
+
+# From Arthur David Olson (2008-06-30):
+# The www.timeanddate.com article cited by Steffen Thorsen notes that "A
+# final decision has yet to be made on the times that daylight saving
+# would begin and end on these dates." As a place holder, use midnight.
+
+# From Paul Eggert (2008-06-30):
+# Follow Thorsen on DST in 1982/1983, instead of Shanks & Pottenger.
+
+# From Steffen Thorsen (2008-07-10):
+# According to
+# 
+# http://www.lexpress.mu/display_article.php?news_id=111216
+# 
+# (in French), Mauritius will start and end their DST a few days earlier
+# than previously announced (2008-11-01 to 2009-03-31).  The new start
+# date is 2008-10-26 at 02:00 and the new end date is 2009-03-27 (no time
+# given, but it is probably at either 2 or 3 wall clock time).
+# 
+# A little strange though, since the article says that they moved the date 
+# to align itself with Europe and USA which also change time on that date, 
+# but that means they have not paid attention to what happened in 
+# USA/Canada last year (DST ends first Sunday in November). I also wonder 
+# why that they end on a Friday, instead of aligning with Europe which 
+# changes two days later.
+
+# From Alex Krivenyshev (2008-07-11):
+# Seems that English language article "The revival of daylight saving
+# time:  Energy conservation?"-# No. 16578 (07/11/2008) was originally
+# published on Monday, June 30, 2008...
+#
+# I guess that article in French "Le gouvernement avance l'introduction
+# de l'heure d'ete" stating that DST in Mauritius starting on October 26
+# and ending on March 27, 2009 is the most recent one.
+# ...
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_mauritius02.html
+# 
+
+# From Riad M. Hossen Ally (2008-08-03):
+# The Government of Mauritius weblink
+# 
+# http://www.gov.mu/portal/site/pmosite/menuitem.4ca0efdee47462e7440a600248a521ca/?content_id=3D4728ca68b2a5b110VgnVCM1000000a04a8c0RCRD
+# 
+# Cabinet Decision of July 18th, 2008 states as follows:
+#
+# 4. ...Cabinet has agreed to the introduction into the National Assembly
+# of the Time Bill which provides for the introduction of summer time in
+# Mauritius. The summer time period which will be of one hour ahead of
+# the standard time, will be aligned with that in Europe and the United
+# States of America. It will start at two o'clock in the morning on the
+# last Sunday of October and will end at two o'clock in the morning on
+# the last Sunday of March the following year. The summer time for the
+# year 2008 - 2009 will, therefore, be effective as from 26 October 2008
+# and end on 29 March 2009.
+
+# From Ed Maste (2008-10-07):
+# THE TIME BILL (No. XXVII of 2008) Explanatory Memorandum states the
+# beginning / ending of summer time is 2 o'clock standard time in the
+# morning of the last Sunday of October / last Sunday of March.
+# 
+# http://www.gov.mu/portal/goc/assemblysite/file/bill2708.pdf
+# 
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule Mauritius	1982	only	-	Oct	10	0:00	1:00	S
+Rule Mauritius	1983	only	-	Mar	21	0:00	0	-
+Rule Mauritius	2008	max	-	Oct	lastSun	2:00s	1:00	S
+Rule Mauritius	2009	max	-	Mar	lastSun	2:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Indian/Mauritius	3:50:00 -	LMT	1907		# Port Louis
+			4:00 Mauritius	MU%sT	# Mauritius Time
+# Agalega Is, Rodriguez
+# no information; probably like Indian/Mauritius
+
+# Mayotte
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
+			3:00	-	EAT
+
+# Morocco
+# See the `europe' file for Spanish Morocco (Africa/Ceuta).
+
+# From Alex Krivenyshev (2008-05-09):
+# Here is an article that Morocco plan to introduce Daylight Saving Time between
+# 1 June, 2008 and 27 September, 2008.
+#
+# "... Morocco is to save energy by adjusting its clock during summer so it will
+# be one hour ahead of GMT between 1 June and 27 September, according to
+# Communication Minister and Gov ernment Spokesman, Khalid Naciri...."
+#
+# 
+# http://www.worldtimezone.net/dst_news/dst_news_morocco01.html
+# 
+# OR
+# 
+# http://en.afrik.com/news11892.html
+# 
+
+# From Alex Krivenyshev (2008-05-09):
+# The Morocco time change can be confirmed on Morocco web site Maghreb Arabe Presse:
+# 
+# http://www.map.ma/eng/sections/box3/morocco_shifts_to_da/view
+# 
+#
+# Morocco shifts to daylight time on June 1st through September 27, Govt.
+# spokesman.
+
+# From Patrice Scattolin (2008-05-09):
+# According to this article:
+# 
+# http://www.avmaroc.com/actualite/heure-dete-comment-a127896.html
+# 
+# (and republished here:
+# 
+# http://www.actu.ma/heure-dete-comment_i127896_0.html
+# 
+# )
+# the changes occurs at midnight:
+#
+# saturday night may 31st at midnight (which in french is to be
+# intrepreted as the night between saturday and sunday)
+# sunday night the 28th  at midnight
+#
+# Seeing that the 28th is monday, I am guessing that she intends to say
+# the midnight of the 28th which is the midnight between sunday and
+# monday, which jives with other sources that say that it's inclusive
+# june1st to sept 27th.
+#
+# The decision was taken by decree *2-08-224 *but I can't find the decree
+# published on the web.
+#
+# It's also confirmed here:
+# 
+# http://www.maroc.ma/NR/exeres/FACF141F-D910-44B0-B7FA-6E03733425D1.htm
+# 
+# on a government portal as being  between june 1st and sept 27th (not yet
+# posted in english).
+#
+# The following google query will generate many relevant hits:
+# 
+# http://www.google.com/search?hl=en&q=Conseil+de+gouvernement+maroc+heure+avance&btnG=Search
+# 
+
+# From Alex Krivenyshev (2008-05-09):
+# Is Western Sahara (part which administrated by Morocco) going to follow
+# Morocco DST changes?  Any information?  What about other part of
+# Western Sahara - under administration of POLISARIO Front (also named
+# SADR Saharawi Arab Democratic Republic)?
+
+# From Arthur David Olson (2008-05-09):
+# XXX--guess that it is only Morocco for now; guess only 2008 for now.
+
+# From Steffen Thorsen (2008-08-27):
+# Morocco will change the clocks back on the midnight between August 31 
+# and September 1. They originally planned to observe DST to near the end 
+# of September:
+#
+# One article about it (in French):
+# 
+# http://www.menara.ma/fr/Actualites/Maroc/Societe/ci.retour_a_l_heure_gmt_a_partir_du_dimanche_31_aout_a_minuit_officiel_.default
+# 
+#
+# We have some further details posted here:
+# 
+# http://www.timeanddate.com/news/time/morocco-ends-dst-early-2008.html
+# 
+
+# From Steffen Thorsen (2009-03-17):
+# Morocco will observe DST from 2009-06-01 00:00 to 2009-08-21 00:00 according
+# to many sources, such as
+# 
+# http://news.marweb.com/morocco/entertainment/morocco-daylight-saving.html
+# 
+# 
+# http://www.medi1sat.ma/fr/depeche.aspx?idp=2312
+# 
+# (French)
+#
+# Our summary:
+# 
+# http://www.timeanddate.com/news/time/morocco-starts-dst-2009.html
+# 
+
+# From Alexander Krivenyshev (2009-03-17):
+# Here is a link to official document from Royaume du Maroc Premier Ministre,
+# Ministere de la Modernisation des Secteurs Publics
+#
+# Under Article 1 of Royal Decree No. 455-67 of Act 23 safar 1387 (2 june 1967)
+# concerning the amendment of the legal time, the Ministry of Modernization of
+# Public Sectors announced that the official time in the Kingdom will be
+# advanced 60 minutes from Sunday 31 May 2009 at midnight.
+#
+# 
+# http://www.mmsp.gov.ma/francais/Actualites_fr/PDF_Actualites_Fr/HeureEte_FR.pdf
+# 
+#
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_morocco03.html
+# 
+
+# RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+
+Rule	Morocco	1939	only	-	Sep	12	 0:00	1:00	S
+Rule	Morocco	1939	only	-	Nov	19	 0:00	0	-
+Rule	Morocco	1940	only	-	Feb	25	 0:00	1:00	S
+Rule	Morocco	1945	only	-	Nov	18	 0:00	0	-
+Rule	Morocco	1950	only	-	Jun	11	 0:00	1:00	S
+Rule	Morocco	1950	only	-	Oct	29	 0:00	0	-
+Rule	Morocco	1967	only	-	Jun	 3	12:00	1:00	S
+Rule	Morocco	1967	only	-	Oct	 1	 0:00	0	-
+Rule	Morocco	1974	only	-	Jun	24	 0:00	1:00	S
+Rule	Morocco	1974	only	-	Sep	 1	 0:00	0	-
+Rule	Morocco	1976	1977	-	May	 1	 0:00	1:00	S
+Rule	Morocco	1976	only	-	Aug	 1	 0:00	0	-
+Rule	Morocco	1977	only	-	Sep	28	 0:00	0	-
+Rule	Morocco	1978	only	-	Jun	 1	 0:00	1:00	S
+Rule	Morocco	1978	only	-	Aug	 4	 0:00	0	-
+Rule	Morocco	2008	only	-	Jun	 1	 0:00	1:00	S
+Rule	Morocco	2008	only	-	Sep	 1	 0:00	0	-
+Rule	Morocco	2009	only	-	Jun	 1	 0:00	1:00	S
+Rule	Morocco	2009	only	-	Aug	 21	 0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Casablanca	-0:30:20 -	LMT	1913 Oct 26
+			 0:00	Morocco	WE%sT	1984 Mar 16
+			 1:00	-	CET	1986
+			 0:00	Morocco	WE%sT
+# Western Sahara
+Zone Africa/El_Aaiun	-0:52:48 -	LMT	1934 Jan
+			-1:00	-	WAT	1976 Apr 14
+			 0:00	-	WET
+
+# Mozambique
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Maputo	2:10:20 -	LMT	1903 Mar
+			2:00	-	CAT
+
+# Namibia
+# The 1994-04-03 transition is from Shanks & Pottenger.
+# Shanks & Pottenger report no DST after 1998-04; go with IATA.
+
+# From Petronella Sibeene (2007-03-30) in
+# :
+# While the entire country changes its time, Katima Mulilo and other
+# settlements in Caprivi unofficially will not because the sun there
+# rises and sets earlier compared to other regions.  Chief of
+# Forecasting Riaan van Zyl explained that the far eastern parts of
+# the country are close to 40 minutes earlier in sunrise than the rest
+# of the country.
+# 
+# From Paul Eggert (2007-03-31):
+# Apparently the Caprivi Strip informally observes Botswana time, but
+# we have no details.  In the meantime people there can use Africa/Gaborone.
+
+# RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Namibia	1994	max	-	Sep	Sun>=1	2:00	1:00	S
+Rule	Namibia	1995	max	-	Apr	Sun>=1	2:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Windhoek	1:08:24 -	LMT	1892 Feb 8
+			1:30	-	SWAT	1903 Mar	# SW Africa Time
+			2:00	-	SAST	1942 Sep 20 2:00
+			2:00	1:00	SAST	1943 Mar 21 2:00
+			2:00	-	SAST	1990 Mar 21 # independence
+			2:00	-	CAT	1994 Apr  3
+			1:00	Namibia	WA%sT
+
+# Niger
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Niamey	 0:08:28 -	LMT	1912
+			-1:00	-	WAT	1934 Feb 26
+			 0:00	-	GMT	1960
+			 1:00	-	WAT
+
+# Nigeria
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Lagos	0:13:36 -	LMT	1919 Sep
+			1:00	-	WAT
+
+# Reunion
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Indian/Reunion	3:41:52 -	LMT	1911 Jun	# Saint-Denis
+			4:00	-	RET	# Reunion Time
+#
+# Scattered Islands (Iles Eparses) administered from Reunion are as follows.
+# The following information about them is taken from
+# Iles Eparses (www.outre-mer.gouv.fr/domtom/ile.htm, 1997-07-22, in French;
+# no longer available as of 1999-08-17).
+# We have no info about their time zone histories.
+#
+# Bassas da India - uninhabited
+# Europa Island - inhabited from 1905 to 1910 by two families
+# Glorioso Is - inhabited until at least 1958
+# Juan de Nova - uninhabited
+# Tromelin - inhabited until at least 1958
+
+# Rwanda
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Kigali	2:00:16 -	LMT	1935 Jun
+			2:00	-	CAT
+
+# St Helena
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Atlantic/St_Helena	-0:22:48 -	LMT	1890		# Jamestown
+			-0:22:48 -	JMT	1951	# Jamestown Mean Time
+			 0:00	-	GMT
+# The other parts of the St Helena territory are similar:
+#	Tristan da Cunha: on GMT, say Whitman and the CIA
+#	Ascension: on GMT, says usno1995 and the CIA
+#	Gough (scientific station since 1955; sealers wintered previously):
+#		on GMT, says the CIA
+#	Inaccessible, Nightingale: no information, but probably GMT
+
+# Sao Tome and Principe
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Sao_Tome	 0:26:56 -	LMT	1884
+			-0:36:32 -	LMT	1912	# Lisbon Mean Time
+			 0:00	-	GMT
+
+# Senegal
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Dakar	-1:09:44 -	LMT	1912
+			-1:00	-	WAT	1941 Jun
+			 0:00	-	GMT
+
+# Seychelles
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Indian/Mahe	3:41:48 -	LMT	1906 Jun	# Victoria
+			4:00	-	SCT	# Seychelles Time
+# From Paul Eggert (2001-05-30):
+# Aldabra, Farquhar, and Desroches, originally dependencies of the
+# Seychelles, were transferred to the British Indian Ocean Territory
+# in 1965 and returned to Seychelles control in 1976.  We don't know
+# whether this affected their time zone, so omit this for now.
+# Possibly the islands were uninhabited.
+
+# Sierra Leone
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+# Whitman gives Mar 31 - Aug 31 for 1931 on; go with Shanks & Pottenger.
+Rule	SL	1935	1942	-	Jun	 1	0:00	0:40	SLST
+Rule	SL	1935	1942	-	Oct	 1	0:00	0	WAT
+Rule	SL	1957	1962	-	Jun	 1	0:00	1:00	SLST
+Rule	SL	1957	1962	-	Sep	 1	0:00	0	GMT
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Freetown	-0:53:00 -	LMT	1882
+			-0:53:00 -	FMT	1913 Jun # Freetown Mean Time
+			-1:00	SL	%s	1957
+			 0:00	SL	%s
+
+# Somalia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Mogadishu	3:01:28 -	LMT	1893 Nov
+			3:00	-	EAT	1931
+			2:30	-	BEAT	1957
+			3:00	-	EAT
+
+# South Africa
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	SA	1942	1943	-	Sep	Sun>=15	2:00	1:00	-
+Rule	SA	1943	1944	-	Mar	Sun>=15	2:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Johannesburg 1:52:00 -	LMT	1892 Feb 8
+			1:30	-	SAST	1903 Mar
+			2:00	SA	SAST
+# Marion and Prince Edward Is
+# scientific station since 1947
+# no information
+
+# Sudan
+#
+# From 
+# Sudan News Agency (2000-01-13)
+# , also reported by Michael De Beukelaer-Dossche via Steffen Thorsen:
+# Clocks will be moved ahead for 60 minutes all over the Sudan as of noon
+# Saturday....  This was announced Thursday by Caretaker State Minister for
+# Manpower Abdul-Rahman Nur-Eddin.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Sudan	1970	only	-	May	 1	0:00	1:00	S
+Rule	Sudan	1970	1985	-	Oct	15	0:00	0	-
+Rule	Sudan	1971	only	-	Apr	30	0:00	1:00	S
+Rule	Sudan	1972	1985	-	Apr	lastSun	0:00	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Khartoum	2:10:08 -	LMT	1931
+			2:00	Sudan	CA%sT	2000 Jan 15 12:00
+			3:00	-	EAT
+
+# Swaziland
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Mbabane	2:04:24 -	LMT	1903 Mar
+			2:00	-	SAST
+
+# Tanzania
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Africa/Dar_es_Salaam 2:37:08 -	LMT	1931
+			3:00	-	EAT	1948
+			2:44:45	-	BEAUT	1961
+			3:00	-	EAT
+
+# Togo
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Lome	0:04:52 -	LMT	1893
+			0:00	-	GMT
+
+# Tunisia
+
+# From Gwillim Law (2005-04-30):
+# My correspondent, Risto Nykanen, has alerted me to another adoption of DST,
+# this time in Tunisia.  According to Yahoo France News
+# , in a story attributed to AP
+# and dated 2005-04-26, "Tunisia has decided to advance its official time by
+# one hour, starting on Sunday, May 1.  Henceforth, Tunisian time will be
+# UTC+2 instead of UTC+1.  The change will take place at 23:00 UTC next
+# Saturday."  (My translation)
+#
+# From Oscar van Vlijmen (2005-05-02):
+# LaPresse, the first national daily newspaper ...
+# 
+# ... DST for 2005: on: Sun May 1 0h standard time, off: Fri Sept. 30,
+# 1h standard time.
+#
+# From Atef Loukil (2006-03-28):
+# The daylight saving time will be the same each year:
+# Beginning      : the last Sunday of March at 02:00
+# Ending         : the last Sunday of October at 03:00 ...
+# http://www.tap.info.tn/en/index.php?option=com_content&task=view&id=1188&Itemid=50
+
+# From Steffen Thorsen (2009-03-16):
+# According to several news sources, Tunisia will not observe DST this year.
+# (Arabic)
+# 
+# http://www.elbashayer.com/?page=viewn&nid=42546
+# 
+# 
+# http://www.babnet.net/kiwidetail-15295.asp
+# 
+#
+# We have also confirmed this with the US embassy in Tunisia.
+# We have a wrap-up about this on the following page:
+# 
+# http://www.timeanddate.com/news/time/tunisia-cancels-dst-2009.html
+# 
+
+# From Alexander Krivenyshev (2009-03-17):
+# Here is a link to Tunis Afrique Presse News Agency
+#
+# Standard time to be kept the whole year long (tap.info.tn):
+#
+# (in English)
+# 
+# http://www.tap.info.tn/en/index.php?option=com_content&task=view&id=26813&Itemid=157
+# 
+#
+# (in Arabic)
+# 
+# http://www.tap.info.tn/ar/index.php?option=com_content&task=view&id=61240&Itemid=1
+# 
+
+# From Arthur David Olson (2009--3-18):
+# The Tunis Afrique Presse News Agency notice contains this: "This measure is due to the fact
+# that the fasting month of ramadan coincides with the period concerned by summer time.
+# Therefore, the standard time will be kept unchanged the whole year long."
+# So foregoing DST seems to be an exception (albeit one that may be repeated in the  future).
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Tunisia	1939	only	-	Apr	15	23:00s	1:00	S
+Rule	Tunisia	1939	only	-	Nov	18	23:00s	0	-
+Rule	Tunisia	1940	only	-	Feb	25	23:00s	1:00	S
+Rule	Tunisia	1941	only	-	Oct	 6	 0:00	0	-
+Rule	Tunisia	1942	only	-	Mar	 9	 0:00	1:00	S
+Rule	Tunisia	1942	only	-	Nov	 2	 3:00	0	-
+Rule	Tunisia	1943	only	-	Mar	29	 2:00	1:00	S
+Rule	Tunisia	1943	only	-	Apr	17	 2:00	0	-
+Rule	Tunisia	1943	only	-	Apr	25	 2:00	1:00	S
+Rule	Tunisia	1943	only	-	Oct	 4	 2:00	0	-
+Rule	Tunisia	1944	1945	-	Apr	Mon>=1	 2:00	1:00	S
+Rule	Tunisia	1944	only	-	Oct	 8	 0:00	0	-
+Rule	Tunisia	1945	only	-	Sep	16	 0:00	0	-
+Rule	Tunisia	1977	only	-	Apr	30	 0:00s	1:00	S
+Rule	Tunisia	1977	only	-	Sep	24	 0:00s	0	-
+Rule	Tunisia	1978	only	-	May	 1	 0:00s	1:00	S
+Rule	Tunisia	1978	only	-	Oct	 1	 0:00s	0	-
+Rule	Tunisia	1988	only	-	Jun	 1	 0:00s	1:00	S
+Rule	Tunisia	1988	1990	-	Sep	lastSun	 0:00s	0	-
+Rule	Tunisia	1989	only	-	Mar	26	 0:00s	1:00	S
+Rule	Tunisia	1990	only	-	May	 1	 0:00s	1:00	S
+Rule	Tunisia	2005	only	-	May	 1	 0:00s	1:00	S
+Rule	Tunisia	2005	only	-	Sep	30	 1:00s	0	-
+Rule	Tunisia	2006	2008	-	Mar	lastSun	 2:00s	1:00	S
+Rule	Tunisia	2006	2008	-	Oct	lastSun	 2:00s	0	-
+Rule	Tunisia	2010	max	-	Mar	lastSun	 2:00s	1:00	S
+Rule	Tunisia	2010	max	-	Oct	lastSun	 2:00s	0	-
+# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
+# more precise 0:09:21.
+# Shanks & Pottenger say the 1911 switch was on Mar 9; go with Howse's Mar 11.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Tunis	0:40:44 -	LMT	1881 May 12
+			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
+			1:00	Tunisia	CE%sT
+
+# Uganda
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Kampala	2:09:40 -	LMT	1928 Jul
+			3:00	-	EAT	1930
+			2:30	-	BEAT	1948
+			2:44:45	-	BEAUT	1957
+			3:00	-	EAT
+
+# Zambia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Lusaka	1:53:08 -	LMT	1903 Mar
+			2:00	-	CAT
+
+# Zimbabwe
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Africa/Harare	2:04:12 -	LMT	1903 Mar
+			2:00	-	CAT
diff --git a/extra/zoneinfo/antarctica b/extra/zoneinfo/antarctica
new file mode 100644
index 0000000000..ef279cbeda
--- /dev/null
+++ b/extra/zoneinfo/antarctica
@@ -0,0 +1,327 @@
+# @(#)antarctica	8.4
+# 
+
+# From Paul Eggert (1999-11-15):
+# To keep things manageable, we list only locations occupied year-round; see
+# 
+# COMNAP - Stations and Bases
+# 
+# and
+# 
+# Summary of the Peri-Antarctic Islands (1998-07-23)
+# 
+# for information.
+# Unless otherwise specified, we have no time zone information.
+#
+# Except for the French entries,
+# I made up all time zone abbreviations mentioned here; corrections welcome!
+# FORMAT is `zzz' and GMTOFF is 0 for locations while uninhabited.
+
+# These rules are stolen from the `europe' file.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	RussAQ	1981	1984	-	Apr	 1	 0:00	1:00	S
+Rule	RussAQ	1981	1983	-	Oct	 1	 0:00	0	-
+Rule	RussAQ	1984	1991	-	Sep	lastSun	 2:00s	0	-
+Rule	RussAQ	1985	1991	-	Mar	lastSun	 2:00s	1:00	S
+Rule	RussAQ	1992	only	-	Mar	lastSat	 23:00	1:00	S
+Rule	RussAQ	1992	only	-	Sep	lastSat	 23:00	0	-
+Rule	RussAQ	1993	max	-	Mar	lastSun	 2:00s	1:00	S
+Rule	RussAQ	1993	1995	-	Sep	lastSun	 2:00s	0	-
+Rule	RussAQ	1996	max	-	Oct	lastSun	 2:00s	0	-
+
+# These rules are stolen from the `southamerica' file.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	ArgAQ	1964	1966	-	Mar	 1	0:00	0	-
+Rule	ArgAQ	1964	1966	-	Oct	15	0:00	1:00	S
+Rule	ArgAQ	1967	only	-	Apr	 2	0:00	0	-
+Rule	ArgAQ	1967	1968	-	Oct	Sun>=1	0:00	1:00	S
+Rule	ArgAQ	1968	1969	-	Apr	Sun>=1	0:00	0	-
+Rule	ArgAQ	1974	only	-	Jan	23	0:00	1:00	S
+Rule	ArgAQ	1974	only	-	May	 1	0:00	0	-
+Rule	ChileAQ	1972	1986	-	Mar	Sun>=9	3:00u	0	-
+Rule	ChileAQ	1974	1987	-	Oct	Sun>=9	4:00u	1:00	S
+Rule	ChileAQ	1987	only	-	Apr	12	3:00u	0	-
+Rule	ChileAQ	1988	1989	-	Mar	Sun>=9	3:00u	0	-
+Rule	ChileAQ	1988	only	-	Oct	Sun>=1	4:00u	1:00	S
+Rule	ChileAQ	1989	only	-	Oct	Sun>=9	4:00u	1:00	S
+Rule	ChileAQ	1990	only	-	Mar	18	3:00u	0	-
+Rule	ChileAQ	1990	only	-	Sep	16	4:00u	1:00	S
+Rule	ChileAQ	1991	1996	-	Mar	Sun>=9	3:00u	0	-
+Rule	ChileAQ	1991	1997	-	Oct	Sun>=9	4:00u	1:00	S
+Rule	ChileAQ	1997	only	-	Mar	30	3:00u	0	-
+Rule	ChileAQ	1998	only	-	Mar	Sun>=9	3:00u	0	-
+Rule	ChileAQ	1998	only	-	Sep	27	4:00u	1:00	S
+Rule	ChileAQ	1999	only	-	Apr	 4	3:00u	0	-
+Rule	ChileAQ	1999	max	-	Oct	Sun>=9	4:00u	1:00	S
+Rule	ChileAQ	2000	max	-	Mar	Sun>=9	3:00u	0	-
+
+
+# Argentina - year-round bases
+# Belgrano II, Confin Coast, -770227-0343737, since 1972-02-05
+# Esperanza, San Martin Land, -6323-05659, since 1952-12-17
+# Jubany, Potter Peninsula, King George Island, -6414-0602320, since 1982-01
+# Marambio, Seymour I, -6414-05637, since 1969-10-29
+# Orcadas, Laurie I, -6016-04444, since 1904-02-22
+# San Martin, Debenham I, -6807-06708, since 1951-03-21
+#	(except 1960-03 / 1976-03-21)
+
+# Australia - territories
+# Heard Island, McDonald Islands (uninhabited)
+#	previously sealers and scientific personnel wintered
+#	
+#	Margaret Turner reports
+#	 (1999-09-30) that they're UTC+5, with no DST;
+#	presumably this is when they have visitors.
+#
+# year-round bases
+# Casey, Bailey Peninsula, -6617+11032, since 1969
+# Davis, Vestfold Hills, -6835+07759, since 1957-01-13
+#	(except 1964-11 - 1969-02)
+# Mawson, Holme Bay, -6736+06253, since 1954-02-13
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Antarctica/Casey	0	-	zzz	1969
+			8:00	-	WST	# Western (Aus) Standard Time
+Zone Antarctica/Davis	0	-	zzz	1957 Jan 13
+			7:00	-	DAVT	1964 Nov # Davis Time
+			0	-	zzz	1969 Feb
+			7:00	-	DAVT
+Zone Antarctica/Mawson	0	-	zzz	1954 Feb 13
+			6:00	-	MAWT	# Mawson Time
+# References:
+# 
+# Casey Weather (1998-02-26)
+# 
+# 
+# Davis Station, Antarctica (1998-02-26)
+# 
+# 
+# Mawson Station, Antarctica (1998-02-25)
+# 
+
+# Brazil - year-round base
+# Comandante Ferraz, King George Island, -6205+05824, since 1983/4
+
+# Chile - year-round bases and towns
+# Escudero, South Shetland Is, -621157-0585735, since 1994
+# Presidente Eduadro Frei, King George Island, -6214-05848, since 1969-03-07
+# General Bernardo O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
+# Capitan Arturo Prat, -6230-05941
+# Villa Las Estrellas (a town), around the Frei base, since 1984-04-09
+# These locations have always used Santiago time; use TZ='America/Santiago'.
+
+# China - year-round bases
+# Great Wall, King George Island, -6213-05858, since 1985-02-20
+# Zhongshan, Larsemann Hills, Prydz Bay, -6922+07623, since 1989-02-26
+
+# France - year-round bases
+#
+# From Antoine Leca (1997-01-20):
+# Time data are from Nicole Pailleau at the IFRTP
+# (French Institute for Polar Research and Technology).
+# She confirms that French Southern Territories and Terre Adelie bases
+# don't observe daylight saving time, even if Terre Adelie supplies came
+# from Tasmania.
+#
+# French Southern Territories with year-round inhabitants
+#
+# Martin-de-Vivies Base, Amsterdam Island, -374105+0773155, since 1950
+# Alfred-Faure Base, Crozet Islands, -462551+0515152, since 1964
+# Port-aux-Francais, Kerguelen Islands, -492110+0701303, since 1951;
+#	whaling & sealing station operated 1908/1914, 1920/1929, and 1951/1956
+#
+# St Paul Island - near Amsterdam, uninhabited
+#	fishing stations operated variously 1819/1931
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Indian/Kerguelen	0	-	zzz	1950	# Port-aux-Francais
+			5:00	-	TFT	# ISO code TF Time
+#
+# year-round base in the main continent
+# Dumont-d'Urville, Ile des Petrels, -6640+14001, since 1956-11
+#
+# Another base at Port-Martin, 50km east, began operation in 1947.
+# It was destroyed by fire on 1952-01-14.
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Antarctica/DumontDUrville 0 -	zzz	1947
+			10:00	-	PMT	1952 Jan 14 # Port-Martin Time
+			0	-	zzz	1956 Nov
+			10:00	-	DDUT	# Dumont-d'Urville Time
+# Reference:
+# 
+# Dumont d'Urville Station (2005-12-05)
+# 
+
+# Germany - year-round base
+# Georg von Neumayer, -7039-00815
+
+# India - year-round base
+# Dakshin Gangotri, -7005+01200
+
+# Japan - year-round bases
+# Dome Fuji, -7719+03942
+# Syowa, -690022+0393524
+#
+# From Hideyuki Suzuki (1999-02-06):
+# In all Japanese stations, +0300 is used as the standard time.
+#
+# Syowa station, which is the first antarctic station of Japan,
+# was established on 1957-01-29.  Since Syowa station is still the main
+# station of Japan, it's appropriate for the principal location.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Antarctica/Syowa	0	-	zzz	1957 Jan 29
+			3:00	-	SYOT	# Syowa Time
+# See:
+# 
+# NIPR Antarctic Research Activities (1999-08-17)
+# 
+
+# S Korea - year-round base
+# King Sejong, King George Island, -6213-05847, since 1988
+
+# New Zealand - claims
+# Balleny Islands (never inhabited)
+# Scott Island (never inhabited)
+#
+# year-round base
+# Scott, Ross Island, since 1957-01, is like Antarctica/McMurdo.
+#
+# These rules for New Zealand are stolen from the `australasia' file.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	NZAQ	1974	only	-	Nov	 3	2:00s	1:00	D
+Rule	NZAQ	1975	1988	-	Oct	lastSun	2:00s	1:00	D
+Rule	NZAQ	1989	only	-	Oct	 8	2:00s	1:00	D
+Rule	NZAQ	1990	2006	-	Oct	Sun>=1	2:00s	1:00	D
+Rule	NZAQ	1975	only	-	Feb	23	2:00s	0	S
+Rule	NZAQ	1976	1989	-	Mar	Sun>=1	2:00s	0	S
+Rule	NZAQ	1990	2007	-	Mar	Sun>=15	2:00s	0	S
+Rule	NZAQ	2007	max	-	Sep	lastSun	2:00s	1:00	D
+Rule	NZAQ	2008	max	-	Apr	Sun>=1	2:00s	0	S
+
+# Norway - territories
+# Bouvet (never inhabited)
+#
+# claims
+# Peter I Island (never inhabited)
+
+# Poland - year-round base
+# Arctowski, King George Island, -620945-0582745, since 1977
+
+# Russia - year-round bases
+# Bellingshausen, King George Island, -621159-0585337, since 1968-02-22
+# Mirny, Davis coast, -6633+09301, since 1956-02
+# Molodezhnaya, Alasheyev Bay, -6740+04551,
+#	year-round from 1962-02 to 1999-07-01
+# Novolazarevskaya, Queen Maud Land, -7046+01150,
+#	year-round from 1960/61 to 1992
+
+# Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11
+# 
+# From Craig Mundell (1994-12-15):
+# Vostok, which is one of the Russian stations, is set on the same
+# time as Moscow, Russia.
+#
+# From Lee Hotz (2001-03-08):
+# I queried the folks at Columbia who spent the summer at Vostok and this is
+# what they had to say about time there:
+# ``in the US Camp (East Camp) we have been on New Zealand (McMurdo)
+# time, which is 12 hours ahead of GMT. The Russian Station Vostok was
+# 6 hours behind that (although only 2 miles away, i.e. 6 hours ahead
+# of GMT). This is a time zone I think two hours east of Moscow. The
+# natural time zone is in between the two: 8 hours ahead of GMT.''
+#
+# From Paul Eggert (2001-05-04):
+# This seems to be hopelessly confusing, so I asked Lee Hotz about it
+# in person.  He said that some Antartic locations set their local
+# time so that noon is the warmest part of the day, and that this
+# changes during the year and does not necessarily correspond to mean
+# solar noon.  So the Vostok time might have been whatever the clocks
+# happened to be during their visit.  So we still don't really know what time
+# it is at Vostok.  But we'll guess UTC+6.
+#
+Zone Antarctica/Vostok	0	-	zzz	1957 Dec 16
+			6:00	-	VOST	# Vostok time
+
+# S Africa - year-round bases
+# Marion Island, -4653+03752
+# Sanae, -7141-00250
+
+# UK
+#
+# British Antarctic Territories (BAT) claims
+# South Orkney Islands
+#	scientific station from 1903
+#	whaling station at Signy I 1920/1926
+# South Shetland Islands
+#
+# year-round bases
+# Bird Island, South Georgia, -5400-03803, since 1983
+# Deception Island, -6259-06034, whaling station 1912/1931,
+#	scientific station 1943/1967,
+#	previously sealers and a scientific expedition wintered by accident,
+#	and a garrison was deployed briefly
+# Halley, Coates Land, -7535-02604, since 1956-01-06
+#	Halley is on a moving ice shelf and is periodically relocated
+#	so that it is never more than 10km from its nominal location.
+# Rothera, Adelaide Island, -6734-6808, since 1976-12-01
+#
+# From Paul Eggert (2002-10-22)
+#  says Rothera is -03 all year.
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Antarctica/Rothera	0	-	zzz	1976 Dec  1
+			-3:00	-	ROTT	# Rothera time
+
+# Uruguay - year round base
+# Artigas, King George Island, -621104-0585107
+
+# USA - year-round bases
+#
+# Palmer, Anvers Island, since 1965 (moved 2 miles in 1968)
+#
+# From Ethan Dicks (1996-10-06):
+# It keeps the same time as Punta Arenas, Chile, because, just like us
+# and the South Pole, that's the other end of their supply line....
+# I verified with someone who was there that since 1980,
+# Palmer has followed Chile.  Prior to that, before the Falklands War,
+# Palmer used to be supplied from Argentina.
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Antarctica/Palmer	0	-	zzz	1965
+			-4:00	ArgAQ	AR%sT	1969 Oct 5
+			-3:00	ArgAQ	AR%sT	1982 May
+			-4:00	ChileAQ	CL%sT
+#
+#
+# McMurdo, Ross Island, since 1955-12
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Antarctica/McMurdo	0	-	zzz	1956
+			12:00	NZAQ	NZ%sT
+#
+# Amundsen-Scott, South Pole, continuously occupied since 1956-11-20
+#
+# From Paul Eggert (1996-09-03):
+# Normally it wouldn't have a separate entry, since it's like the
+# larger Antarctica/McMurdo since 1970, but it's too famous to omit.
+#
+# From Chris Carrier (1996-06-27):
+# Siple, the first commander of the South Pole station,
+# stated that he would have liked to have kept GMT at the station,
+# but that he found it more convenient to keep GMT+12
+# as supplies for the station were coming from McMurdo Sound,
+# which was on GMT+12 because New Zealand was on GMT+12 all year
+# at that time (1957).  (Source: Siple's book 90 degrees SOUTH.)
+#
+# From Susan Smith
+# http://www.cybertours.com/whs/pole10.html
+# (1995-11-13 16:24:56 +1300, no longer available):
+# We use the same time as McMurdo does.
+# And they use the same time as Christchurch, NZ does....
+# One last quirk about South Pole time.
+# All the electric clocks are usually wrong.
+# Something about the generators running at 60.1hertz or something
+# makes all of the clocks run fast.  So every couple of days,
+# we have to go around and set them back 5 minutes or so.
+# Maybe if we let them run fast all of the time, we'd get to leave here sooner!!
+#
+Link	Antarctica/McMurdo	Antarctica/South_Pole
diff --git a/extra/zoneinfo/asia b/extra/zoneinfo/asia
new file mode 100644
index 0000000000..2c3dc38b8f
--- /dev/null
+++ b/extra/zoneinfo/asia
@@ -0,0 +1,2152 @@
+# @(#)asia	8.30
+# 
+
+# This data is by no means authoritative; if you think you know better,
+# go ahead and edit the file (and please send any changes to
+# tz@elsie.nci.nih.gov for general use in the future).
+
+# From Paul Eggert (2006-03-22):
+#
+# A good source for time zone historical data outside the U.S. is
+# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
+# San Diego: ACS Publications, Inc. (2003).
+#
+# Gwillim Law writes that a good source
+# for recent time zone data is the International Air Transport
+# Association's Standard Schedules Information Manual (IATA SSIM),
+# published semiannually.  Law sent in several helpful summaries
+# of the IATA's data after 1990.
+#
+# Except where otherwise noted, Shanks & Pottenger is the source for
+# entries through 1990, and IATA SSIM is the source for entries afterwards.
+#
+# Another source occasionally used is Edward W. Whitman, World Time Differences,
+# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
+# I found in the UCLA library.
+#
+# A reliable and entertaining source about time zones is
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
+#
+# I invented the abbreviations marked `*' in the following table;
+# the rest are from earlier versions of this file, or from other sources.
+# Corrections are welcome!
+#	     std  dst
+#	     LMT	Local Mean Time
+#	2:00 EET  EEST	Eastern European Time
+#	2:00 IST  IDT	Israel
+#	3:00 AST  ADT	Arabia*
+#	3:30 IRST IRDT	Iran
+#	4:00 GST	Gulf*
+#	5:30 IST	India
+#	7:00 ICT	Indochina*
+#	7:00 WIT	west Indonesia
+#	8:00 CIT	central Indonesia
+#	8:00 CST	China
+#	9:00 CJT	Central Japanese Time (1896/1937)*
+#	9:00 EIT	east Indonesia
+#	9:00 JST  JDT	Japan
+#	9:00 KST  KDT	Korea
+#	9:30 CST	(Australian) Central Standard Time
+#
+# See the `europe' file for Russia and Turkey in Asia.
+
+# From Guy Harris:
+# Incorporates data for Singapore from Robert Elz' asia 1.1, as well as
+# additional information from Tom Yap, Sun Microsystems Intercontinental
+# Technical Support (including a page from the Official Airline Guide -
+# Worldwide Edition).  The names for time zones are guesses.
+
+###############################################################################
+
+# These rules are stolen from the `europe' file.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	EUAsia	1981	max	-	Mar	lastSun	 1:00u	1:00	S
+Rule	EUAsia	1979	1995	-	Sep	lastSun	 1:00u	0	-
+Rule	EUAsia	1996	max	-	Oct	lastSun	 1:00u	0	-
+Rule E-EurAsia	1981	max	-	Mar	lastSun	 0:00	1:00	S
+Rule E-EurAsia	1979	1995	-	Sep	lastSun	 0:00	0	-
+Rule E-EurAsia	1996	max	-	Oct	lastSun	 0:00	0	-
+Rule RussiaAsia	1981	1984	-	Apr	1	 0:00	1:00	S
+Rule RussiaAsia	1981	1983	-	Oct	1	 0:00	0	-
+Rule RussiaAsia	1984	1991	-	Sep	lastSun	 2:00s	0	-
+Rule RussiaAsia	1985	1991	-	Mar	lastSun	 2:00s	1:00	S
+Rule RussiaAsia	1992	only	-	Mar	lastSat	23:00	1:00	S
+Rule RussiaAsia	1992	only	-	Sep	lastSat	23:00	0	-
+Rule RussiaAsia	1993	max	-	Mar	lastSun	 2:00s	1:00	S
+Rule RussiaAsia	1993	1995	-	Sep	lastSun	 2:00s	0	-
+Rule RussiaAsia	1996	max	-	Oct	lastSun	 2:00s	0	-
+
+# Afghanistan
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Kabul	4:36:48 -	LMT	1890
+			4:00	-	AFT	1945
+			4:30	-	AFT
+
+# Armenia
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger have Yerevan switching to 3:00 (with Russian DST)
+# in spring 1991, then to 4:00 with no DST in fall 1995, then
+# readopting Russian DST in 1997.  Go with Shanks & Pottenger, even
+# when they disagree with others.  Edgar Der-Danieliantz
+# reported (1996-05-04) that Yerevan probably wouldn't use DST
+# in 1996, though it did use DST in 1995.  IATA SSIM (1991/1998) reports that
+# Armenia switched from 3:00 to 4:00 in 1998 and observed DST after 1991,
+# but started switching at 3:00s in 1998.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Yerevan	2:58:00 -	LMT	1924 May  2
+			3:00	-	YERT	1957 Mar    # Yerevan Time
+			4:00 RussiaAsia YER%sT	1991 Mar 31 2:00s
+			3:00	1:00	YERST	1991 Sep 23 # independence
+			3:00 RussiaAsia	AM%sT	1995 Sep 24 2:00s
+			4:00	-	AMT	1997
+			4:00 RussiaAsia	AM%sT
+
+# Azerbaijan
+# From Rustam Aliyev of the Azerbaijan Internet Forum (2005-10-23):
+# According to the resolution of Cabinet of Ministers, 1997
+# Resolution available at: http://aif.az/docs/daylight_res.pdf
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Azer	1997	max	-	Mar	lastSun	 4:00	1:00	S
+Rule	Azer	1997	max	-	Oct	lastSun	 5:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Baku	3:19:24 -	LMT	1924 May  2
+			3:00	-	BAKT	1957 Mar    # Baku Time
+			4:00 RussiaAsia BAK%sT	1991 Mar 31 2:00s
+			3:00	1:00	BAKST	1991 Aug 30 # independence
+			3:00 RussiaAsia	AZ%sT	1992 Sep lastSat 23:00
+			4:00	-	AZT	1996 # Azerbaijan time
+			4:00	EUAsia	AZ%sT	1997
+			4:00	Azer	AZ%sT
+
+# Bahrain
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
+			4:00	-	GST	1972 Jun
+			3:00	-	AST
+
+# Bangladesh
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Dhaka	6:01:40 -	LMT	1890
+			5:53:20	-	HMT	1941 Oct    # Howrah Mean Time?
+			6:30	-	BURT	1942 May 15 # Burma Time
+			5:30	-	IST	1942 Sep
+			6:30	-	BURT	1951 Sep 30
+			6:00	-	DACT	1971 Mar 26 # Dacca Time
+			6:00	-	BDT	# Bangladesh Time
+
+# Bhutan
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Thimphu	5:58:36 -	LMT	1947 Aug 15 # or Thimbu
+			5:30	-	IST	1987 Oct
+			6:00	-	BTT	# Bhutan Time
+
+# British Indian Ocean Territory
+# Whitman and the 1995 CIA time zone map say 5:00, but the
+# 1997 and later maps say 6:00.  Assume the switch occurred in 1996.
+# We have no information as to when standard time was introduced;
+# assume it occurred in 1907, the same year as Mauritius (which
+# then contained the Chagos Archipelago).
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Indian/Chagos	4:49:40	-	LMT	1907
+			5:00	-	IOT	1996 # BIOT Time
+			6:00	-	IOT
+
+# Brunei
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Brunei	7:39:40 -	LMT	1926 Mar   # Bandar Seri Begawan
+			7:30	-	BNT	1933
+			8:00	-	BNT
+
+# Burma / Myanmar
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Rangoon	6:24:40 -	LMT	1880		# or Yangon
+			6:24:36	-	RMT	1920	   # Rangoon Mean Time?
+			6:30	-	BURT	1942 May   # Burma Time
+			9:00	-	JST	1945 May 3
+			6:30	-	MMT		   # Myanmar Time
+
+# Cambodia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Phnom_Penh	6:59:40 -	LMT	1906 Jun  9
+			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
+			7:00	-	ICT	1912 May
+			8:00	-	ICT	1931 May
+			7:00	-	ICT
+
+# China
+
+# From Guy Harris:
+# People's Republic of China.  Yes, they really have only one time zone.
+
+# From Bob Devine (1988-01-28):
+# No they don't.  See TIME mag, 1986-02-17 p.52.  Even though
+# China is across 4 physical time zones, before Feb 1, 1986 only the
+# Peking (Bejing) time zone was recognized.  Since that date, China
+# has two of 'em -- Peking's and Urumqi (named after the capital of
+# the Xinjiang Uyghur Autonomous Region).  I don't know about DST for it.
+#
+# . . .I just deleted the DST table and this editor makes it too
+# painful to suck in another copy..  So, here is what I have for
+# DST start/end dates for Peking's time zone (info from AP):
+#
+#     1986 May 4 - Sept 14
+#     1987 mid-April - ??
+
+# From U. S. Naval Observatory (1989-01-19):
+# CHINA               8 H  AHEAD OF UTC  ALL OF CHINA, INCL TAIWAN
+# CHINA               9 H  AHEAD OF UTC  APR 17 - SEP 10
+
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger write that China (except for Hong Kong and Macau)
+# has had a single time zone since 1980 May 1, observing summer DST
+# from 1986 through 1991; this contradicts Devine's
+# note about Time magazine, though apparently _something_ happened in 1986.
+# Go with Shanks & Pottenger for now.  I made up names for the other
+# pre-1980 time zones.
+
+# From Shanks & Pottenger:
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Shang	1940	only	-	Jun	 3	0:00	1:00	D
+Rule	Shang	1940	1941	-	Oct	 1	0:00	0	S
+Rule	Shang	1941	only	-	Mar	16	0:00	1:00	D
+Rule	PRC	1986	only	-	May	 4	0:00	1:00	D
+Rule	PRC	1986	1991	-	Sep	Sun>=11	0:00	0	S
+Rule	PRC	1987	1991	-	Apr	Sun>=10	0:00	1:00	D
+
+# From Anthony Fok (2001-12-20):
+# BTW, I did some research on-line and found some info regarding these five
+# historic timezones from some Taiwan websites.  And yes, there are official
+# Chinese names for these locales (before 1949).
+#
+# From Jesper Norgaard Welen (2006-07-14):
+# I have investigated the timezones around 1970 on the
+# http://www.astro.com/atlas site [with provinces and county
+# boundaries summarized below]....  A few other exceptions were two
+# counties on the Sichuan side of the Xizang-Sichuan border,
+# counties Dege and Baiyu which lies on the Sichuan side and are
+# therefore supposed to be GMT+7, Xizang region being GMT+6, but Dege
+# county is GMT+8 according to astro.com while Baiyu county is GMT+6
+# (could be true), for the moment I am assuming that those two
+# counties are mistakes in the astro.com data.
+
+# From Paul Eggert (2008-02-11):
+# I just now checked Google News for western news sources that talk
+# about China's single time zone, and couldn't find anything before 1986
+# talking about China being in one time zone.  (That article was: Jim
+# Mann, "A clumsy embrace for another western custom: China on daylight
+# time--sort of", Los Angeles Times, 1986-05-05.  By the way, this
+# article confirms the tz database's data claiming that China began
+# observing daylight saving time in 1986.
+#
+# From Thomas S. Mullaney (2008-02-11):
+# I think you're combining two subjects that need to treated 
+# separately: daylight savings (which, you're correct, wasn't 
+# implemented until the 1980s) and the unified time zone centered near 
+# Beijing (which was implemented in 1949). Briefly, there was also a 
+# "Lhasa Time" in Tibet and "Urumqi Time" in Xinjiang. The first was 
+# ceased, and the second eventually recognized (again, in the 1980s).
+#
+# From Paul Eggert (2008-06-30):
+# There seems to be a good chance China switched to a single time zone in 1949
+# rather than in 1980 as Shanks & Pottenger have it, but we don't have a
+# reliable documentary source saying so yet, so for now we still go with
+# Shanks & Pottenger.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+# Changbai Time ("Long-white Time", Long-white = Heilongjiang area)
+# Heilongjiang (except Mohe county), Jilin
+Zone	Asia/Harbin	8:26:44	-	LMT	1928 # or Haerbin
+			8:30	-	CHAT	1932 Mar # Changbai Time
+			8:00	-	CST	1940
+			9:00	-	CHAT	1966 May
+			8:30	-	CHAT	1980 May
+			8:00	PRC	C%sT
+# Zhongyuan Time ("Central plain Time")
+# most of China
+Zone	Asia/Shanghai	8:05:52	-	LMT	1928
+			8:00	Shang	C%sT	1949
+			8:00	PRC	C%sT
+# Long-shu Time (probably due to Long and Shu being two names of that area)
+# Guangxi, Guizhou, Hainan, Ningxia, Sichuan, Shaanxi, and Yunnan;
+# most of Gansu; west Inner Mongolia; west Qinghai; and the Guangdong
+# counties Deqing, Enping, Kaiping, Luoding, Taishan, Xinxing,
+# Yangchun, Yangjiang, Yu'nan, and Yunfu.
+Zone	Asia/Chongqing	7:06:20	-	LMT	1928 # or Chungking
+			7:00	-	LONT	1980 May # Long-shu Time
+			8:00	PRC	C%sT
+# Xin-zang Time ("Xinjiang-Tibet Time")
+# The Gansu counties Aksay, Anxi, Dunhuang, Subei; west Qinghai;
+# the Guangdong counties  Xuwen, Haikang, Suixi, Lianjiang,
+# Zhanjiang, Wuchuan, Huazhou, Gaozhou, Maoming, Dianbai, and Xinyi;
+# east Tibet, including Lhasa, Chamdo, Shigaise, Jimsar, Shawan and Hutubi;
+# east Xinjiang, including Urumqi, Turpan, Karamay, Korla, Minfeng, Jinghe,
+# Wusu, Qiemo, Xinyan, Wulanwusu, Jinghe, Yumin, Tacheng, Tuoli, Emin,
+# Shihezi, Changji, Yanqi, Heshuo, Tuokexun, Tulufan, Shanshan, Hami,
+# Fukang, Kuitun, Kumukuli, Miquan, Qitai, and Turfan.
+Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
+			6:00	-	URUT	1980 May # Urumqi Time
+			8:00	PRC	C%sT
+# Kunlun Time
+# West Tibet, including Pulan, Aheqi, Shufu, Shule;
+# West Xinjiang, including Aksu, Atushi, Yining, Hetian, Cele, Luopu, Nileke,
+# Zhaosu, Tekesi, Gongliu, Chabuchaer, Huocheng, Bole, Pishan, Suiding,
+# and Yarkand.
+Zone	Asia/Kashgar	5:03:56	-	LMT	1928 # or Kashi or Kaxgar
+			5:30	-	KAST	1940	 # Kashgar Time
+			5:00	-	KAST	1980 May
+			8:00	PRC	C%sT
+
+# Hong Kong (Xianggang)
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	HK	1946	only	-	Apr	20	3:30	1:00	S
+Rule	HK	1946	only	-	Dec	1	3:30	0	-
+Rule	HK	1947	only	-	Apr	13	3:30	1:00	S
+Rule	HK	1947	only	-	Dec	30	3:30	0	-
+Rule	HK	1948	only	-	May	2	3:30	1:00	S
+Rule	HK	1948	1952	-	Oct	lastSun	3:30	0	-
+Rule	HK	1949	1953	-	Apr	Sun>=1	3:30	1:00	S
+Rule	HK	1953	only	-	Nov	1	3:30	0	-
+Rule	HK	1954	1964	-	Mar	Sun>=18	3:30	1:00	S
+Rule	HK	1954	only	-	Oct	31	3:30	0	-
+Rule	HK	1955	1964	-	Nov	Sun>=1	3:30	0	-
+Rule	HK	1965	1977	-	Apr	Sun>=16	3:30	1:00	S
+Rule	HK	1965	1977	-	Oct	Sun>=16	3:30	0	-
+Rule	HK	1979	1980	-	May	Sun>=8	3:30	1:00	S
+Rule	HK	1979	1980	-	Oct	Sun>=16	3:30	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Hong_Kong	7:36:36 -	LMT	1904 Oct 30
+			8:00	HK	HK%sT
+
+
+###############################################################################
+
+# Taiwan
+
+# Shanks & Pottenger write that Taiwan observed DST during 1945, when it
+# was still controlled by Japan.  This is hard to believe, but we don't
+# have any other information.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Taiwan	1945	1951	-	May	1	0:00	1:00	D
+Rule	Taiwan	1945	1951	-	Oct	1	0:00	0	S
+Rule	Taiwan	1952	only	-	Mar	1	0:00	1:00	D
+Rule	Taiwan	1952	1954	-	Nov	1	0:00	0	S
+Rule	Taiwan	1953	1959	-	Apr	1	0:00	1:00	D
+Rule	Taiwan	1955	1961	-	Oct	1	0:00	0	S
+Rule	Taiwan	1960	1961	-	Jun	1	0:00	1:00	D
+Rule	Taiwan	1974	1975	-	Apr	1	0:00	1:00	D
+Rule	Taiwan	1974	1975	-	Oct	1	0:00	0	S
+Rule	Taiwan	1980	only	-	Jun	30	0:00	1:00	D
+Rule	Taiwan	1980	only	-	Sep	30	0:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Taipei	8:06:00 -	LMT	1896 # or Taibei or T'ai-pei
+			8:00	Taiwan	C%sT
+
+# Macau (Macao, Aomen)
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Macau	1961	1962	-	Mar	Sun>=16	3:30	1:00	S
+Rule	Macau	1961	1964	-	Nov	Sun>=1	3:30	0	-
+Rule	Macau	1963	only	-	Mar	Sun>=16	0:00	1:00	S
+Rule	Macau	1964	only	-	Mar	Sun>=16	3:30	1:00	S
+Rule	Macau	1965	only	-	Mar	Sun>=16	0:00	1:00	S
+Rule	Macau	1965	only	-	Oct	31	0:00	0	-
+Rule	Macau	1966	1971	-	Apr	Sun>=16	3:30	1:00	S
+Rule	Macau	1966	1971	-	Oct	Sun>=16	3:30	0	-
+Rule	Macau	1972	1974	-	Apr	Sun>=15	0:00	1:00	S
+Rule	Macau	1972	1973	-	Oct	Sun>=15	0:00	0	-
+Rule	Macau	1974	1977	-	Oct	Sun>=15	3:30	0	-
+Rule	Macau	1975	1977	-	Apr	Sun>=15	3:30	1:00	S
+Rule	Macau	1978	1980	-	Apr	Sun>=15	0:00	1:00	S
+Rule	Macau	1978	1980	-	Oct	Sun>=15	0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Macau	7:34:20 -	LMT	1912
+			8:00	Macau	MO%sT	1999 Dec 20 # return to China
+			8:00	PRC	C%sT
+
+
+###############################################################################
+
+# Cyprus
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Cyprus	1975	only	-	Apr	13	0:00	1:00	S
+Rule	Cyprus	1975	only	-	Oct	12	0:00	0	-
+Rule	Cyprus	1976	only	-	May	15	0:00	1:00	S
+Rule	Cyprus	1976	only	-	Oct	11	0:00	0	-
+Rule	Cyprus	1977	1980	-	Apr	Sun>=1	0:00	1:00	S
+Rule	Cyprus	1977	only	-	Sep	25	0:00	0	-
+Rule	Cyprus	1978	only	-	Oct	2	0:00	0	-
+Rule	Cyprus	1979	1997	-	Sep	lastSun	0:00	0	-
+Rule	Cyprus	1981	1998	-	Mar	lastSun	0:00	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Nicosia	2:13:28 -	LMT	1921 Nov 14
+			2:00	Cyprus	EE%sT	1998 Sep
+			2:00	EUAsia	EE%sT
+# IATA SSIM (1998-09) has Cyprus using EU rules for the first time.
+
+# Classically, Cyprus belongs to Asia; e.g. see Herodotus, Histories, I.72.
+# However, for various reasons many users expect to find it under Europe.
+Link	Asia/Nicosia	Europe/Nicosia
+
+# Georgia
+# From Paul Eggert (1994-11-19):
+# Today's _Economist_ (p 60) reports that Georgia moved its clocks forward
+# an hour recently, due to a law proposed by Zurab Murvanidze,
+# an MP who went on a hunger strike for 11 days to force discussion about it!
+# We have no details, but we'll guess they didn't move the clocks back in fall.
+#
+# From Mathew Englander, quoting AP (1996-10-23 13:05-04):
+# Instead of putting back clocks at the end of October, Georgia
+# will stay on daylight savings time this winter to save energy,
+# President Eduard Shevardnadze decreed Wednesday.
+#
+# From the BBC via Joseph S. Myers (2004-06-27):
+#
+# Georgia moved closer to Western Europe on Sunday...  The former Soviet
+# republic has changed its time zone back to that of Moscow.  As a result it
+# is now just four hours ahead of Greenwich Mean Time, rather than five hours
+# ahead.  The switch was decreed by the pro-Western president of Georgia,
+# Mikhail Saakashvili, who said the change was partly prompted by the process
+# of integration into Europe.
+
+# From Teimuraz Abashidze (2005-11-07):
+# Government of Georgia ... decided to NOT CHANGE daylight savings time on
+# [Oct.] 30, as it was done before during last more than 10 years.
+# Currently, we are in fact GMT +4:00, as before 30 October it was GMT
+# +3:00.... The problem is, there is NO FORMAL LAW or governmental document
+# about it.  As far as I can find, I was told, that there is no document,
+# because we just DIDN'T ISSUE document about switching to winter time....
+# I don't know what can be done, especially knowing that some years ago our
+# DST rules where changed THREE TIMES during one month.
+
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Tbilisi	2:59:16 -	LMT	1880
+			2:59:16	-	TBMT	1924 May  2 # Tbilisi Mean Time
+			3:00	-	TBIT	1957 Mar    # Tbilisi Time
+			4:00 RussiaAsia TBI%sT	1991 Mar 31 2:00s
+			3:00	1:00	TBIST	1991 Apr  9 # independence
+			3:00 RussiaAsia GE%sT	1992 # Georgia Time
+			3:00 E-EurAsia	GE%sT	1994 Sep lastSun
+			4:00 E-EurAsia	GE%sT	1996 Oct lastSun
+			4:00	1:00	GEST	1997 Mar lastSun
+			4:00 E-EurAsia	GE%sT	2004 Jun 27
+			3:00 RussiaAsia	GE%sT	2005 Mar lastSun 2:00
+			4:00	-	GET
+
+# East Timor
+
+# See Indonesia for the 1945 transition.
+
+# From Joao Carrascalao, brother of the former governor of East Timor, in
+# 
+# East Timor may be late for its millennium
+#  (1999-12-26/31):
+# Portugal tried to change the time forward in 1974 because the sun
+# rises too early but the suggestion raised a lot of problems with the
+# Timorese and I still don't think it would work today because it
+# conflicts with their way of life.
+
+# From Paul Eggert (2000-12-04):
+# We don't have any record of the above attempt.
+# Most likely our records are incomplete, but we have no better data.
+
+# 
+# From Manoel de Almeida e Silva, Deputy Spokesman for the UN Secretary-General
+# (2000-08-16):
+# The Cabinet of the East Timor Transition Administration decided
+# today to advance East Timor's time by one hour.  The time change,
+# which will be permanent, with no seasonal adjustment, will happen at
+# midnight on Saturday, September 16.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Dili	8:22:20 -	LMT	1912
+			8:00	-	TLT	1942 Feb 21 23:00 # E Timor Time
+			9:00	-	JST	1945 Sep 23
+			9:00	-	TLT	1976 May  3
+			8:00	-	CIT	2000 Sep 17 00:00
+			9:00	-	TLT
+
+# India
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Kolkata	5:53:28 -	LMT	1880	# Kolkata
+			5:53:20	-	HMT	1941 Oct    # Howrah Mean Time?
+			6:30	-	BURT	1942 May 15 # Burma Time
+			5:30	-	IST	1942 Sep
+			5:30	1:00	IST	1945 Oct 15
+			5:30	-	IST
+# The following are like Asia/Kolkata:
+#	Andaman Is
+#	Lakshadweep (Laccadive, Minicoy and Amindivi Is)
+#	Nicobar Is
+
+# Indonesia
+#
+# From Gwillim Law (2001-05-28), overriding Shanks & Pottenger:
+# 
+# says that Indonesia's time zones changed on 1988-01-01.  Looking at some
+# time zone maps, I think that must refer to Western Borneo (Kalimantan Barat
+# and Kalimantan Tengah) switching from UTC+8 to UTC+7.
+#
+# From Paul Eggert (2007-03-10):
+# Here is another correction to Shanks & Pottenger.
+# JohnTWB writes that Japanese forces did not surrender control in
+# Indonesia until 1945-09-01 00:00 at the earliest (in Jakarta) and
+# other formal surrender ceremonies were September 9, 11, and 13, plus
+# September 12 for the regional surrender to Mountbatten in Singapore.
+# These would be the earliest possible times for a change.
+# Regimes horaires pour le monde entier, by Henri Le Corre, (Editions
+# Traditionnelles, 1987, Paris) says that Java and Madura switched
+# from JST to UTC+07:30 on 1945-09-23, and gives 1944-09-01 for Jayapura
+# (Hollandia).  For now, assume all Indonesian locations other than Jayapura
+# switched on 1945-09-23.
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Asia/Jakarta	7:07:12 -	LMT	1867 Aug 10
+# Shanks & Pottenger say the next transition was at 1924 Jan 1 0:13,
+# but this must be a typo.
+			7:07:12	-	JMT	1923 Dec 31 23:47:12 # Jakarta
+			7:20	-	JAVT	1932 Nov	 # Java Time
+			7:30	-	WIT	1942 Mar 23
+			9:00	-	JST	1945 Sep 23
+			7:30	-	WIT	1948 May
+			8:00	-	WIT	1950 May
+			7:30	-	WIT	1964
+			7:00	-	WIT
+Zone Asia/Pontianak	7:17:20	-	LMT	1908 May
+			7:17:20	-	PMT	1932 Nov    # Pontianak MT
+			7:30	-	WIT	1942 Jan 29
+			9:00	-	JST	1945 Sep 23
+			7:30	-	WIT	1948 May
+			8:00	-	WIT	1950 May
+			7:30	-	WIT	1964
+			8:00	-	CIT	1988 Jan  1
+			7:00	-	WIT
+Zone Asia/Makassar	7:57:36 -	LMT	1920
+			7:57:36	-	MMT	1932 Nov    # Macassar MT
+			8:00	-	CIT	1942 Feb  9
+			9:00	-	JST	1945 Sep 23
+			8:00	-	CIT
+Zone Asia/Jayapura	9:22:48 -	LMT	1932 Nov
+			9:00	-	EIT	1944 Sep  1
+			9:30	-	CST	1964
+			9:00	-	EIT
+
+# Iran
+
+# From Roozbeh Pournader (2003-03-15):
+# This is an English translation of what I just found (originally in Persian).
+# The Gregorian dates in brackets are mine:
+#
+#	Official Newspaper No. 13548-1370/6/25 [1991-09-16]
+#	No. 16760/T233 H				1370/6/10 [1991-09-01]
+#
+#	The Rule About Change of the Official Time of the Country
+#
+#	The Board of Ministers, in the meeting dated 1370/5/23 [1991-08-14],
+#	based on the suggestion number 2221/D dated 1370/4/22 [1991-07-13]
+#	of the Country's Organization for Official and Employment Affairs,
+#	and referring to the law for equating the working hours of workers
+#	and officers in the whole country dated 1359/4/23 [1980-07-14], and
+#	for synchronizing the official times of the country, agreed that:
+#
+#	The official time of the country will should move forward one hour
+#	at the 24[:00] hours of the first day of Farvardin and should return
+#	to its previous state at the 24[:00] hours of the 30th day of
+#	Shahrivar.
+#
+#	First Deputy to the President - Hassan Habibi
+#
+# From personal experience, that agrees with what has been followed
+# for at least the last 5 years.  Before that, for a few years, the
+# date used was the first Thursday night of Farvardin and the last
+# Thursday night of Shahrivar, but I can't give exact dates....
+# I have also changed the abbreviations to what is considered correct
+# here in Iran, IRST for regular time and IRDT for daylight saving time.
+#
+# From Roozbeh Pournader (2005-04-05):
+# The text of the Iranian law, in effect since 1925, clearly mentions
+# that the true solar year is the measure, and there is no arithmetic
+# leap year calculation involved.  There has never been any serious
+# plan to change that law....
+#
+# From Paul Eggert (2006-03-22):
+# Go with Shanks & Pottenger before Sept. 1991, and with Pournader thereafter.
+# I used Ed Reingold's cal-persia in GNU Emacs 21.2 to check Persian dates,
+# stopping after 2037 when 32-bit time_t's overflow.
+# That cal-persia used Birashk's approximation, which disagrees with the solar
+# calendar predictions for the year 2025, so I corrected those dates by hand.
+#
+# From Oscar van Vlijmen (2005-03-30), writing about future
+# discrepancies between cal-persia and the Iranian calendar:
+# For 2091 solar-longitude-after yields 2091-03-20 08:40:07.7 UT for
+# the vernal equinox and that gets so close to 12:00 some local
+# Iranian time that the definition of the correct location needs to be
+# known exactly, amongst other factors.  2157 is even closer:
+# 2157-03-20 08:37:15.5 UT.  But the Gregorian year 2025 should give
+# no interpretation problem whatsoever.  By the way, another instant
+# in the near future where there will be a discrepancy between
+# arithmetical and astronomical Iranian calendars will be in 2058:
+# vernal equinox on 2058-03-20 09:03:05.9 UT.  The Java version of
+# Reingold's/Dershowitz' calculator gives correctly the Gregorian date
+# 2058-03-21 for 1 Farvardin 1437 (astronomical).
+#
+# From Steffen Thorsen (2006-03-22):
+# Several of my users have reported that Iran will not observe DST anymore:
+# http://www.irna.ir/en/news/view/line-17/0603193812164948.htm
+#
+# From Reuters (2007-09-16), with a heads-up from Jesper Norgaard Welen:
+# ... the Guardian Council ... approved a law on Sunday to re-introduce
+# daylight saving time ...
+# http://uk.reuters.com/article/oilRpt/idUKBLA65048420070916
+#
+# From Roozbeh Pournader (2007-11-05):
+# This is quoted from Official Gazette of the Islamic Republic of
+# Iran, Volume 63, Number 18242, dated Tuesday 1386/6/24
+# [2007-10-16]. I am doing the best translation I can:...
+# The official time of the country will be moved forward for one hour
+# on the 24 hours of the first day of the month of Farvardin and will
+# be changed back to its previous state on the 24 hours of the
+# thirtieth day of Shahrivar.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Iran	1978	1980	-	Mar	21	0:00	1:00	D
+Rule	Iran	1978	only	-	Oct	21	0:00	0	S
+Rule	Iran	1979	only	-	Sep	19	0:00	0	S
+Rule	Iran	1980	only	-	Sep	23	0:00	0	S
+Rule	Iran	1991	only	-	May	 3	0:00	1:00	D
+Rule	Iran	1992	1995	-	Mar	22	0:00	1:00	D
+Rule	Iran	1991	1995	-	Sep	22	0:00	0	S
+Rule	Iran	1996	only	-	Mar	21	0:00	1:00	D
+Rule	Iran	1996	only	-	Sep	21	0:00	0	S
+Rule	Iran	1997	1999	-	Mar	22	0:00	1:00	D
+Rule	Iran	1997	1999	-	Sep	22	0:00	0	S
+Rule	Iran	2000	only	-	Mar	21	0:00	1:00	D
+Rule	Iran	2000	only	-	Sep	21	0:00	0	S
+Rule	Iran	2001	2003	-	Mar	22	0:00	1:00	D
+Rule	Iran	2001	2003	-	Sep	22	0:00	0	S
+Rule	Iran	2004	only	-	Mar	21	0:00	1:00	D
+Rule	Iran	2004	only	-	Sep	21	0:00	0	S
+Rule	Iran	2005	only	-	Mar	22	0:00	1:00	D
+Rule	Iran	2005	only	-	Sep	22	0:00	0	S
+Rule	Iran	2008	only	-	Mar	21	0:00	1:00	D
+Rule	Iran	2008	only	-	Sep	21	0:00	0	S
+Rule	Iran	2009	2011	-	Mar	22	0:00	1:00	D
+Rule	Iran	2009	2011	-	Sep	22	0:00	0	S
+Rule	Iran	2012	only	-	Mar	21	0:00	1:00	D
+Rule	Iran	2012	only	-	Sep	21	0:00	0	S
+Rule	Iran	2013	2015	-	Mar	22	0:00	1:00	D
+Rule	Iran	2013	2015	-	Sep	22	0:00	0	S
+Rule	Iran	2016	only	-	Mar	21	0:00	1:00	D
+Rule	Iran	2016	only	-	Sep	21	0:00	0	S
+Rule	Iran	2017	2019	-	Mar	22	0:00	1:00	D
+Rule	Iran	2017	2019	-	Sep	22	0:00	0	S
+Rule	Iran	2020	only	-	Mar	21	0:00	1:00	D
+Rule	Iran	2020	only	-	Sep	21	0:00	0	S
+Rule	Iran	2021	2023	-	Mar	22	0:00	1:00	D
+Rule	Iran	2021	2023	-	Sep	22	0:00	0	S
+Rule	Iran	2024	only	-	Mar	21	0:00	1:00	D
+Rule	Iran	2024	only	-	Sep	21	0:00	0	S
+Rule	Iran	2025	2027	-	Mar	22	0:00	1:00	D
+Rule	Iran	2025	2027	-	Sep	22	0:00	0	S
+Rule	Iran	2028	2029	-	Mar	21	0:00	1:00	D
+Rule	Iran	2028	2029	-	Sep	21	0:00	0	S
+Rule	Iran	2030	2031	-	Mar	22	0:00	1:00	D
+Rule	Iran	2030	2031	-	Sep	22	0:00	0	S
+Rule	Iran	2032	2033	-	Mar	21	0:00	1:00	D
+Rule	Iran	2032	2033	-	Sep	21	0:00	0	S
+Rule	Iran	2034	2035	-	Mar	22	0:00	1:00	D
+Rule	Iran	2034	2035	-	Sep	22	0:00	0	S
+Rule	Iran	2036	2037	-	Mar	21	0:00	1:00	D
+Rule	Iran	2036	2037	-	Sep	21	0:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Tehran	3:25:44	-	LMT	1916
+			3:25:44	-	TMT	1946	# Tehran Mean Time
+			3:30	-	IRST	1977 Nov
+			4:00	Iran	IR%sT	1979
+			3:30	Iran	IR%sT
+
+
+# Iraq
+#
+# From Jonathan Lennox (2000-06-12):
+# An article in this week's Economist ("Inside the Saddam-free zone", p. 50 in
+# the U.S. edition) on the Iraqi Kurds contains a paragraph:
+# "The three northern provinces ... switched their clocks this spring and
+# are an hour ahead of Baghdad."
+#
+# But Rives McDow (2000-06-18) quotes a contact in Iraqi-Kurdistan as follows:
+# In the past, some Kurdish nationalists, as a protest to the Iraqi
+# Government, did not adhere to daylight saving time.  They referred
+# to daylight saving as Saddam time.  But, as of today, the time zone
+# in Iraqi-Kurdistan is on standard time with Baghdad, Iraq.
+#
+# So we'll ignore the Economist's claim.
+
+# From Steffen Thorsen (2008-03-10):
+# The cabinet in Iraq abolished DST last week, according to the following
+# news sources (in Arabic):
+# 
+# http://www.aljeeran.net/wesima_articles/news-20080305-98602.html
+# 
+# 
+# http://www.aswataliraq.info/look/article.tpl?id=2047&IdLanguage=17&IdPublication=4&NrArticle=71743&NrIssue=1&NrSection=10
+# 
+#
+# We have published a short article in English about the change:
+# 
+# http://www.timeanddate.com/news/time/iraq-dumps-daylight-saving.html
+# 
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Iraq	1982	only	-	May	1	0:00	1:00	D
+Rule	Iraq	1982	1984	-	Oct	1	0:00	0	S
+Rule	Iraq	1983	only	-	Mar	31	0:00	1:00	D
+Rule	Iraq	1984	1985	-	Apr	1	0:00	1:00	D
+Rule	Iraq	1985	1990	-	Sep	lastSun	1:00s	0	S
+Rule	Iraq	1986	1990	-	Mar	lastSun	1:00s	1:00	D
+# IATA SSIM (1991/1996) says Apr 1 12:01am UTC; guess the `:01' is a typo.
+# Shanks & Pottenger say Iraq did not observe DST 1992/1997; ignore this.
+#
+Rule	Iraq	1991	2007	-	Apr	 1	3:00s	1:00	D
+Rule	Iraq	1991	2007	-	Oct	 1	3:00s	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Baghdad	2:57:40	-	LMT	1890
+			2:57:36	-	BMT	1918	    # Baghdad Mean Time?
+			3:00	-	AST	1982 May
+			3:00	Iraq	A%sT
+
+
+###############################################################################
+
+# Israel
+
+# From Ephraim Silverberg (2001-01-11):
+#
+# I coined "IST/IDT" circa 1988.  Until then there were three
+# different abbreviations in use:
+#
+# JST  Jerusalem Standard Time [Danny Braniss, Hebrew University]
+# IZT  Israel Zonal (sic) Time [Prof. Haim Papo, Technion]
+# EEST Eastern Europe Standard Time [used by almost everyone else]
+#
+# Since timezones should be called by country and not capital cities,
+# I ruled out JST.  As Israel is in Asia Minor and not Eastern Europe,
+# EEST was equally unacceptable.  Since "zonal" was not compatible with
+# any other timezone abbreviation, I felt that 'IST' was the way to go
+# and, indeed, it has received almost universal acceptance in timezone
+# settings in Israeli computers.
+#
+# In any case, I am happy to share timezone abbreviations with India,
+# high on my favorite-country list (and not only because my wife's
+# family is from India).
+
+# From Shanks & Pottenger:
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Zion	1940	only	-	Jun	 1	0:00	1:00	D
+Rule	Zion	1942	1944	-	Nov	 1	0:00	0	S
+Rule	Zion	1943	only	-	Apr	 1	2:00	1:00	D
+Rule	Zion	1944	only	-	Apr	 1	0:00	1:00	D
+Rule	Zion	1945	only	-	Apr	16	0:00	1:00	D
+Rule	Zion	1945	only	-	Nov	 1	2:00	0	S
+Rule	Zion	1946	only	-	Apr	16	2:00	1:00	D
+Rule	Zion	1946	only	-	Nov	 1	0:00	0	S
+Rule	Zion	1948	only	-	May	23	0:00	2:00	DD
+Rule	Zion	1948	only	-	Sep	 1	0:00	1:00	D
+Rule	Zion	1948	1949	-	Nov	 1	2:00	0	S
+Rule	Zion	1949	only	-	May	 1	0:00	1:00	D
+Rule	Zion	1950	only	-	Apr	16	0:00	1:00	D
+Rule	Zion	1950	only	-	Sep	15	3:00	0	S
+Rule	Zion	1951	only	-	Apr	 1	0:00	1:00	D
+Rule	Zion	1951	only	-	Nov	11	3:00	0	S
+Rule	Zion	1952	only	-	Apr	20	2:00	1:00	D
+Rule	Zion	1952	only	-	Oct	19	3:00	0	S
+Rule	Zion	1953	only	-	Apr	12	2:00	1:00	D
+Rule	Zion	1953	only	-	Sep	13	3:00	0	S
+Rule	Zion	1954	only	-	Jun	13	0:00	1:00	D
+Rule	Zion	1954	only	-	Sep	12	0:00	0	S
+Rule	Zion	1955	only	-	Jun	11	2:00	1:00	D
+Rule	Zion	1955	only	-	Sep	11	0:00	0	S
+Rule	Zion	1956	only	-	Jun	 3	0:00	1:00	D
+Rule	Zion	1956	only	-	Sep	30	3:00	0	S
+Rule	Zion	1957	only	-	Apr	29	2:00	1:00	D
+Rule	Zion	1957	only	-	Sep	22	0:00	0	S
+Rule	Zion	1974	only	-	Jul	 7	0:00	1:00	D
+Rule	Zion	1974	only	-	Oct	13	0:00	0	S
+Rule	Zion	1975	only	-	Apr	20	0:00	1:00	D
+Rule	Zion	1975	only	-	Aug	31	0:00	0	S
+Rule	Zion	1985	only	-	Apr	14	0:00	1:00	D
+Rule	Zion	1985	only	-	Sep	15	0:00	0	S
+Rule	Zion	1986	only	-	May	18	0:00	1:00	D
+Rule	Zion	1986	only	-	Sep	 7	0:00	0	S
+Rule	Zion	1987	only	-	Apr	15	0:00	1:00	D
+Rule	Zion	1987	only	-	Sep	13	0:00	0	S
+Rule	Zion	1988	only	-	Apr	 9	0:00	1:00	D
+Rule	Zion	1988	only	-	Sep	 3	0:00	0	S
+
+# From Ephraim Silverberg
+# (1997-03-04, 1998-03-16, 1998-12-28, 2000-01-17, 2000-07-25, 2004-12-22,
+# and 2005-02-17):
+
+# According to the Office of the Secretary General of the Ministry of
+# Interior, there is NO set rule for Daylight-Savings/Standard time changes.
+# One thing is entrenched in law, however: that there must be at least 150
+# days of daylight savings time annually.  From 1993-1998, the change to
+# daylight savings time was on a Friday morning from midnight IST to
+# 1 a.m IDT; up until 1998, the change back to standard time was on a
+# Saturday night from midnight daylight savings time to 11 p.m. standard
+# time.  1996 is an exception to this rule where the change back to standard
+# time took place on Sunday night instead of Saturday night to avoid
+# conflicts with the Jewish New Year.  In 1999, the change to
+# daylight savings time was still on a Friday morning but from
+# 2 a.m. IST to 3 a.m. IDT; furthermore, the change back to standard time
+# was also on a Friday morning from 2 a.m. IDT to 1 a.m. IST for
+# 1999 only.  In the year 2000, the change to daylight savings time was
+# similar to 1999, but although the change back will be on a Friday, it
+# will take place from 1 a.m. IDT to midnight IST.  Starting in 2001, all
+# changes to/from will take place at 1 a.m. old time, but now there is no
+# rule as to what day of the week it will take place in as the start date
+# (except in 2003) is the night after the Passover Seder (i.e. the eve
+# of the 16th of Nisan in the lunar Hebrew calendar) and the end date
+# (except in 2002) is three nights before Yom Kippur [Day of Atonement]
+# (the eve of the 7th of Tishrei in the lunar Hebrew calendar).
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Zion	1989	only	-	Apr	30	0:00	1:00	D
+Rule	Zion	1989	only	-	Sep	 3	0:00	0	S
+Rule	Zion	1990	only	-	Mar	25	0:00	1:00	D
+Rule	Zion	1990	only	-	Aug	26	0:00	0	S
+Rule	Zion	1991	only	-	Mar	24	0:00	1:00	D
+Rule	Zion	1991	only	-	Sep	 1	0:00	0	S
+Rule	Zion	1992	only	-	Mar	29	0:00	1:00	D
+Rule	Zion	1992	only	-	Sep	 6	0:00	0	S
+Rule	Zion	1993	only	-	Apr	 2	0:00	1:00	D
+Rule	Zion	1993	only	-	Sep	 5	0:00	0	S
+
+# The dates for 1994-1995 were obtained from Office of the Spokeswoman for the
+# Ministry of Interior, Jerusalem, Israel.  The spokeswoman can be reached by
+# calling the office directly at 972-2-6701447 or 972-2-6701448.
+
+# Rule	NAME    FROM    TO      TYPE    IN      ON      AT      SAVE    LETTER/S
+Rule	Zion	1994	only	-	Apr	 1	0:00	1:00	D
+Rule	Zion	1994	only	-	Aug	28	0:00	0	S
+Rule	Zion	1995	only	-	Mar	31	0:00	1:00	D
+Rule	Zion	1995	only	-	Sep	 3	0:00	0	S
+
+# The dates for 1996 were determined by the Minister of Interior of the
+# time, Haim Ramon.  The official announcement regarding 1996-1998
+# (with the dates for 1997-1998 no longer being relevant) can be viewed at:
+#
+#   ftp://ftp.cs.huji.ac.il/pub/tz/announcements/1996-1998.ramon.ps.gz
+#
+# The dates for 1997-1998 were altered by his successor, Rabbi Eli Suissa.
+#
+# The official announcements for the years 1997-1999 can be viewed at:
+#
+#   ftp://ftp.cs.huji.ac.il/pub/tz/announcements/YYYY.ps.gz
+#
+#       where YYYY is the relevant year.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Zion	1996	only	-	Mar	15	0:00	1:00	D
+Rule	Zion	1996	only	-	Sep	16	0:00	0	S
+Rule	Zion	1997	only	-	Mar	21	0:00	1:00	D
+Rule	Zion	1997	only	-	Sep	14	0:00	0	S
+Rule	Zion	1998	only	-	Mar	20	0:00	1:00	D
+Rule	Zion	1998	only	-	Sep	 6	0:00	0	S
+Rule	Zion	1999	only	-	Apr	 2	2:00	1:00	D
+Rule	Zion	1999	only	-	Sep	 3	2:00	0	S
+
+# The Knesset Interior Committee has changed the dates for 2000 for
+# the third time in just over a year and have set new dates for the
+# years 2001-2004 as well.
+#
+# The official announcement for the start date of 2000 can be viewed at:
+#
+#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2000-start.ps.gz
+#
+# The official announcement for the end date of 2000 and the dates
+# for the years 2001-2004 can be viewed at:
+#
+#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2000-2004.ps.gz
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Zion	2000	only	-	Apr	14	2:00	1:00	D
+Rule	Zion	2000	only	-	Oct	 6	1:00	0	S
+Rule	Zion	2001	only	-	Apr	 9	1:00	1:00	D
+Rule	Zion	2001	only	-	Sep	24	1:00	0	S
+Rule	Zion	2002	only	-	Mar	29	1:00	1:00	D
+Rule	Zion	2002	only	-	Oct	 7	1:00	0	S
+Rule	Zion	2003	only	-	Mar	28	1:00	1:00	D
+Rule	Zion	2003	only	-	Oct	 3	1:00	0	S
+Rule	Zion	2004	only	-	Apr	 7	1:00	1:00	D
+Rule	Zion	2004	only	-	Sep	22	1:00	0	S
+
+# The proposed law agreed upon by the Knesset Interior Committee on
+# 2005-02-14 is that, for 2005 and beyond, DST starts at 02:00 the
+# last Friday before April 2nd (i.e. the last Friday in March or April
+# 1st itself if it falls on a Friday) and ends at 02:00 on the Saturday
+# night _before_ the fast of Yom Kippur.
+#
+# Those who can read Hebrew can view the announcement at:
+#
+#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2005+beyond.ps
+
+# From Paul Eggert (2005-02-22):
+# I used Ephraim Silverberg's dst-israel.el program
+#  (2005-02-20)
+# along with Ed Reingold's cal-hebrew in GNU Emacs 21.4,
+# to generate the transitions in this list.
+# (I replaced "lastFri" with "Fri>=26" by hand.)
+# The spring transitions below all correspond to the following Rule:
+#
+# Rule	Zion	2005	max	-	Mar	Fri>=26	2:00	1:00	D
+#
+# but older zic implementations (e.g., Solaris 8) do not support
+# "Fri>=26" to mean April 1 in years like 2005, so for now we list the
+# springtime transitions explicitly.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Zion	2005	only	-	Apr	 1	2:00	1:00	D
+Rule	Zion	2005	only	-	Oct	 9	2:00	0	S
+Rule	Zion	2006	2010	-	Mar	Fri>=26	2:00	1:00	D
+Rule	Zion	2006	only	-	Oct	 1	2:00	0	S
+Rule	Zion	2007	only	-	Sep	16	2:00	0	S
+Rule	Zion	2008	only	-	Oct	 5	2:00	0	S
+Rule	Zion	2009	only	-	Sep	27	2:00	0	S
+Rule	Zion	2010	only	-	Sep	12	2:00	0	S
+Rule	Zion	2011	only	-	Apr	 1	2:00	1:00	D
+Rule	Zion	2011	only	-	Oct	 2	2:00	0	S
+Rule	Zion	2012	2015	-	Mar	Fri>=26	2:00	1:00	D
+Rule	Zion	2012	only	-	Sep	23	2:00	0	S
+Rule	Zion	2013	only	-	Sep	 8	2:00	0	S
+Rule	Zion	2014	only	-	Sep	28	2:00	0	S
+Rule	Zion	2015	only	-	Sep	20	2:00	0	S
+Rule	Zion	2016	only	-	Apr	 1	2:00	1:00	D
+Rule	Zion	2016	only	-	Oct	 9	2:00	0	S
+Rule	Zion	2017	2021	-	Mar	Fri>=26	2:00	1:00	D
+Rule	Zion	2017	only	-	Sep	24	2:00	0	S
+Rule	Zion	2018	only	-	Sep	16	2:00	0	S
+Rule	Zion	2019	only	-	Oct	 6	2:00	0	S
+Rule	Zion	2020	only	-	Sep	27	2:00	0	S
+Rule	Zion	2021	only	-	Sep	12	2:00	0	S
+Rule	Zion	2022	only	-	Apr	 1	2:00	1:00	D
+Rule	Zion	2022	only	-	Oct	 2	2:00	0	S
+Rule	Zion	2023	2032	-	Mar	Fri>=26	2:00	1:00	D
+Rule	Zion	2023	only	-	Sep	24	2:00	0	S
+Rule	Zion	2024	only	-	Oct	 6	2:00	0	S
+Rule	Zion	2025	only	-	Sep	28	2:00	0	S
+Rule	Zion	2026	only	-	Sep	20	2:00	0	S
+Rule	Zion	2027	only	-	Oct	10	2:00	0	S
+Rule	Zion	2028	only	-	Sep	24	2:00	0	S
+Rule	Zion	2029	only	-	Sep	16	2:00	0	S
+Rule	Zion	2030	only	-	Oct	 6	2:00	0	S
+Rule	Zion	2031	only	-	Sep	21	2:00	0	S
+Rule	Zion	2032	only	-	Sep	12	2:00	0	S
+Rule	Zion	2033	only	-	Apr	 1	2:00	1:00	D
+Rule	Zion	2033	only	-	Oct	 2	2:00	0	S
+Rule	Zion	2034	2037	-	Mar	Fri>=26	2:00	1:00	D
+Rule	Zion	2034	only	-	Sep	17	2:00	0	S
+Rule	Zion	2035	only	-	Oct	 7	2:00	0	S
+Rule	Zion	2036	only	-	Sep	28	2:00	0	S
+Rule	Zion	2037	only	-	Sep	13	2:00	0	S
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Jerusalem	2:20:56 -	LMT	1880
+			2:20:40	-	JMT	1918	# Jerusalem Mean Time?
+			2:00	Zion	I%sT
+
+
+
+###############################################################################
+
+# Japan
+
+# `9:00' and `JST' is from Guy Harris.
+
+# From Paul Eggert (1995-03-06):
+# Today's _Asahi Evening News_ (page 4) reports that Japan had
+# daylight saving between 1948 and 1951, but ``the system was discontinued
+# because the public believed it would lead to longer working hours.''
+
+# From Mayumi Negishi in the 2005-08-10 Japan Times
+# :
+# Occupation authorities imposed daylight-saving time on Japan on
+# [1948-05-01]....  But lack of prior debate and the execution of
+# daylight-saving time just three days after the bill was passed generated
+# deep hatred of the concept....  The Diet unceremoniously passed a bill to
+# dump the unpopular system in October 1951, less than a month after the San
+# Francisco Peace Treaty was signed.  (A government poll in 1951 showed 53%
+# of the Japanese wanted to scrap daylight-saving time, as opposed to 30% who
+# wanted to keep it.)
+
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger write that DST in Japan during those years was as follows:
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Japan	1948	only	-	May	Sun>=1	2:00	1:00	D
+Rule	Japan	1948	1951	-	Sep	Sat>=8	2:00	0	S
+Rule	Japan	1949	only	-	Apr	Sun>=1	2:00	1:00	D
+Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
+# but the only locations using it (for birth certificates, presumably, since
+# their audience is astrologers) were US military bases.  For now, assume
+# that for most purposes daylight-saving time was observed; otherwise, what
+# would have been the point of the 1951 poll?
+
+# From Hideyuki Suzuki (1998-11-09):
+# 'Tokyo' usually stands for the former location of Tokyo Astronomical
+# Observatory: E 139 44' 40".90 (9h 18m 58s.727), N 35 39' 16".0.
+# This data is from 'Rika Nenpyou (Chronological Scientific Tables) 1996'
+# edited by National Astronomical Observatory of Japan....
+# JST (Japan Standard Time) has been used since 1888-01-01 00:00 (JST).
+# The law is enacted on 1886-07-07.
+
+# From Hideyuki Suzuki (1998-11-16):
+# The ordinance No. 51 (1886) established "standard time" in Japan,
+# which stands for the time on E 135 degree.
+# In the ordinance No. 167 (1895), "standard time" was renamed to "central
+# standard time".  And the same ordinance also established "western standard
+# time", which stands for the time on E 120 degree....  But "western standard
+# time" was abolished in the ordinance No. 529 (1937).  In the ordinance No.
+# 167, there is no mention regarding for what place western standard time is
+# standard....
+#
+# I wrote "ordinance" above, but I don't know how to translate.
+# In Japanese it's "chokurei", which means ordinance from emperor.
+
+# Shanks & Pottenger claim JST in use since 1896, and that a few
+# places (e.g. Ishigaki) use +0800; go with Suzuki.  Guess that all
+# ordinances took effect on Jan 1.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Tokyo	9:18:59	-	LMT	1887 Dec 31 15:00u
+			9:00	-	JST	1896
+			9:00	-	CJT	1938
+			9:00	Japan	J%sT
+# Since 1938, all Japanese possessions have been like Asia/Tokyo.
+
+# Jordan
+#
+# From 
+# Jordan Week (1999-07-01)  via Steffen Thorsen (1999-09-09):
+# Clocks in Jordan were forwarded one hour on Wednesday at midnight,
+# in accordance with the government's decision to implement summer time
+# all year round.
+#
+# From 
+# Jordan Week (1999-09-30)  via Steffen Thorsen (1999-11-09):
+# Winter time starts today Thursday, 30 September. Clocks will be turned back
+# by one hour.  This is the latest government decision and it's final!
+# The decision was taken because of the increase in working hours in
+# government's departments from six to seven hours.
+#
+# From Paul Eggert (2005-11-22):
+# Starting 2003 transitions are from Steffen Thorsen's web site timeanddate.com.
+#
+# From Steffen Thorsen (2005-11-23):
+# For Jordan I have received multiple independent user reports every year
+# about DST end dates, as the end-rule is different every year.
+#
+# From Steffen Thorsen (2006-10-01), after a heads-up from Hilal Malawi:
+# http://www.petranews.gov.jo/nepras/2006/Sep/05/4000.htm
+# "Jordan will switch to winter time on Friday, October 27".
+#
+
+# From Phil Pizzey (2009-04-02):
+# ...I think I may have spotted an error in the timezone data for
+# Jordan.
+# The current (2009d) asia file shows Jordan going to daylight
+# saving
+# time on the last Thursday in March.
+#
+# Rule  Jordan      2000  max	-  Mar   lastThu     0:00s 1:00  S
+#
+# However timeanddate.com, which I usually find reliable, shows Jordan
+# going to daylight saving time on the last Friday in March since 2002.
+# Please see
+# 
+# http://www.timeanddate.com/worldclock/timezone.html?n=11
+# 
+
+# From Steffen Thorsen (2009-04-02):
+# This single one might be good enough, (2009-03-24, Arabic):
+# 
+# http://petra.gov.jo/Artical.aspx?Lng=2&Section=8&Artical=95279
+# 
+#
+# Google's translation:
+#
+# > The Council of Ministers decided in 2002 to adopt the principle of timely
+# > submission of the summer at 60 minutes as of midnight on the last Thursday
+# > of the month of March of each year.
+#
+# So - this means the midnight between Thursday and Friday since 2002.
+
+# From Arthur David Olson (2009-04-06):
+# We still have Jordan switching to DST on Thursdays in 2000 and 2001.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Jordan	1973	only	-	Jun	6	0:00	1:00	S
+Rule	Jordan	1973	1975	-	Oct	1	0:00	0	-
+Rule	Jordan	1974	1977	-	May	1	0:00	1:00	S
+Rule	Jordan	1976	only	-	Nov	1	0:00	0	-
+Rule	Jordan	1977	only	-	Oct	1	0:00	0	-
+Rule	Jordan	1978	only	-	Apr	30	0:00	1:00	S
+Rule	Jordan	1978	only	-	Sep	30	0:00	0	-
+Rule	Jordan	1985	only	-	Apr	1	0:00	1:00	S
+Rule	Jordan	1985	only	-	Oct	1	0:00	0	-
+Rule	Jordan	1986	1988	-	Apr	Fri>=1	0:00	1:00	S
+Rule	Jordan	1986	1990	-	Oct	Fri>=1	0:00	0	-
+Rule	Jordan	1989	only	-	May	8	0:00	1:00	S
+Rule	Jordan	1990	only	-	Apr	27	0:00	1:00	S
+Rule	Jordan	1991	only	-	Apr	17	0:00	1:00	S
+Rule	Jordan	1991	only	-	Sep	27	0:00	0	-
+Rule	Jordan	1992	only	-	Apr	10	0:00	1:00	S
+Rule	Jordan	1992	1993	-	Oct	Fri>=1	0:00	0	-
+Rule	Jordan	1993	1998	-	Apr	Fri>=1	0:00	1:00	S
+Rule	Jordan	1994	only	-	Sep	Fri>=15	0:00	0	-
+Rule	Jordan	1995	1998	-	Sep	Fri>=15	0:00s	0	-
+Rule	Jordan	1999	only	-	Jul	 1	0:00s	1:00	S
+Rule	Jordan	1999	2002	-	Sep	lastFri	0:00s	0	-
+Rule	Jordan	2000	2001	-	Mar	lastThu	0:00s	1:00	S
+Rule	Jordan	2002	max	-	Mar	lastFri	0:00s	1:00	S
+Rule	Jordan	2003	only	-	Oct	24	0:00s	0	-
+Rule	Jordan	2004	only	-	Oct	15	0:00s	0	-
+Rule	Jordan	2005	only	-	Sep	lastFri	0:00s	0	-
+Rule	Jordan	2006	max	-	Oct	lastFri	0:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Amman	2:23:44 -	LMT	1931
+			2:00	Jordan	EE%sT
+
+
+# Kazakhstan
+
+# From Paul Eggert (1996-11-22):
+# Andrew Evtichov (1996-04-13) writes that Kazakhstan
+# stayed in sync with Moscow after 1990, and that Aqtobe (formerly Aktyubinsk)
+# and Aqtau (formerly Shevchenko) are the largest cities in their zones.
+# Guess that Aqtau and Aqtobe diverged in 1995, since that's the first time
+# IATA SSIM mentions a third time zone in Kazakhstan.
+
+# From Paul Eggert (2006-03-22):
+# German Iofis, ELSI, Almaty (2001-10-09) reports that Kazakhstan uses
+# RussiaAsia rules, instead of switching at 00:00 as the IATA has it.
+# Go with Shanks & Pottenger, who have them always using RussiaAsia rules.
+# Also go with the following claims of Shanks & Pottenger:
+#
+# - Kazakhstan did not observe DST in 1991.
+# - Qyzylorda switched from +5:00 to +6:00 on 1992-01-19 02:00.
+# - Oral switched from +5:00 to +4:00 in spring 1989.
+
+# 
+# From Kazakhstan Embassy's News Bulletin #11 (2005-03-21):
+# 
+# The Government of Kazakhstan passed a resolution March 15 abolishing
+# daylight saving time citing lack of economic benefits and health
+# complications coupled with a decrease in productivity.
+#
+# From Branislav Kojic (in Astana) via Gwillim Law (2005-06-28):
+# ... what happened was that the former Kazakhstan Eastern time zone
+# was "blended" with the Central zone.  Therefore, Kazakhstan now has
+# two time zones, and difference between them is one hour.  The zone
+# closer to UTC is the former Western zone (probably still called the
+# same), encompassing four provinces in the west: Aqtobe, Atyrau,
+# Mangghystau, and West Kazakhstan.  The other zone encompasses
+# everything else....  I guess that would make Kazakhstan time zones
+# de jure UTC+5 and UTC+6 respectively.
+
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+#
+# Almaty (formerly Alma-Ata), representing most locations in Kazakhstan
+Zone	Asia/Almaty	5:07:48 -	LMT	1924 May  2 # or Alma-Ata
+			5:00	-	ALMT	1930 Jun 21 # Alma-Ata Time
+			6:00 RussiaAsia ALM%sT	1991
+			6:00	-	ALMT	1992
+			6:00 RussiaAsia	ALM%sT	2005 Mar 15
+			6:00	-	ALMT
+# Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.)
+Zone	Asia/Qyzylorda	4:21:52 -	LMT	1924 May  2
+			4:00	-	KIZT	1930 Jun 21 # Kizilorda Time
+			5:00	-	KIZT	1981 Apr  1
+			5:00	1:00	KIZST	1981 Oct  1
+			6:00	-	KIZT	1982 Apr  1
+			5:00 RussiaAsia	KIZ%sT	1991
+			5:00	-	KIZT	1991 Dec 16 # independence
+			5:00	-	QYZT	1992 Jan 19 2:00
+			6:00 RussiaAsia	QYZ%sT	2005 Mar 15
+			6:00	-	QYZT
+# Aqtobe (aka Aktobe, formerly Akt'ubinsk)
+Zone	Asia/Aqtobe	3:48:40	-	LMT	1924 May  2
+			4:00	-	AKTT	1930 Jun 21 # Aktyubinsk Time
+			5:00	-	AKTT	1981 Apr  1
+			5:00	1:00	AKTST	1981 Oct  1
+			6:00	-	AKTT	1982 Apr  1
+			5:00 RussiaAsia	AKT%sT	1991
+			5:00	-	AKTT	1991 Dec 16 # independence
+			5:00 RussiaAsia	AQT%sT	2005 Mar 15 # Aqtobe Time
+			5:00	-	AQTT
+# Mangghystau
+# Aqtau was not founded until 1963, but it represents an inhabited region,
+# so include time stamps before 1963.
+Zone	Asia/Aqtau	3:21:04	-	LMT	1924 May  2
+			4:00	-	FORT	1930 Jun 21 # Fort Shevchenko T
+			5:00	-	FORT	1963
+			5:00	-	SHET	1981 Oct  1 # Shevchenko Time
+			6:00	-	SHET	1982 Apr  1
+			5:00 RussiaAsia	SHE%sT	1991
+			5:00	-	SHET	1991 Dec 16 # independence
+			5:00 RussiaAsia	AQT%sT	1995 Mar lastSun 2:00 # Aqtau Time
+			4:00 RussiaAsia	AQT%sT	2005 Mar 15
+			5:00	-	AQTT
+# West Kazakhstan
+Zone	Asia/Oral	3:25:24	-	LMT	1924 May  2 # or Ural'sk
+			4:00	-	URAT	1930 Jun 21 # Ural'sk time
+			5:00	-	URAT	1981 Apr  1
+			5:00	1:00	URAST	1981 Oct  1
+			6:00	-	URAT	1982 Apr  1
+			5:00 RussiaAsia	URA%sT	1989 Mar 26 2:00
+			4:00 RussiaAsia	URA%sT	1991
+			4:00	-	URAT	1991 Dec 16 # independence
+			4:00 RussiaAsia	ORA%sT	2005 Mar 15 # Oral Time
+			5:00	-	ORAT
+
+# Kyrgyzstan (Kirgizstan)
+# Transitions through 1991 are from Shanks & Pottenger.
+
+# From Paul Eggert (2005-08-15):
+# According to an article dated today in the Kyrgyzstan Development Gateway
+# 
+# Kyrgyzstan is canceling the daylight saving time system.  I take the article
+# to mean that they will leave their clocks at 6 hours ahead of UTC.
+# From Malik Abdugaliev (2005-09-21):
+# Our government cancels daylight saving time 6th of August 2005.
+# From 2005-08-12 our GMT-offset is +6, w/o any daylight saving.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Kyrgyz	1992	1996	-	Apr	Sun>=7	0:00s	1:00	S
+Rule	Kyrgyz	1992	1996	-	Sep	lastSun	0:00	0	-
+Rule	Kyrgyz	1997	2005	-	Mar	lastSun	2:30	1:00	S
+Rule	Kyrgyz	1997	2004	-	Oct	lastSun	2:30	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Bishkek	4:58:24 -	LMT	1924 May  2
+			5:00	-	FRUT	1930 Jun 21 # Frunze Time
+			6:00 RussiaAsia FRU%sT	1991 Mar 31 2:00s
+			5:00	1:00	FRUST	1991 Aug 31 2:00 # independence
+			5:00	Kyrgyz	KG%sT	2005 Aug 12    # Kyrgyzstan Time
+			6:00	-	KGT
+
+###############################################################################
+
+# Korea (North and South)
+
+# From Annie I. Bang (2006-07-10) in
+# :
+# The Ministry of Commerce, Industry and Energy has already
+# commissioned a research project [to reintroduce DST] and has said
+# the system may begin as early as 2008....  Korea ran a daylight
+# saving program from 1949-61 but stopped it during the 1950-53 Korean War.
+
+# From Shanks & Pottenger:
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	ROK	1960	only	-	May	15	0:00	1:00	D
+Rule	ROK	1960	only	-	Sep	13	0:00	0	S
+Rule	ROK	1987	1988	-	May	Sun>=8	0:00	1:00	D
+Rule	ROK	1987	1988	-	Oct	Sun>=8	0:00	0	S
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Seoul	8:27:52	-	LMT	1890
+			8:30	-	KST	1904 Dec
+			9:00	-	KST	1928
+			8:30	-	KST	1932
+			9:00	-	KST	1954 Mar 21
+			8:00	ROK	K%sT	1961 Aug 10
+			8:30	-	KST	1968 Oct
+			9:00	ROK	K%sT
+Zone	Asia/Pyongyang	8:23:00 -	LMT	1890
+			8:30	-	KST	1904 Dec
+			9:00	-	KST	1928
+			8:30	-	KST	1932
+			9:00	-	KST	1954 Mar 21
+			8:00	-	KST	1961 Aug 10
+			9:00	-	KST
+
+###############################################################################
+
+# Kuwait
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+# From the Arab Times (2007-03-14):
+# The Civil Service Commission (CSC) has approved a proposal forwarded
+# by MP Ahmad Baqer on implementing the daylight saving time (DST) in
+# Kuwait starting from April until the end of Sept this year, reports Al-Anba.
+# .
+# From Paul Eggert (2007-03-29):
+# We don't know the details, or whether the approval means it'll happen,
+# so for now we assume no DST.
+Zone	Asia/Kuwait	3:11:56 -	LMT	1950
+			3:00	-	AST
+
+# Laos
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Vientiane	6:50:24 -	LMT	1906 Jun  9 # or Viangchan
+			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
+			7:00	-	ICT	1912 May
+			8:00	-	ICT	1931 May
+			7:00	-	ICT
+
+# Lebanon
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Lebanon	1920	only	-	Mar	28	0:00	1:00	S
+Rule	Lebanon	1920	only	-	Oct	25	0:00	0	-
+Rule	Lebanon	1921	only	-	Apr	3	0:00	1:00	S
+Rule	Lebanon	1921	only	-	Oct	3	0:00	0	-
+Rule	Lebanon	1922	only	-	Mar	26	0:00	1:00	S
+Rule	Lebanon	1922	only	-	Oct	8	0:00	0	-
+Rule	Lebanon	1923	only	-	Apr	22	0:00	1:00	S
+Rule	Lebanon	1923	only	-	Sep	16	0:00	0	-
+Rule	Lebanon	1957	1961	-	May	1	0:00	1:00	S
+Rule	Lebanon	1957	1961	-	Oct	1	0:00	0	-
+Rule	Lebanon	1972	only	-	Jun	22	0:00	1:00	S
+Rule	Lebanon	1972	1977	-	Oct	1	0:00	0	-
+Rule	Lebanon	1973	1977	-	May	1	0:00	1:00	S
+Rule	Lebanon	1978	only	-	Apr	30	0:00	1:00	S
+Rule	Lebanon	1978	only	-	Sep	30	0:00	0	-
+Rule	Lebanon	1984	1987	-	May	1	0:00	1:00	S
+Rule	Lebanon	1984	1991	-	Oct	16	0:00	0	-
+Rule	Lebanon	1988	only	-	Jun	1	0:00	1:00	S
+Rule	Lebanon	1989	only	-	May	10	0:00	1:00	S
+Rule	Lebanon	1990	1992	-	May	1	0:00	1:00	S
+Rule	Lebanon	1992	only	-	Oct	4	0:00	0	-
+Rule	Lebanon	1993	max	-	Mar	lastSun	0:00	1:00	S
+Rule	Lebanon	1993	1998	-	Sep	lastSun	0:00	0	-
+Rule	Lebanon	1999	max	-	Oct	lastSun	0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Beirut	2:22:00 -	LMT	1880
+			2:00	Lebanon	EE%sT
+
+# Malaysia
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	NBorneo	1935	1941	-	Sep	14	0:00	0:20	TS # one-Third Summer
+Rule	NBorneo	1935	1941	-	Dec	14	0:00	0	-
+#
+# peninsular Malaysia
+# The data here are taken from Mok Ly Yng (2003-10-30)
+# .
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Asia/Kuala_Lumpur	6:46:46 -	LMT	1901 Jan  1
+			6:55:25	-	SMT	1905 Jun  1 # Singapore M.T.
+			7:00	-	MALT	1933 Jan  1 # Malaya Time
+			7:00	0:20	MALST	1936 Jan  1
+			7:20	-	MALT	1941 Sep  1
+			7:30	-	MALT	1942 Feb 16
+			9:00	-	JST	1945 Sep 12
+			7:30	-	MALT	1982 Jan  1
+			8:00	-	MYT	# Malaysia Time
+# Sabah & Sarawak
+# From Paul Eggert (2006-03-22):
+# The data here are mostly from Shanks & Pottenger, but the 1942, 1945 and 1982
+# transition dates are from Mok Ly Yng.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Asia/Kuching	7:21:20	-	LMT	1926 Mar
+			7:30	-	BORT	1933	# Borneo Time
+			8:00	NBorneo	BOR%sT	1942 Feb 16
+			9:00	-	JST	1945 Sep 12
+			8:00	-	BORT	1982 Jan  1
+			8:00	-	MYT
+
+# Maldives
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
+			4:54:00	-	MMT	1960	# Male Mean Time
+			5:00	-	MVT		# Maldives Time
+
+# Mongolia
+
+# Shanks & Pottenger say that Mongolia has three time zones, but
+# usno1995 and the CIA map Standard Time Zones of the World (2005-03)
+# both say that it has just one.
+
+# From Oscar van Vlijmen (1999-12-11):
+# 
+# General Information Mongolia
+#  (1999-09)
+# "Time: Mongolia has two time zones. Three westernmost provinces of
+# Bayan-Ulgii, Uvs, and Hovd are one hour earlier than the capital city, and
+# the rest of the country follows the Ulaanbaatar time, which is UTC/GMT plus
+# eight hours."
+
+# From Rives McDow (1999-12-13):
+# Mongolia discontinued the use of daylight savings time in 1999; 1998
+# being the last year it was implemented.  The dates of implementation I am
+# unsure of, but most probably it was similar to Russia, except for the time
+# of implementation may have been different....
+# Some maps in the past have indicated that there was an additional time
+# zone in the eastern part of Mongolia, including the provinces of Dornod,
+# Suhbaatar, and possibly Khentij.
+
+# From Paul Eggert (1999-12-15):
+# Naming and spelling is tricky in Mongolia.
+# We'll use Hovd (also spelled Chovd and Khovd) to represent the west zone;
+# the capital of the Hovd province is sometimes called Hovd, sometimes Dund-Us,
+# and sometimes Jirgalanta (with variant spellings), but the name Hovd
+# is good enough for our purposes.
+
+# From Rives McDow (2001-05-13):
+# In addition to Mongolia starting daylight savings as reported earlier
+# (adopted DST on 2001-04-27 02:00 local time, ending 2001-09-28),
+# there are three time zones.
+#
+# Provinces [at 7:00]: Bayan-ulgii, Uvs, Khovd, Zavkhan, Govi-Altai
+# Provinces [at 8:00]: Khovsgol, Bulgan, Arkhangai, Khentii, Tov,
+#	Bayankhongor, Ovorkhangai, Dundgovi, Dornogovi, Omnogovi
+# Provinces [at 9:00]: Dornod, Sukhbaatar
+#
+# [The province of Selenge is omitted from the above lists.]
+
+# From Ganbold Ts., Ulaanbaatar (2004-04-17):
+# Daylight saving occurs at 02:00 local time last Saturday of March.
+# It will change back to normal at 02:00 local time last Saturday of
+# September.... As I remember this rule was changed in 2001.
+#
+# From Paul Eggert (2004-04-17):
+# For now, assume Rives McDow's informant got confused about Friday vs
+# Saturday, and that his 2001 dates should have 1 added to them.
+
+# From Paul Eggert (2005-07-26):
+# We have wildly conflicting information about Mongolia's time zones.
+# Bill Bonnet (2005-05-19) reports that the US Embassy in Ulaanbaatar says
+# there is only one time zone and that DST is observed, citing Microsoft
+# Windows XP as the source.  Risto Nykanen (2005-05-16) reports that
+# travelmongolia.org says there are two time zones (UTC+7, UTC+8) with no DST.
+# Oscar van Vlijmen (2005-05-20) reports that the Mongolian Embassy in
+# Washington, DC says there are two time zones, with DST observed.
+# He also found
+# 
+# which also says that there is DST, and which has a comment by "Toddius"
+# (2005-03-31 06:05 +0700) saying "Mongolia actually has 3.5 time zones.
+# The West (OLGII) is +7 GMT, most of the country is ULAT is +8 GMT
+# and some Eastern provinces are +9 GMT but Sukhbaatar Aimag is SUHK +8.5 GMT.
+# The SUKH timezone is new this year, it is one of the few things the
+# parliament passed during the tumultuous winter session."
+# For now, let's ignore this information, until we have more confirmation.
+
+# From Ganbold Ts. (2007-02-26):
+# Parliament of Mongolia has just changed the daylight-saving rule in February.
+# They decided not to adopt daylight-saving time....
+# http://www.mongolnews.mn/index.php?module=unuudur&sec=view&id=15742
+
+# From Deborah Goldsmith (2008-03-30):
+# We received a bug report claiming that the tz database UTC offset for
+# Asia/Choibalsan (GMT+09:00) is incorrect, and that it should be GMT
+# +08:00 instead. Different sources appear to disagree with the tz
+# database on this, e.g.:
+#
+# 
+# http://www.timeanddate.com/worldclock/city.html?n=1026
+# 
+# 
+# http://www.worldtimeserver.com/current_time_in_MN.aspx
+# 
+#
+# both say GMT+08:00.
+
+# From Steffen Thorsen (2008-03-31):
+# eznis airways, which operates several domestic flights, has a flight
+# schedule here:
+# 
+# http://www.eznis.com/Container.jsp?id=112
+# 
+# (click the English flag for English)
+#
+# There it appears that flights between Choibalsan and Ulaanbatar arrive
+# about 1:35 - 1:50 hours later in local clock time, no matter the
+# direction, while Ulaanbaatar-Khvod takes 2 hours in the Eastern
+# direction and 3:35 back, which indicates that Ulaanbatar and Khvod are
+# in different time zones (like we know about), while Choibalsan and
+# Ulaanbatar are in the same time zone (correction needed).
+
+# From Arthur David Olson (2008-05-19):
+# Assume that Choibalsan is indeed offset by 8:00.
+# XXX--in the absence of better information, assume that transition
+# was at the start of 2008-03-31 (the day of Steffen Thorsen's report);
+# this is almost surely wrong.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Mongol	1983	1984	-	Apr	1	0:00	1:00	S
+Rule	Mongol	1983	only	-	Oct	1	0:00	0	-
+# Shanks & Pottenger and IATA SSIM say 1990s switches occurred at 00:00,
+# but McDow says the 2001 switches occurred at 02:00.  Also, IATA SSIM
+# (1996-09) says 1996-10-25.  Go with Shanks & Pottenger through 1998.
+#
+# Shanks & Pottenger say that the Sept. 1984 through Sept. 1990 switches
+# in Choibalsan (more precisely, in Dornod and Sukhbaatar) took place
+# at 02:00 standard time, not at 00:00 local time as in the rest of
+# the country.  That would be odd, and possibly is a result of their
+# correction of 02:00 (in the previous edition) not being done correctly
+# in the latest edition; so ignore it for now.
+
+Rule	Mongol	1985	1998	-	Mar	lastSun	0:00	1:00	S
+Rule	Mongol	1984	1998	-	Sep	lastSun	0:00	0	-
+# IATA SSIM (1999-09) says Mongolia no longer observes DST.
+Rule	Mongol	2001	only	-	Apr	lastSat	2:00	1:00	S
+Rule	Mongol	2001	2006	-	Sep	lastSat	2:00	0	-
+Rule	Mongol	2002	2006	-	Mar	lastSat	2:00	1:00	S
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+# Hovd, a.k.a. Chovd, Dund-Us, Dzhargalant, Khovd, Jirgalanta
+Zone	Asia/Hovd	6:06:36 -	LMT	1905 Aug
+			6:00	-	HOVT	1978	# Hovd Time
+			7:00	Mongol	HOV%sT
+# Ulaanbaatar, a.k.a. Ulan Bataar, Ulan Bator, Urga
+Zone	Asia/Ulaanbaatar 7:07:32 -	LMT	1905 Aug
+			7:00	-	ULAT	1978	# Ulaanbaatar Time
+			8:00	Mongol	ULA%sT
+# Choibalsan, a.k.a. Bajan Tuemen, Bajan Tumen, Chojbalsan,
+# Choybalsan, Sanbejse, Tchoibalsan
+Zone	Asia/Choibalsan	7:38:00 -	LMT	1905 Aug
+			7:00	-	ULAT	1978
+			8:00	-	ULAT	1983 Apr
+			9:00	Mongol	CHO%sT	2008 Mar 31 # Choibalsan Time
+			8:00	Mongol	CHO%sT
+
+# Nepal
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Kathmandu	5:41:16 -	LMT	1920
+			5:30	-	IST	1986
+			5:45	-	NPT	# Nepal Time
+
+# Oman
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Muscat	3:54:20 -	LMT	1920
+			4:00	-	GST
+
+# Pakistan
+
+# From Rives McDow (2002-03-13):
+# I have been advised that Pakistan has decided to adopt dst on a
+# TRIAL basis for one year, starting 00:01 local time on April 7, 2002
+# and ending at 00:01 local time October 6, 2002.  This is what I was
+# told, but I believe that the actual time of change may be 00:00; the
+# 00:01 was to make it clear which day it was on.
+
+# From Paul Eggert (2002-03-15):
+# Jesper Norgaard found this URL:
+# http://www.pak.gov.pk/public/news/app/app06_dec.htm
+# (dated 2001-12-06) which says that the Cabinet adopted a scheme "to
+# advance the clocks by one hour on the night between the first
+# Saturday and Sunday of April and revert to the original position on
+# 15th October each year".  This agrees with McDow's 04-07 at 00:00,
+# but disagrees about the October transition, and makes it sound like
+# it's not on a trial basis.  Also, the "between the first Saturday
+# and Sunday of April" phrase, if taken literally, means that the
+# transition takes place at 00:00 on the first Sunday on or after 04-02.
+
+# From Paul Eggert (2003-02-09):
+# DAWN  reported on 2002-10-05
+# that 2002 DST ended that day at midnight.  Go with McDow for now.
+
+# From Steffen Thorsen (2003-03-14):
+# According to http://www.dawn.com/2003/03/07/top15.htm
+# there will be no DST in Pakistan this year:
+#
+# ISLAMABAD, March 6: Information and Media Development Minister Sheikh
+# Rashid Ahmed on Thursday said the cabinet had reversed a previous
+# decision to advance clocks by one hour in summer and put them back by
+# one hour in winter with the aim of saving light hours and energy.
+#
+# The minister told a news conference that the experiment had rather
+# shown 8 per cent higher consumption of electricity.
+
+# From Alex Krivenyshev (2008-05-15):
+# 
+# Here is an article that Pakistan plan to introduce Daylight Saving Time 
+# on June 1, 2008 for 3 months.
+# 
+# "... The federal cabinet on Wednesday announced a new conservation plan to help 
+# reduce load shedding by approving the closure of commercial centres at 9pm and 
+# moving clocks forward by one hour for the next three months. 
+# ...."
+# 
+# 
+# http://www.worldtimezone.net/dst_news/dst_news_pakistan01.html
+# 
+# OR
+# 
+# http://www.dailytimes.com.pk/default.asp?page=2008%5C05%5C15%5Cstory_15-5-2008_pg1_4
+# 
+
+# From Arthur David Olson (2008-05-19):
+# XXX--midnight transitions is a guess; 2008 only is a guess.
+
+# From Alexander Krivenyshev (2008-08-28):
+# Pakistan government has decided to keep the watches one-hour advanced
+# for another 2 months--plan to return to Standard Time on October 31
+# instead of August 31.
+#
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_pakistan02.html
+# 
+# OR
+# 
+# http://dailymailnews.com/200808/28/news/dmbrn03.html
+# 
+
+# From Alexander Krivenyshev (2009-04-08):
+# Based on previous media reports that "... proposed plan to
+# advance clocks by one hour from May 1 will cause disturbance
+# to the working schedules rather than bringing discipline in
+# official working."
+# 
+# http://www.thenews.com.pk/daily_detail.asp?id=171280
+# 
+#
+# recent news that instead of May 2009 - Pakistan plan to
+# introduce DST from April 15, 2009
+#
+# FYI: Associated Press Of Pakistan
+# April 08, 2009
+# Cabinet okays proposal to advance clocks by one hour from April 15
+# 
+# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=73043&Itemid=1
+# 
+#
+# or
+#
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_pakistan05.html
+# 
+#
+# ....
+# The Federal Cabinet on Wednesday approved the proposal to
+# advance clocks in the country by one hour from April 15 to
+# conserve energy"
+
+# From Arthur David Olson (2009-04-10):
+# Assume for now that Pakistan will end DST in 2009 as it did in 2008.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule Pakistan	2002	only	-	Apr	Sun>=2	0:01	1:00	S
+Rule Pakistan	2002	only	-	Oct	Sun>=2	0:01	0	-
+Rule Pakistan	2008	only	-	Jun	1	0:00	1:00	S
+Rule Pakistan	2008	only	-	Nov	1	0:00	0	-
+Rule Pakistan	2009	only	-	Apr	15	0:00	1:00	S
+Rule Pakistan	2009	only	-	Nov	1	0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Karachi	4:28:12 -	LMT	1907
+			5:30	-	IST	1942 Sep
+			5:30	1:00	IST	1945 Oct 15
+			5:30	-	IST	1951 Sep 30
+			5:00	-	KART	1971 Mar 26 # Karachi Time
+			5:00 Pakistan	PK%sT	# Pakistan Time
+
+# Palestine
+
+# From Amos Shapir (1998-02-15):
+#
+# From 1917 until 1948-05-15, all of Palestine, including the parts now
+# known as the Gaza Strip and the West Bank, was under British rule.
+# Therefore the rules given for Israel for that period, apply there too...
+#
+# The Gaza Strip was under Egyptian rule between 1948-05-15 until 1967-06-05
+# (except a short occupation by Israel from 1956-11 till 1957-03, but no
+# time zone was affected then).  It was never formally annexed to Egypt,
+# though.
+#
+# The rest of Palestine was under Jordanian rule at that time, formally
+# annexed in 1950 as the West Bank (and the word "Trans" was dropped from
+# the country's previous name of "the Hashemite Kingdom of the
+# Trans-Jordan").  So the rules for Jordan for that time apply.  Major
+# towns in that area are Nablus (Shchem), El-Halil (Hebron), Ramallah, and
+# East Jerusalem.
+#
+# Both areas were occupied by Israel in June 1967, but not annexed (except
+# for East Jerusalem).  They were on Israel time since then; there might
+# have been a Military Governor's order about time zones, but I'm not aware
+# of any (such orders may have been issued semi-annually whenever summer
+# time was in effect, but maybe the legal aspect of time was just neglected).
+#
+# The Palestinian Authority was established in 1993, and got hold of most
+# towns in the West Bank and Gaza by 1995.  I know that in order to
+# demonstrate...independence, they have been switching to
+# summer time and back on a different schedule than Israel's, but I don't
+# know when this was started, or what algorithm is used (most likely the
+# Jordanian one).
+#
+# To summarize, the table should probably look something like that:
+#
+# Area \ when | 1918-1947 | 1948-1967 | 1967-1995 | 1996-
+# ------------+-----------+-----------+-----------+-----------
+# Israel      | Zion      | Zion      | Zion      | Zion
+# West bank   | Zion      | Jordan    | Zion      | Jordan
+# Gaza        | Zion      | Egypt     | Zion      | Jordan
+#
+# I guess more info may be available from the PA's web page (if/when they
+# have one).
+
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger write that Gaza did not observe DST until 1957, but go
+# with Shapir and assume that it observed DST from 1940 through 1947,
+# and that it used Jordanian rules starting in 1996.
+# We don't yet need a separate entry for the West Bank, since
+# the only differences between it and Gaza that we know about
+# occurred before our cutoff date of 1970.
+# However, as we get more information, we may need to add entries
+# for parts of the West Bank as they transitioned from Israel's rules
+# to Palestine's rules.  If you have more info about this, please
+# send it to tz@elsie.nci.nih.gov for incorporation into future editions.
+
+# From IINS News Service - Israel - 1998-03-23 10:38:07 Israel time,
+# forwarded by Ephraim Silverberg:
+#
+# Despite the fact that Israel changed over to daylight savings time
+# last week, the PLO Authority (PA) has decided not to turn its clocks
+# one-hour forward at this time.  As a sign of independence from Israeli rule,
+# the PA has decided to implement DST in April.
+
+# From Paul Eggert (1999-09-20):
+# Daoud Kuttab writes in
+# 
+# Holiday havoc
+#  (Jerusalem Post, 1999-04-22) that
+# the Palestinian National Authority changed to DST on 1999-04-15.
+# I vaguely recall that they switch back in October (sorry, forgot the source).
+# For now, let's assume that the spring switch was at 24:00,
+# and that they switch at 0:00 on the 3rd Fridays of April and October.
+
+# From Paul Eggert (2005-11-22):
+# Starting 2004 transitions are from Steffen Thorsen's web site timeanddate.com.
+
+# From Steffen Thorsen (2005-11-23):
+# A user from Gaza reported that Gaza made the change early because of
+# the Ramadan.  Next year Ramadan will be even earlier, so I think
+# there is a good chance next year's end date will be around two weeks
+# earlier--the same goes for Jordan.
+
+# From Steffen Thorsen (2006-08-17):
+# I was informed by a user in Bethlehem that in Bethlehem it started the
+# same day as Israel, and after checking with other users in the area, I
+# was informed that they started DST one day after Israel.  I was not
+# able to find any authoritative sources at the time, nor details if
+# Gaza changed as well, but presumed Gaza to follow the same rules as
+# the West Bank.
+
+# From Steffen Thorsen (2006-09-26):
+# according to the Palestine News Network (2006-09-19):
+# http://english.pnn.ps/index.php?option=com_content&task=view&id=596&Itemid=5
+# > The Council of Ministers announced that this year its winter schedule
+# > will begin early, as of midnight Thursday.  It is also time to turn
+# > back the clocks for winter.  Friday will begin an hour late this week.
+# I guess it is likely that next year's date will be moved as well,
+# because of the Ramadan.
+
+# From Jesper Norgaard Welen (2007-09-18):
+# According to Steffen Thorsen's web site the Gaza Strip and the rest of the
+# Palestinian territories left DST early on 13.th. of September at 2:00.
+
+# From Paul Eggert (2007-09-20):
+# My understanding is that Gaza and the West Bank disagree even over when
+# the weekend is (Thursday+Friday versus Friday+Saturday), so I'd be a bit
+# surprised if they agreed about DST.  But for now, assume they agree.
+# For lack of better information, predict that future changes will be
+# the 2nd Thursday of September at 02:00.
+
+# From Alexander Krivenyshev (2008-08-28):
+# Here is an article, that Mideast running on different clocks at Ramadan.
+#
+# Gaza Strip (as Egypt) ended DST at midnight Thursday (Aug 28, 2008), while
+# the West Bank will end Daylight Saving Time at midnight Sunday (Aug 31, 2008).
+#
+# 
+# http://www.guardian.co.uk/world/feedarticle/7759001
+# 
+# 
+# http://www.abcnews.go.com/International/wireStory?id=5676087
+# 
+# or
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_gazastrip01.html
+# 
+
+# From Alexander Krivenyshev (2009-03-26):
+# According to the Palestine News Network (arabic.pnn.ps), Palestinian
+# government decided to start Daylight Time on Thursday night March
+# 26 and continue until the night of 27 September 2009.
+#
+# (in Arabic)
+# 
+# http://arabic.pnn.ps/index.php?option=com_content&task=view&id=50850
+# 
+#
+# or
+# (English translation)
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_westbank01.html
+# 
+
+# The rules for Egypt are stolen from the `africa' file.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule EgyptAsia	1957	only	-	May	10	0:00	1:00	S
+Rule EgyptAsia	1957	1958	-	Oct	 1	0:00	0	-
+Rule EgyptAsia	1958	only	-	May	 1	0:00	1:00	S
+Rule EgyptAsia	1959	1967	-	May	 1	1:00	1:00	S
+Rule EgyptAsia	1959	1965	-	Sep	30	3:00	0	-
+Rule EgyptAsia	1966	only	-	Oct	 1	3:00	0	-
+
+Rule Palestine	1999	2005	-	Apr	Fri>=15	0:00	1:00	S
+Rule Palestine	1999	2003	-	Oct	Fri>=15	0:00	0	-
+Rule Palestine	2004	only	-	Oct	 1	1:00	0	-
+Rule Palestine	2005	only	-	Oct	 4	2:00	0	-
+Rule Palestine	2006	2008	-	Apr	 1	0:00	1:00	S
+Rule Palestine	2006	only	-	Sep	22	0:00	0	-
+Rule Palestine	2007	only	-	Sep	Thu>=8	2:00	0	-
+Rule Palestine	2008	only	-	Aug	lastFri	2:00	0	-
+Rule Palestine	2009	max	-	Mar	lastFri	0:00	1:00	S
+Rule Palestine	2009	max	-	Sep	lastMon	2:00	0	-
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Gaza	2:17:52	-	LMT	1900 Oct
+			2:00	Zion	EET	1948 May 15
+			2:00 EgyptAsia	EE%sT	1967 Jun  5
+			2:00	Zion	I%sT	1996
+			2:00	Jordan	EE%sT	1999
+			2:00 Palestine	EE%sT
+
+# Paracel Is
+# no information
+
+# Philippines
+# On 1844-08-16, Narciso Claveria, governor-general of the
+# Philippines, issued a proclamation announcing that 1844-12-30 was to
+# be immediately followed by 1845-01-01.  Robert H. van Gent has a
+# transcript of the decree in .
+# The rest of the data are from Shanks & Pottenger.
+
+# From Paul Eggert (2006-04-25):
+# Tomorrow's Manila Standard reports that the Philippines Department of
+# Trade and Industry is considering adopting DST this June when the
+# rainy season begins.  See
+# .
+# For now, we'll ignore this, since it's not definite and we lack details.
+#
+# From Jesper Norgaard Welen (2006-04-26):
+# ... claims that Philippines had DST last time in 1990:
+# http://story.philippinetimes.com/p.x/ct/9/id/145be20cc6b121c0/cid/3e5bbccc730d258c/
+# [a story dated 2006-04-25 by Cris Larano of Dow Jones Newswires,
+# but no details]
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Phil	1936	only	-	Nov	1	0:00	1:00	S
+Rule	Phil	1937	only	-	Feb	1	0:00	0	-
+Rule	Phil	1954	only	-	Apr	12	0:00	1:00	S
+Rule	Phil	1954	only	-	Jul	1	0:00	0	-
+Rule	Phil	1978	only	-	Mar	22	0:00	1:00	S
+Rule	Phil	1978	only	-	Sep	21	0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Manila	-15:56:00 -	LMT	1844 Dec 31
+			8:04:00 -	LMT	1899 May 11
+			8:00	Phil	PH%sT	1942 May
+			9:00	-	JST	1944 Nov
+			8:00	Phil	PH%sT
+
+# Qatar
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Qatar	3:26:08 -	LMT	1920	# Al Dawhah / Doha
+			4:00	-	GST	1972 Jun
+			3:00	-	AST
+
+# Saudi Arabia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Riyadh	3:06:52 -	LMT	1950
+			3:00	-	AST
+
+# Singapore
+# The data here are taken from Mok Ly Yng (2003-10-30)
+# .
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
+			6:55:25	-	SMT	1905 Jun  1 # Singapore M.T.
+			7:00	-	MALT	1933 Jan  1 # Malaya Time
+			7:00	0:20	MALST	1936 Jan  1
+			7:20	-	MALT	1941 Sep  1
+			7:30	-	MALT	1942 Feb 16
+			9:00	-	JST	1945 Sep 12
+			7:30	-	MALT	1965 Aug  9 # independence
+			7:30	-	SGT	1982 Jan  1 # Singapore Time
+			8:00	-	SGT
+
+# Spratly Is
+# no information
+
+# Sri Lanka
+# From Paul Eggert (1996-09-03):
+# "Sri Lanka advances clock by an hour to avoid blackout"
+# (www.virtual-pc.com/lankaweb/news/items/240596-2.html, 1996-05-24,
+# no longer available as of 1999-08-17)
+# reported ``the country's standard time will be put forward by one hour at
+# midnight Friday (1830 GMT) `in the light of the present power crisis'.''
+#
+# From Dharmasiri Senanayake, Sri Lanka Media Minister (1996-10-24), as quoted
+# by Shamindra in
+# 
+# Daily News - Hot News Section (1996-10-26)
+# :
+# With effect from 12.30 a.m. on 26th October 1996
+# Sri Lanka will be six (06) hours ahead of GMT.
+
+# From Jesper Norgaard Welen (2006-04-14), quoting Sri Lanka News Online
+#  (2006-04-13):
+# 0030 hrs on April 15, 2006 (midnight of April 14, 2006 +30 minutes)
+# at present, become 2400 hours of April 14, 2006 (midnight of April 14, 2006).
+
+# From Peter Apps and Ranga Sirila of Reuters (2006-04-12) in:
+# 
+# [The Tamil Tigers] never accepted the original 1996 time change and simply
+# kept their clocks set five and a half hours ahead of Greenwich Mean
+# Time (GMT), in line with neighbor India.
+# From Paul Eggert (2006-04-18):
+# People who live in regions under Tamil control can use [TZ='Asia/Kolkata'],
+# as that zone has agreed with the Tamil areas since our cutoff date of 1970.
+
+# From K Sethu (2006-04-25):
+# I think the abbreviation LKT originated from the world of computers at
+# the time of or subsequent to the time zone changes by SL Government
+# twice in 1996 and probably SL Government or its standardization
+# agencies never declared an abbreviation as a national standard.
+#
+# I recollect before the recent change the government annoucemments
+# mentioning it as simply changing Sri Lanka Standard Time or Sri Lanka
+# Time and no mention was made about the abbreviation.
+#
+# If we look at Sri Lanka Department of Government's "Official News
+# Website of Sri Lanka" ... http://www.news.lk/ we can see that they
+# use SLT as abbreviation in time stamp at the beginning of each news
+# item....
+#
+# Within Sri Lanka I think LKT is well known among computer users and
+# adminsitrators.  In my opinion SLT may not be a good choice because the
+# nation's largest telcom / internet operator Sri Lanka Telcom is well
+# known by that abbreviation - simply as SLT (there IP domains are
+# slt.lk and sltnet.lk).
+#
+# But if indeed our government has adopted SLT as standard abbreviation
+# (that we have not known so far) then  it is better that it be used for
+# all computers.
+
+# From Paul Eggert (2006-04-25):
+# One possibility is that we wait for a bit for the dust to settle down
+# and then see what people actually say in practice.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Colombo	5:19:24 -	LMT	1880
+			5:19:32	-	MMT	1906	# Moratuwa Mean Time
+			5:30	-	IST	1942 Jan  5
+			5:30	0:30	IHST	1942 Sep
+			5:30	1:00	IST	1945 Oct 16 2:00
+			5:30	-	IST	1996 May 25 0:00
+			6:30	-	LKT	1996 Oct 26 0:30
+			6:00	-	LKT	2006 Apr 15 0:30
+			5:30	-	IST
+
+# Syria
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Syria	1920	1923	-	Apr	Sun>=15	2:00	1:00	S
+Rule	Syria	1920	1923	-	Oct	Sun>=1	2:00	0	-
+Rule	Syria	1962	only	-	Apr	29	2:00	1:00	S
+Rule	Syria	1962	only	-	Oct	1	2:00	0	-
+Rule	Syria	1963	1965	-	May	1	2:00	1:00	S
+Rule	Syria	1963	only	-	Sep	30	2:00	0	-
+Rule	Syria	1964	only	-	Oct	1	2:00	0	-
+Rule	Syria	1965	only	-	Sep	30	2:00	0	-
+Rule	Syria	1966	only	-	Apr	24	2:00	1:00	S
+Rule	Syria	1966	1976	-	Oct	1	2:00	0	-
+Rule	Syria	1967	1978	-	May	1	2:00	1:00	S
+Rule	Syria	1977	1978	-	Sep	1	2:00	0	-
+Rule	Syria	1983	1984	-	Apr	9	2:00	1:00	S
+Rule	Syria	1983	1984	-	Oct	1	2:00	0	-
+Rule	Syria	1986	only	-	Feb	16	2:00	1:00	S
+Rule	Syria	1986	only	-	Oct	9	2:00	0	-
+Rule	Syria	1987	only	-	Mar	1	2:00	1:00	S
+Rule	Syria	1987	1988	-	Oct	31	2:00	0	-
+Rule	Syria	1988	only	-	Mar	15	2:00	1:00	S
+Rule	Syria	1989	only	-	Mar	31	2:00	1:00	S
+Rule	Syria	1989	only	-	Oct	1	2:00	0	-
+Rule	Syria	1990	only	-	Apr	1	2:00	1:00	S
+Rule	Syria	1990	only	-	Sep	30	2:00	0	-
+Rule	Syria	1991	only	-	Apr	 1	0:00	1:00	S
+Rule	Syria	1991	1992	-	Oct	 1	0:00	0	-
+Rule	Syria	1992	only	-	Apr	 8	0:00	1:00	S
+Rule	Syria	1993	only	-	Mar	26	0:00	1:00	S
+Rule	Syria	1993	only	-	Sep	25	0:00	0	-
+# IATA SSIM (1998-02) says 1998-04-02;
+# (1998-09) says 1999-03-29 and 1999-09-29; (1999-02) says 1999-04-02,
+# 2000-04-02, and 2001-04-02; (1999-09) says 2000-03-31 and 2001-03-31;
+# (2006) says 2006-03-31 and 2006-09-22;
+# for now ignore all these claims and go with Shanks & Pottenger,
+# except for the 2006-09-22 claim (which seems right for Ramadan).
+Rule	Syria	1994	1996	-	Apr	 1	0:00	1:00	S
+Rule	Syria	1994	2005	-	Oct	 1	0:00	0	-
+Rule	Syria	1997	1998	-	Mar	lastMon	0:00	1:00	S
+Rule	Syria	1999	2006	-	Apr	 1	0:00	1:00	S
+# From Stephen Colebourne (2006-09-18):
+# According to IATA data, Syria will change DST on 21st September [21:00 UTC]
+# this year [only]....  This is probably related to Ramadan, like Egypt.
+Rule	Syria	2006	only	-	Sep	22	0:00	0	-
+# From Paul Eggert (2007-03-29):
+# Today the AP reported "Syria will switch to summertime at midnight Thursday."
+# http://www.iht.com/articles/ap/2007/03/29/africa/ME-GEN-Syria-Time-Change.php
+Rule	Syria	2007	only	-	Mar	lastFri	0:00	1:00	S
+# From Jesper Norgard (2007-10-27):
+# The sister center ICARDA of my work CIMMYT is confirming that Syria DST will
+# not take place 1.st November at 0:00 o'clock but 1.st November at 24:00 or
+# rather Midnight between Thursday and Friday. This does make more sence than
+# having it between Wednesday and Thursday (two workdays in Syria) since the
+# weekend in Syria is not Saturday and Sunday, but Friday and Saturday. So now
+# it is implemented at midnight of the last workday before weekend...
+# 
+# From Steffen Thorsen (2007-10-27):
+# Jesper Norgaard Welen wrote:
+# 
+# > "Winter local time in Syria will be observed at midnight of Thursday 1
+# > November 2007, and the clock will be put back 1 hour."
+# 
+# I found confirmation on this in this gov.sy-article (Arabic):
+# http://wehda.alwehda.gov.sy/_print_veiw.asp?FileName=12521710520070926111247
+# 
+# which using Google's translate tools says:
+# Council of Ministers also approved the commencement of work on 
+# identifying the winter time as of Friday, 2/11/2007 where the 60th 
+# minute delay at midnight Thursday 1/11/2007.
+Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
+
+# From Stephen Colebourne (2008-03-17):
+# For everyone's info, I saw an IATA time zone change for [Syria] for
+# this month (March 2008) in the last day or so...This is the data IATA
+# are now using:
+# Country     Time Standard   --- DST Start ---   --- DST End ---  DST
+# Name        Zone Variation   Time    Date        Time    Date
+# Variation
+# Syrian Arab
+# Republic    SY    +0200      2200  03APR08       2100  30SEP08   +0300
+#                              2200  02APR09       2100  30SEP09   +0300
+#                              2200  01APR10       2100  30SEP10   +0300
+
+# From Arthur David Olson (2008-03-17):
+# Here's a link to English-language coverage by the Syrian Arab News
+# Agency (SANA)...
+# 
+# http://www.sana.sy/eng/21/2008/03/11/165173.htm
+# ...which reads (in part) "The Cabinet approved the suggestion of the
+# Ministry of Electricity to begin daylight savings time on Friday April
+# 4th, advancing clocks one hour ahead on midnight of Thursday April 3rd."
+# Since Syria is two hours east of UTC, the 2200 and 2100 transition times
+# shown above match up with midnight in Syria.
+
+# From Arthur David Olson (2008-03-18):
+# My buest guess at a Syrian rule is "the Friday nearest April 1";
+# coding that involves either using a "Mar Fri>=29" construct that old time zone
+# compilers can't handle  or having multiple Rules (a la Israel).
+# For now, use "Apr Fri>=1", and go with IATA on a uniform Sep 30 end.
+
+# From Steffen Thorsen (2008-10-07):
+# Syria has now officially decided to end DST on 2008-11-01 this year,
+# according to the following article in the Syrian Arab News Agency (SANA).
+#
+# The article is in Arabic, and seems to tell that they will go back to
+# winter time on 2008-11-01 at 00:00 local daylight time (delaying/setting
+# clocks back 60 minutes).
+#
+# 
+# http://sana.sy/ara/2/2008/10/07/195459.htm
+# 
+
+# From Steffen Thorsen (2009-03-19):
+# Syria will start DST on 2009-03-27 00:00 this year according to many sources,
+# two examples:
+#
+# 
+# http://www.sana.sy/eng/21/2009/03/17/217563.htm
+# 
+# (English, Syrian Arab News # Agency)
+# 
+# http://thawra.alwehda.gov.sy/_View_news2.asp?FileName=94459258720090318012209
+# 
+# (Arabic, gov-site)
+#
+# We have not found any sources saying anything about when DST ends this year.
+#
+# Our summary
+# 
+# http://www.timeanddate.com/news/time/syria-dst-starts-march-27-2009.html
+# 
+
+Rule	Syria	2008	only	-	Apr	Fri>=1	0:00	1:00	S
+Rule	Syria	2008	max	-	Nov	1	0:00	0	-
+Rule	Syria	2009	max	-	Mar	lastFri	0:00	1:00	S
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Damascus	2:25:12 -	LMT	1920	# Dimashq
+			2:00	Syria	EE%sT
+
+# Tajikistan
+# From Shanks & Pottenger.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Dushanbe	4:35:12 -	LMT	1924 May  2
+			5:00	-	DUST	1930 Jun 21 # Dushanbe Time
+			6:00 RussiaAsia DUS%sT	1991 Mar 31 2:00s
+			5:00	1:00	DUSST	1991 Sep  9 2:00s
+			5:00	-	TJT		    # Tajikistan Time
+
+# Thailand
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Bangkok	6:42:04	-	LMT	1880
+			6:42:04	-	BMT	1920 Apr # Bangkok Mean Time
+			7:00	-	ICT
+
+# Turkmenistan
+# From Shanks & Pottenger.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Ashgabat	3:53:32 -	LMT	1924 May  2 # or Ashkhabad
+			4:00	-	ASHT	1930 Jun 21 # Ashkhabad Time
+			5:00 RussiaAsia	ASH%sT	1991 Mar 31 2:00
+			4:00 RussiaAsia	ASH%sT	1991 Oct 27 # independence
+			4:00 RussiaAsia	TM%sT	1992 Jan 19 2:00
+			5:00	-	TMT
+
+# United Arab Emirates
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Dubai	3:41:12 -	LMT	1920
+			4:00	-	GST
+
+# Uzbekistan
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Samarkand	4:27:12 -	LMT	1924 May  2
+			4:00	-	SAMT	1930 Jun 21 # Samarkand Time
+			5:00	-	SAMT	1981 Apr  1
+			5:00	1:00	SAMST	1981 Oct  1
+			6:00	-	TAST	1982 Apr  1 # Tashkent Time
+			5:00 RussiaAsia	SAM%sT	1991 Sep  1 # independence
+			5:00 RussiaAsia	UZ%sT	1992
+			5:00	-	UZT
+Zone	Asia/Tashkent	4:37:12 -	LMT	1924 May  2
+			5:00	-	TAST	1930 Jun 21 # Tashkent Time
+			6:00 RussiaAsia	TAS%sT	1991 Mar 31 2:00
+			5:00 RussiaAsia	TAS%sT	1991 Sep  1 # independence
+			5:00 RussiaAsia	UZ%sT	1992
+			5:00	-	UZT
+
+# Vietnam
+
+# From Arthur David Olson (2008-03-18):
+# The English-language name of Vietnam's most populous city is "Ho Chi Min City";
+# we use Ho_Chi_Minh below to avoid a name of more than 14 characters.
+
+# From Shanks & Pottenger:
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Ho_Chi_Minh	7:06:40 -	LMT	1906 Jun  9
+			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
+			7:00	-	ICT	1912 May
+			8:00	-	ICT	1931 May
+			7:00	-	ICT
+
+# Yemen
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Asia/Aden	3:00:48	-	LMT	1950
+			3:00	-	AST
diff --git a/extra/zoneinfo/australasia b/extra/zoneinfo/australasia
new file mode 100644
index 0000000000..41608cdc34
--- /dev/null
+++ b/extra/zoneinfo/australasia
@@ -0,0 +1,1454 @@
+# @(#)australasia	8.9
+# 
+
+# This file also includes Pacific islands.
+
+# Notes are at the end of this file
+
+###############################################################################
+
+# Australia
+
+# Please see the notes below for the controversy about "EST" versus "AEST" etc.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Aus	1917	only	-	Jan	 1	0:01	1:00	-
+Rule	Aus	1917	only	-	Mar	25	2:00	0	-
+Rule	Aus	1942	only	-	Jan	 1	2:00	1:00	-
+Rule	Aus	1942	only	-	Mar	29	2:00	0	-
+Rule	Aus	1942	only	-	Sep	27	2:00	1:00	-
+Rule	Aus	1943	1944	-	Mar	lastSun	2:00	0	-
+Rule	Aus	1943	only	-	Oct	 3	2:00	1:00	-
+# Go with Whitman and the Australian National Standards Commission, which
+# says W Australia didn't use DST in 1943/1944.  Ignore Whitman's claim that
+# 1944/1945 was just like 1943/1944.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+# Northern Territory
+Zone Australia/Darwin	 8:43:20 -	LMT	1895 Feb
+			 9:00	-	CST	1899 May
+			 9:30	Aus	CST
+# Western Australia
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	AW	1974	only	-	Oct	lastSun	2:00s	1:00	-
+Rule	AW	1975	only	-	Mar	Sun>=1	2:00s	0	-
+Rule	AW	1983	only	-	Oct	lastSun	2:00s	1:00	-
+Rule	AW	1984	only	-	Mar	Sun>=1	2:00s	0	-
+Rule	AW	1991	only	-	Nov	17	2:00s	1:00	-
+Rule	AW	1992	only	-	Mar	Sun>=1	2:00s	0	-
+Rule	AW	2006	only	-	Dec	 3	2:00s	1:00	-
+Rule	AW	2007	2009	-	Mar	lastSun	2:00s	0	-
+Rule	AW	2007	2008	-	Oct	lastSun	2:00s	1:00	-
+Zone Australia/Perth	 7:43:24 -	LMT	1895 Dec
+			 8:00	Aus	WST	1943 Jul
+			 8:00	AW	WST
+Zone Australia/Eucla	 8:35:28 -	LMT	1895 Dec
+			 8:45	Aus	CWST	1943 Jul
+			 8:45	AW	CWST
+
+# Queensland
+#
+# From Alex Livingston (1996-11-01):
+# I have heard or read more than once that some resort islands off the coast
+# of Queensland chose to keep observing daylight-saving time even after
+# Queensland ceased to.
+#
+# From Paul Eggert (1996-11-22):
+# IATA SSIM (1993-02/1994-09) say that the Holiday Islands (Hayman, Lindeman,
+# Hamilton) observed DST for two years after the rest of Queensland stopped.
+# Hamilton is the largest, but there is also a Hamilton in Victoria,
+# so use Lindeman.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	AQ	1971	only	-	Oct	lastSun	2:00s	1:00	-
+Rule	AQ	1972	only	-	Feb	lastSun	2:00s	0	-
+Rule	AQ	1989	1991	-	Oct	lastSun	2:00s	1:00	-
+Rule	AQ	1990	1992	-	Mar	Sun>=1	2:00s	0	-
+Rule	Holiday	1992	1993	-	Oct	lastSun	2:00s	1:00	-
+Rule	Holiday	1993	1994	-	Mar	Sun>=1	2:00s	0	-
+Zone Australia/Brisbane	10:12:08 -	LMT	1895
+			10:00	Aus	EST	1971
+			10:00	AQ	EST
+Zone Australia/Lindeman  9:55:56 -	LMT	1895
+			10:00	Aus	EST	1971
+			10:00	AQ	EST	1992 Jul
+			10:00	Holiday	EST
+
+# South Australia
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	AS	1971	1985	-	Oct	lastSun	2:00s	1:00	-
+Rule	AS	1986	only	-	Oct	19	2:00s	1:00	-
+Rule	AS	1987	2007	-	Oct	lastSun	2:00s	1:00	-
+Rule	AS	1972	only	-	Feb	27	2:00s	0	-
+Rule	AS	1973	1985	-	Mar	Sun>=1	2:00s	0	-
+Rule	AS	1986	1989	-	Mar	Sun>=15	2:00s	0	-
+Rule	AS	1990	only	-	Mar	Sun>=18	2:00s	0	-
+Rule	AS	1991	only	-	Mar	Sun>=1	2:00s	0	-
+Rule	AS	1992	only	-	Mar	Sun>=18	2:00s	0	-
+Rule	AS	1993	only	-	Mar	Sun>=1	2:00s	0	-
+Rule	AS	1994	only	-	Mar	Sun>=18	2:00s	0	-
+Rule	AS	1995	2005	-	Mar	lastSun	2:00s	0	-
+Rule	AS	2006	only	-	Apr	Sun>=1	2:00s	0	-
+Rule	AS	2007	only	-	Mar	lastSun	2:00s	0	-
+Rule	AS	2008	max	-	Apr	Sun>=1	2:00s	0	-
+Rule	AS	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Australia/Adelaide	9:14:20 -	LMT	1895 Feb
+			9:00	-	CST	1899 May
+			9:30	Aus	CST	1971
+			9:30	AS	CST
+
+# Tasmania
+#
+# From Paul Eggert (2005-08-16):
+# 
+# says King Island didn't observe DST from WWII until late 1971.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	AT	1967	only	-	Oct	Sun>=1	2:00s	1:00	-
+Rule	AT	1968	only	-	Mar	lastSun	2:00s	0	-
+Rule	AT	1968	1985	-	Oct	lastSun	2:00s	1:00	-
+Rule	AT	1969	1971	-	Mar	Sun>=8	2:00s	0	-
+Rule	AT	1972	only	-	Feb	lastSun	2:00s	0	-
+Rule	AT	1973	1981	-	Mar	Sun>=1	2:00s	0	-
+Rule	AT	1982	1983	-	Mar	lastSun	2:00s	0	-
+Rule	AT	1984	1986	-	Mar	Sun>=1	2:00s	0	-
+Rule	AT	1986	only	-	Oct	Sun>=15	2:00s	1:00	-
+Rule	AT	1987	1990	-	Mar	Sun>=15	2:00s	0	-
+Rule	AT	1987	only	-	Oct	Sun>=22	2:00s	1:00	-
+Rule	AT	1988	1990	-	Oct	lastSun	2:00s	1:00	-
+Rule	AT	1991	1999	-	Oct	Sun>=1	2:00s	1:00	-
+Rule	AT	1991	2005	-	Mar	lastSun	2:00s	0	-
+Rule	AT	2000	only	-	Aug	lastSun	2:00s	1:00	-
+Rule	AT	2001	max	-	Oct	Sun>=1	2:00s	1:00	-
+Rule	AT	2006	only	-	Apr	Sun>=1	2:00s	0	-
+Rule	AT	2007	only	-	Mar	lastSun	2:00s	0	-
+Rule	AT	2008	max	-	Apr	Sun>=1	2:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Australia/Hobart	9:49:16	-	LMT	1895 Sep
+			10:00	-	EST	1916 Oct 1 2:00
+			10:00	1:00	EST	1917 Feb
+			10:00	Aus	EST	1967
+			10:00	AT	EST
+Zone Australia/Currie	9:35:28	-	LMT	1895 Sep
+			10:00	-	EST	1916 Oct 1 2:00
+			10:00	1:00	EST	1917 Feb
+			10:00	Aus	EST	1971 Jul
+			10:00	AT	EST
+
+# Victoria
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	AV	1971	1985	-	Oct	lastSun	2:00s	1:00	-
+Rule	AV	1972	only	-	Feb	lastSun	2:00s	0	-
+Rule	AV	1973	1985	-	Mar	Sun>=1	2:00s	0	-
+Rule	AV	1986	1990	-	Mar	Sun>=15	2:00s	0	-
+Rule	AV	1986	1987	-	Oct	Sun>=15	2:00s	1:00	-
+Rule	AV	1988	1999	-	Oct	lastSun	2:00s	1:00	-
+Rule	AV	1991	1994	-	Mar	Sun>=1	2:00s	0	-
+Rule	AV	1995	2005	-	Mar	lastSun	2:00s	0	-
+Rule	AV	2000	only	-	Aug	lastSun	2:00s	1:00	-
+Rule	AV	2001	2007	-	Oct	lastSun	2:00s	1:00	-
+Rule	AV	2006	only	-	Apr	Sun>=1	2:00s	0	-
+Rule	AV	2007	only	-	Mar	lastSun	2:00s	0	-
+Rule	AV	2008	max	-	Apr	Sun>=1	2:00s	0	-
+Rule	AV	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Australia/Melbourne 9:39:52 -	LMT	1895 Feb
+			10:00	Aus	EST	1971
+			10:00	AV	EST
+
+# New South Wales
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	AN	1971	1985	-	Oct	lastSun	2:00s	1:00	-
+Rule	AN	1972	only	-	Feb	27	2:00s	0	-
+Rule	AN	1973	1981	-	Mar	Sun>=1	2:00s	0	-
+Rule	AN	1982	only	-	Apr	Sun>=1	2:00s	0	-
+Rule	AN	1983	1985	-	Mar	Sun>=1	2:00s	0	-
+Rule	AN	1986	1989	-	Mar	Sun>=15	2:00s	0	-
+Rule	AN	1986	only	-	Oct	19	2:00s	1:00	-
+Rule	AN	1987	1999	-	Oct	lastSun	2:00s	1:00	-
+Rule	AN	1990	1995	-	Mar	Sun>=1	2:00s	0	-
+Rule	AN	1996	2005	-	Mar	lastSun	2:00s	0	-
+Rule	AN	2000	only	-	Aug	lastSun	2:00s	1:00	-
+Rule	AN	2001	2007	-	Oct	lastSun	2:00s	1:00	-
+Rule	AN	2006	only	-	Apr	Sun>=1	2:00s	0	-
+Rule	AN	2007	only	-	Mar	lastSun	2:00s	0	-
+Rule	AN	2008	max	-	Apr	Sun>=1	2:00s	0	-
+Rule	AN	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Australia/Sydney	10:04:52 -	LMT	1895 Feb
+			10:00	Aus	EST	1971
+			10:00	AN	EST
+Zone Australia/Broken_Hill 9:25:48 -	LMT	1895 Feb
+			10:00	-	EST	1896 Aug 23
+			9:00	-	CST	1899 May
+			9:30	Aus	CST	1971
+			9:30	AN	CST	2000
+			9:30	AS	CST
+
+# Lord Howe Island
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	LH	1981	1984	-	Oct	lastSun	2:00	1:00	-
+Rule	LH	1982	1985	-	Mar	Sun>=1	2:00	0	-
+Rule	LH	1985	only	-	Oct	lastSun	2:00	0:30	-
+Rule	LH	1986	1989	-	Mar	Sun>=15	2:00	0	-
+Rule	LH	1986	only	-	Oct	19	2:00	0:30	-
+Rule	LH	1987	1999	-	Oct	lastSun	2:00	0:30	-
+Rule	LH	1990	1995	-	Mar	Sun>=1	2:00	0	-
+Rule	LH	1996	2005	-	Mar	lastSun	2:00	0	-
+Rule	LH	2000	only	-	Aug	lastSun	2:00	0:30	-
+Rule	LH	2001	2007	-	Oct	lastSun	2:00	0:30	-
+Rule	LH	2006	only	-	Apr	Sun>=1	2:00	0	-
+Rule	LH	2007	only	-	Mar	lastSun	2:00	0	-
+Rule	LH	2008	max	-	Apr	Sun>=1	2:00	0	-
+Rule	LH	2008	max	-	Oct	Sun>=1	2:00	0:30	-
+Zone Australia/Lord_Howe 10:36:20 -	LMT	1895 Feb
+			10:00	-	EST	1981 Mar
+			10:30	LH	LHST
+
+# Australian miscellany
+#
+# Ashmore Is, Cartier
+# no indigenous inhabitants; only seasonal caretakers
+# no times are set
+#
+# Coral Sea Is
+# no indigenous inhabitants; only meteorologists
+# no times are set
+#
+# Macquarie
+# permanent occupation (scientific station) since 1948;
+# sealing and penguin oil station operated 1888/1917
+# like Australia/Hobart
+
+# Christmas
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Indian/Christmas	7:02:52 -	LMT	1895 Feb
+			7:00	-	CXT	# Christmas Island Time
+
+# Cook Is
+# From Shanks & Pottenger:
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Cook	1978	only	-	Nov	12	0:00	0:30	HS
+Rule	Cook	1979	1991	-	Mar	Sun>=1	0:00	0	-
+Rule	Cook	1979	1990	-	Oct	lastSun	0:00	0:30	HS
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Rarotonga	-10:39:04 -	LMT	1901		# Avarua
+			-10:30	-	CKT	1978 Nov 12	# Cook Is Time
+			-10:00	Cook	CK%sT
+
+# Cocos
+# These islands were ruled by the Ross family from about 1830 to 1978.
+# We don't know when standard time was introduced; for now, we guess 1900.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Indian/Cocos	6:27:40	-	LMT	1900
+			6:30	-	CCT	# Cocos Islands Time
+
+# Fiji
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Fiji	1998	1999	-	Nov	Sun>=1	2:00	1:00	S
+Rule	Fiji	1999	2000	-	Feb	lastSun	3:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Fiji	11:53:40 -	LMT	1915 Oct 26	# Suva
+			12:00	Fiji	FJ%sT	# Fiji Time
+
+# French Polynesia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Gambier	 -8:59:48 -	LMT	1912 Oct	# Rikitea
+			 -9:00	-	GAMT	# Gambier Time
+Zone	Pacific/Marquesas -9:18:00 -	LMT	1912 Oct
+			 -9:30	-	MART	# Marquesas Time
+Zone	Pacific/Tahiti	 -9:58:16 -	LMT	1912 Oct	# Papeete
+			-10:00	-	TAHT	# Tahiti Time
+# Clipperton (near North America) is administered from French Polynesia;
+# it is uninhabited.
+
+# Guam
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Guam	-14:21:00 -	LMT	1844 Dec 31
+			 9:39:00 -	LMT	1901		# Agana
+			10:00	-	GST	2000 Dec 23	# Guam
+			10:00	-	ChST	# Chamorro Standard Time
+
+# Kiribati
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Tarawa	 11:32:04 -	LMT	1901		# Bairiki
+			 12:00	-	GILT		 # Gilbert Is Time
+Zone Pacific/Enderbury	-11:24:20 -	LMT	1901
+			-12:00	-	PHOT	1979 Oct # Phoenix Is Time
+			-11:00	-	PHOT	1995
+			 13:00	-	PHOT
+Zone Pacific/Kiritimati	-10:29:20 -	LMT	1901
+			-10:40	-	LINT	1979 Oct # Line Is Time
+			-10:00	-	LINT	1995
+			 14:00	-	LINT
+
+# N Mariana Is
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Saipan	-14:17:00 -	LMT	1844 Dec 31
+			 9:43:00 -	LMT	1901
+			 9:00	-	MPT	1969 Oct # N Mariana Is Time
+			10:00	-	MPT	2000 Dec 23
+			10:00	-	ChST	# Chamorro Standard Time
+
+# Marshall Is
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Majuro	11:24:48 -	LMT	1901
+			11:00	-	MHT	1969 Oct # Marshall Islands Time
+			12:00	-	MHT
+Zone Pacific/Kwajalein	11:09:20 -	LMT	1901
+			11:00	-	MHT	1969 Oct
+			-12:00	-	KWAT	1993 Aug 20	# Kwajalein Time
+			12:00	-	MHT
+
+# Micronesia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Truk	10:07:08 -	LMT	1901
+			10:00	-	TRUT			# Truk Time
+Zone Pacific/Ponape	10:32:52 -	LMT	1901		# Kolonia
+			11:00	-	PONT			# Ponape Time
+Zone Pacific/Kosrae	10:51:56 -	LMT	1901
+			11:00	-	KOST	1969 Oct	# Kosrae Time
+			12:00	-	KOST	1999
+			11:00	-	KOST
+
+# Nauru
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Nauru	11:07:40 -	LMT	1921 Jan 15	# Uaobe
+			11:30	-	NRT	1942 Mar 15	# Nauru Time
+			9:00	-	JST	1944 Aug 15
+			11:30	-	NRT	1979 May
+			12:00	-	NRT
+
+# New Caledonia
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	NC	1977	1978	-	Dec	Sun>=1	0:00	1:00	S
+Rule	NC	1978	1979	-	Feb	27	0:00	0	-
+Rule	NC	1996	only	-	Dec	 1	2:00s	1:00	S
+# Shanks & Pottenger say the following was at 2:00; go with IATA.
+Rule	NC	1997	only	-	Mar	 2	2:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Noumea	11:05:48 -	LMT	1912 Jan 13
+			11:00	NC	NC%sT
+
+
+###############################################################################
+
+# New Zealand
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	NZ	1927	only	-	Nov	 6	2:00	1:00	S
+Rule	NZ	1928	only	-	Mar	 4	2:00	0	M
+Rule	NZ	1928	1933	-	Oct	Sun>=8	2:00	0:30	S
+Rule	NZ	1929	1933	-	Mar	Sun>=15	2:00	0	M
+Rule	NZ	1934	1940	-	Apr	lastSun	2:00	0	M
+Rule	NZ	1934	1940	-	Sep	lastSun	2:00	0:30	S
+Rule	NZ	1946	only	-	Jan	 1	0:00	0	S
+# Since 1957 Chatham has been 45 minutes ahead of NZ, but there's no
+# convenient notation for this so we must duplicate the Rule lines.
+Rule	NZ	1974	only	-	Nov	Sun>=1	2:00s	1:00	D
+Rule	Chatham	1974	only	-	Nov	Sun>=1	2:45s	1:00	D
+Rule	NZ	1975	only	-	Feb	lastSun	2:00s	0	S
+Rule	Chatham	1975	only	-	Feb	lastSun	2:45s	0	S
+Rule	NZ	1975	1988	-	Oct	lastSun	2:00s	1:00	D
+Rule	Chatham	1975	1988	-	Oct	lastSun	2:45s	1:00	D
+Rule	NZ	1976	1989	-	Mar	Sun>=1	2:00s	0	S
+Rule	Chatham	1976	1989	-	Mar	Sun>=1	2:45s	0	S
+Rule	NZ	1989	only	-	Oct	Sun>=8	2:00s	1:00	D
+Rule	Chatham	1989	only	-	Oct	Sun>=8	2:45s	1:00	D
+Rule	NZ	1990	2006	-	Oct	Sun>=1	2:00s	1:00	D
+Rule	Chatham	1990	2006	-	Oct	Sun>=1	2:45s	1:00	D
+Rule	NZ	1990	2007	-	Mar	Sun>=15	2:00s	0	S
+Rule	Chatham	1990	2007	-	Mar	Sun>=15	2:45s	0	S
+Rule	NZ	2007	max	-	Sep	lastSun	2:00s	1:00	D
+Rule	Chatham	2007	max	-	Sep	lastSun	2:45s	1:00	D
+Rule	NZ	2008	max	-	Apr	Sun>=1	2:00s	0	S
+Rule	Chatham	2008	max	-	Apr	Sun>=1	2:45s	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Auckland	11:39:04 -	LMT	1868 Nov  2
+			11:30	NZ	NZ%sT	1946 Jan  1
+			12:00	NZ	NZ%sT
+Zone Pacific/Chatham	12:13:48 -	LMT	1957 Jan  1
+			12:45	Chatham	CHA%sT
+
+
+# Auckland Is
+# uninhabited; Maori and Moriori, colonial settlers, pastoralists, sealers,
+# and scientific personnel have wintered
+
+# Campbell I
+# minor whaling stations operated 1909/1914
+# scientific station operated 1941/1995;
+# previously whalers, sealers, pastoralists, and scientific personnel wintered
+# was probably like Pacific/Auckland
+
+###############################################################################
+
+
+# Niue
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Niue	-11:19:40 -	LMT	1901		# Alofi
+			-11:20	-	NUT	1951	# Niue Time
+			-11:30	-	NUT	1978 Oct 1
+			-11:00	-	NUT
+
+# Norfolk
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Norfolk	11:11:52 -	LMT	1901		# Kingston
+			11:12	-	NMT	1951	# Norfolk Mean Time
+			11:30	-	NFT		# Norfolk Time
+
+# Palau (Belau)
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Palau	8:57:56 -	LMT	1901		# Koror
+			9:00	-	PWT	# Palau Time
+
+# Papua New Guinea
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Port_Moresby 9:48:40 -	LMT	1880
+			9:48:32	-	PMMT	1895	# Port Moresby Mean Time
+			10:00	-	PGT		# Papua New Guinea Time
+
+# Pitcairn
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Pitcairn	-8:40:20 -	LMT	1901		# Adamstown
+			-8:30	-	PNT	1998 Apr 27 00:00
+			-8:00	-	PST	# Pitcairn Standard Time
+
+# American Samoa
+Zone Pacific/Pago_Pago	 12:37:12 -	LMT	1879 Jul  5
+			-11:22:48 -	LMT	1911
+			-11:30	-	SAMT	1950		# Samoa Time
+			-11:00	-	NST	1967 Apr	# N=Nome
+			-11:00	-	BST	1983 Nov 30	# B=Bering
+			-11:00	-	SST			# S=Samoa
+
+# Samoa
+Zone Pacific/Apia	 12:33:04 -	LMT	1879 Jul  5
+			-11:26:56 -	LMT	1911
+			-11:30	-	SAMT	1950		# Samoa Time
+			-11:00	-	WST			# Samoa Time
+
+# Solomon Is
+# excludes Bougainville, for which see Papua New Guinea
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Guadalcanal 10:39:48 -	LMT	1912 Oct	# Honiara
+			11:00	-	SBT	# Solomon Is Time
+
+# Tokelau Is
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Fakaofo	-11:24:56 -	LMT	1901
+			-10:00	-	TKT	# Tokelau Time
+
+# Tonga
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Tonga	1999	only	-	Oct	 7	2:00s	1:00	S
+Rule	Tonga	2000	only	-	Mar	19	2:00s	0	-
+Rule	Tonga	2000	2001	-	Nov	Sun>=1	2:00	1:00	S
+Rule	Tonga	2001	2002	-	Jan	lastSun	2:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Tongatapu	12:19:20 -	LMT	1901
+			12:20	-	TOT	1941 # Tonga Time
+			13:00	-	TOT	1999
+			13:00	Tonga	TO%sT
+
+# Tuvalu
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Funafuti	11:56:52 -	LMT	1901
+			12:00	-	TVT	# Tuvalu Time
+
+
+# US minor outlying islands
+
+# Howland, Baker
+# Howland was mined for guano by American companies 1857-1878 and British
+# 1886-1891; Baker was similar but exact dates are not known.
+# Inhabited by civilians 1935-1942; U.S. military bases 1943-1944;
+# uninhabited thereafter.
+# Howland observed Hawaii Standard Time (UTC-10:30) in 1937;
+# see page 206 of Elgen M. Long and Marie K. Long,
+# Amelia Earhart: the Mystery Solved, Simon & Schuster (2000).
+# So most likely Howland and Baker observed Hawaii Time from 1935
+# until they were abandoned after the war.
+
+# Jarvis
+# Mined for guano by American companies 1857-1879 and British 1883?-1891?.
+# Inhabited by civilians 1935-1942; IGY scientific base 1957-1958;
+# uninhabited thereafter.
+# no information; was probably like Pacific/Kiritimati
+
+# Johnston
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Pacific/Johnston	-10:00	-	HST
+
+# Kingman
+# uninhabited
+
+# Midway
+#
+# From Mark Brader (2005-01-23):
+# [Fallacies and Fantasies of Air Transport History, by R.E.G. Davies,
+# published 1994 by Paladwr Press, McLean, VA, USA; ISBN 0-9626483-5-3]
+# reproduced a Pan American Airways timeables from 1936, for their weekly
+# "Orient Express" flights between San Francisco and Manila, and connecting
+# flights to Chicago and the US East Coast.  As it uses some time zone
+# designations that I've never seen before:....
+# Fri. 6:30A Lv. HONOLOLU (Pearl Harbor), H.I.   H.L.T. Ar. 5:30P Sun.
+#  "   3:00P Ar. MIDWAY ISLAND . . . . . . . . . M.L.T. Lv. 6:00A  "
+#
+Zone Pacific/Midway	-11:49:28 -	LMT	1901
+			-11:00	-	NST	1956 Jun  3
+			-11:00	1:00	NDT	1956 Sep  2
+			-11:00	-	NST	1967 Apr	# N=Nome
+			-11:00	-	BST	1983 Nov 30	# B=Bering
+			-11:00	-	SST			# S=Samoa
+
+# Palmyra
+# uninhabited since World War II; was probably like Pacific/Kiritimati
+
+# Wake
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Wake	11:06:28 -	LMT	1901
+			12:00	-	WAKT	# Wake Time
+
+
+# Vanuatu
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Vanuatu	1983	only	-	Sep	25	0:00	1:00	S
+Rule	Vanuatu	1984	1991	-	Mar	Sun>=23	0:00	0	-
+Rule	Vanuatu	1984	only	-	Oct	23	0:00	1:00	S
+Rule	Vanuatu	1985	1991	-	Sep	Sun>=23	0:00	1:00	S
+Rule	Vanuatu	1992	1993	-	Jan	Sun>=23	0:00	0	-
+Rule	Vanuatu	1992	only	-	Oct	Sun>=23	0:00	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Efate	11:13:16 -	LMT	1912 Jan 13		# Vila
+			11:00	Vanuatu	VU%sT	# Vanuatu Time
+
+# Wallis and Futuna
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Pacific/Wallis	12:15:20 -	LMT	1901
+			12:00	-	WFT	# Wallis & Futuna Time
+
+###############################################################################
+
+# NOTES
+
+# This data is by no means authoritative; if you think you know better,
+# go ahead and edit the file (and please send any changes to
+# tz@elsie.nci.nih.gov for general use in the future).
+
+# From Paul Eggert (2006-03-22):
+# A good source for time zone historical data outside the U.S. is
+# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
+# San Diego: ACS Publications, Inc. (2003).
+#
+# Gwillim Law writes that a good source
+# for recent time zone data is the International Air Transport
+# Association's Standard Schedules Information Manual (IATA SSIM),
+# published semiannually.  Law sent in several helpful summaries
+# of the IATA's data after 1990.
+#
+# Except where otherwise noted, Shanks & Pottenger is the source for
+# entries through 1990, and IATA SSIM is the source for entries afterwards.
+#
+# Another source occasionally used is Edward W. Whitman, World Time Differences,
+# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
+# I found in the UCLA library.
+#
+# A reliable and entertaining source about time zones is
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
+#
+# I invented the abbreviations marked `*' in the following table;
+# the rest are from earlier versions of this file, or from other sources.
+# Corrections are welcome!
+#		std dst
+#		LMT	Local Mean Time
+#	  8:00	WST WST	Western Australia
+#	  8:45	CWST CWST Central Western Australia*
+#	  9:00	JST	Japan
+#	  9:30	CST CST	Central Australia
+#	 10:00	EST EST	Eastern Australia
+#	 10:00	ChST	Chamorro
+#	 10:30	LHST LHST Lord Howe*
+#	 11:30	NZMT NZST New Zealand through 1945
+#	 12:00	NZST NZDT New Zealand 1946-present
+#	 12:45	CHAST CHADT Chatham*
+#	-11:00	SST	Samoa
+#	-10:00	HST	Hawaii
+#	- 8:00	PST	Pitcairn*
+#
+# See the `northamerica' file for Hawaii.
+# See the `southamerica' file for Easter I and the Galapagos Is.
+
+###############################################################################
+
+# Australia
+
+# From Paul Eggert (2005-12-08):
+# 
+# Implementation Dates of Daylight Saving Time within Australia
+#  summarizes daylight saving issues in Australia.
+
+# From Arthur David Olson (2005-12-12):
+# 
+# Lawlink NSW:Daylight Saving in New South Wales
+#  covers New South Wales in particular.
+
+# From John Mackin (1991-03-06):
+# We in Australia have _never_ referred to DST as `daylight' time.
+# It is called `summer' time.  Now by a happy coincidence, `summer'
+# and `standard' happen to start with the same letter; hence, the
+# abbreviation does _not_ change...
+# The legislation does not actually define abbreviations, at least
+# in this State, but the abbreviation is just commonly taken to be the
+# initials of the phrase, and the legislation here uniformly uses
+# the phrase `summer time' and does not use the phrase `daylight
+# time'.
+# Announcers on the Commonwealth radio network, the ABC (for Australian
+# Broadcasting Commission), use the phrases `Eastern Standard Time'
+# or `Eastern Summer Time'.  (Note, though, that as I say in the
+# current australasia file, there is really no such thing.)  Announcers
+# on its overseas service, Radio Australia, use the same phrases
+# prefixed by the word `Australian' when referring to local times;
+# time announcements on that service, naturally enough, are made in UTC.
+
+# From Arthur David Olson (1992-03-08):
+# Given the above, what's chosen for year-round use is:
+#	CST	for any place operating at a GMTOFF of 9:30
+#	WST	for any place operating at a GMTOFF of 8:00
+#	EST	for any place operating at a GMTOFF of 10:00
+
+# From Chuck Soper (2006-06-01):
+# I recently found this Australian government web page on time zones:
+# 
+# And this government web page lists time zone names and abbreviations:
+# 
+
+# From Paul Eggert (2001-04-05), summarizing a long discussion about "EST"
+# versus "AEST" etc.:
+#
+# I see the following points of dispute:
+#
+# * How important are unique time zone abbreviations?
+#
+#   Here I tend to agree with the point (most recently made by Chris
+#   Newman) that unique abbreviations should not be essential for proper
+#   operation of software.  We have other instances of ambiguity
+#   (e.g. "IST" denoting both "Israel Standard Time" and "Indian
+#   Standard Time"), and they are not likely to go away any time soon.
+#   In the old days, some software mistakenly relied on unique
+#   abbreviations, but this is becoming less true with time, and I don't
+#   think it's that important to cater to such software these days.
+#
+#   On the other hand, there is another motivation for unambiguous
+#   abbreviations: it cuts down on human confusion.  This is
+#   particularly true for Australia, where "EST" can mean one thing for
+#   time T and a different thing for time T plus 1 second.
+#
+# * Does the relevant legislation indicate which abbreviations should be used?
+#
+#   Here I tend to think that things are a mess, just as they are in
+#   many other countries.  We Americans are currently disagreeing about
+#   which abbreviation to use for the newly legislated Chamorro Standard
+#   Time, for example.
+#
+#   Personally, I would prefer to use common practice; I would like to
+#   refer to legislation only for examples of common practice, or as a
+#   tiebreaker.
+#
+# * Do Australians more often use "Eastern Daylight Time" or "Eastern
+#   Summer Time"?  Do they typically prefix the time zone names with
+#   the word "Australian"?
+#
+#   My own impression is that both "Daylight Time" and "Summer Time" are
+#   common and are widely understood, but that "Summer Time" is more
+#   popular; and that the leading "A" is also common but is omitted more
+#   often than not.  I just used AltaVista advanced search and got the
+#   following count of page hits:
+#
+#     1,103 "Eastern Summer Time" AND domain:au
+#       971 "Australian Eastern Summer Time" AND domain:au
+#       613 "Eastern Daylight Time" AND domain:au
+#       127 "Australian Eastern Daylight Time" AND domain:au
+#
+#   Here "Summer" seems quite a bit more popular than "Daylight",
+#   particularly when we know the time zone is Australian and not US,
+#   say.  The "Australian" prefix seems to be popular for Eastern Summer
+#   Time, but unpopular for Eastern Daylight Time.
+#
+#   For abbreviations, tools like AltaVista are less useful because of
+#   ambiguity.  Many hits are not really time zones, unfortunately, and
+#   many hits denote US time zones and not Australian ones.  But here
+#   are the hit counts anyway:
+#
+#     161,304 "EST" and domain:au
+#      25,156 "EDT" and domain:au
+#      18,263 "AEST" and domain:au
+#      10,416 "AEDT" and domain:au
+#
+#      14,538 "CST" and domain:au
+#       5,728 "CDT" and domain:au
+#         176 "ACST" and domain:au
+#          29 "ACDT" and domain:au
+#
+#       7,539 "WST" and domain:au
+#          68 "AWST" and domain:au
+#
+#   This data suggest that Australians tend to omit the "A" prefix in
+#   practice.  The situation for "ST" versus "DT" is less clear, given
+#   the ambiguities involved.
+#
+# * How do Australians feel about the abbreviations in the tz database?
+#
+#   If you just count Australians on this list, I count 2 in favor and 3
+#   against.  One of the "against" votes (David Keegel) counseled delay,
+#   saying that both AEST/AEDT and EST/EST are widely used and
+#   understood in Australia.
+
+# From Paul Eggert (1995-12-19):
+# Shanks & Pottenger report 2:00 for all autumn changes in Australia and NZ.
+# Mark Prior writes that his newspaper
+# reports that NSW's fall 1995 change will occur at 2:00,
+# but Robert Elz says it's been 3:00 in Victoria since 1970
+# and perhaps the newspaper's `2:00' is referring to standard time.
+# For now we'll continue to assume 2:00s for changes since 1960.
+
+# From Eric Ulevik (1998-01-05):
+#
+# Here are some URLs to Australian time legislation. These URLs are stable,
+# and should probably be included in the data file. There are probably more
+# relevant entries in this database.
+#
+# NSW (including LHI and Broken Hill):
+# 
+# Standard Time Act 1987 (updated 1995-04-04)
+# 
+# ACT
+# 
+# Standard Time and Summer Time Act 1972
+# 
+# SA
+# 
+# Standard Time Act, 1898
+# 
+
+# From David Grosz (2005-06-13):
+# It was announced last week that Daylight Saving would be extended by
+# one week next year to allow for the 2006 Commonwealth Games.
+# Daylight Saving is now to end for next year only on the first Sunday
+# in April instead of the last Sunday in March.
+#
+# From Gwillim Law (2005-06-14):
+# I did some Googling and found that all of those states (and territory) plan
+# to extend DST together in 2006.
+# ACT: http://www.cmd.act.gov.au/mediareleases/fileread.cfm?file=86.txt
+# New South Wales: http://www.thecouriermail.news.com.au/common/story_page/0,5936,15538869%255E1702,00.html
+# South Australia: http://www.news.com.au/story/0,10117,15555031-1246,00.html
+# Tasmania: http://www.media.tas.gov.au/release.php?id=14772
+# Victoria: I wasn't able to find anything separate, but the other articles
+# allude to it.
+# But not Queensland
+# http://www.news.com.au/story/0,10117,15564030-1248,00.html.
+
+# Northern Territory
+
+# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
+# # The NORTHERN TERRITORY..  [ Courtesy N.T. Dept of the Chief Minister ]
+# #					[ Nov 1990 ]
+# #	N.T. have never utilised any DST due to sub-tropical/tropical location.
+# ...
+# Zone        Australia/North         9:30    -       CST
+
+# From Bradley White (1991-03-04):
+# A recent excerpt from an Australian newspaper...
+# the Northern Territory do[es] not have daylight saving.
+
+# Western Australia
+
+# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
+# #  The state of WESTERN AUSTRALIA..  [ Courtesy W.A. dept Premier+Cabinet ]
+# #						[ Nov 1990 ]
+# #	W.A. suffers from a great deal of public and political opposition to
+# #	DST in principle. A bill is brought before parliament in most years, but
+# #	usually defeated either in the upper house, or in party caucus
+# #	before reaching parliament.
+# ...
+# Zone	Australia/West		8:00	AW	%sST
+# ...
+# Rule	AW	1974	only	-	Oct	lastSun	2:00	1:00	D
+# Rule	AW	1975	only	-	Mar	Sun>=1	3:00	0	W
+# Rule	AW	1983	only	-	Oct	lastSun	2:00	1:00	D
+# Rule	AW	1984	only	-	Mar	Sun>=1	3:00	0	W
+
+# From Bradley White (1991-03-04):
+# A recent excerpt from an Australian newspaper...
+# Western Australia...do[es] not have daylight saving.
+
+# From John D. Newman via Bradley White (1991-11-02):
+# Western Australia is still on "winter time". Some DH in Sydney
+# rang me at home a few days ago at 6.00am. (He had just arrived at
+# work at 9.00am.)
+# W.A. is switching to Summer Time on Nov 17th just to confuse
+# everybody again.
+
+# From Arthur David Olson (1992-03-08):
+# The 1992 ending date used in the rules is a best guess;
+# it matches what was used in the past.
+
+# 
+# The Australian Bureau of Meteorology FAQ
+#  (1999-09-27) writes that Giles Meteorological Station uses
+# South Australian time even though it's located in Western Australia.
+
+# Queensland
+# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
+# #   The state of QUEENSLAND.. [ Courtesy Qld. Dept Premier Econ&Trade Devel ]
+# #						[ Dec 1990 ]
+# ...
+# Zone	Australia/Queensland	10:00	AQ	%sST
+# ...
+# Rule	AQ	1971	only	-	Oct	lastSun	2:00	1:00	D
+# Rule	AQ	1972	only	-	Feb	lastSun	3:00	0	E
+# Rule	AQ	1989	max	-	Oct	lastSun	2:00	1:00	D
+# Rule	AQ	1990	max	-	Mar	Sun>=1	3:00	0	E
+
+# From Bradley White (1989-12-24):
+# "Australia/Queensland" now observes daylight time (i.e. from
+# October 1989).
+
+# From Bradley White (1991-03-04):
+# A recent excerpt from an Australian newspaper...
+# ...Queensland...[has] agreed to end daylight saving
+# at 3am tomorrow (March 3)...
+
+# From John Mackin (1991-03-06):
+# I can certainly confirm for my part that Daylight Saving in NSW did in fact
+# end on Sunday, 3 March.  I don't know at what hour, though.  (It surprised
+# me.)
+
+# From Bradley White (1992-03-08):
+# ...there was recently a referendum in Queensland which resulted
+# in the experimental daylight saving system being abandoned. So, ...
+# ...
+# Rule	QLD	1989	1991	-	Oct	lastSun	2:00	1:00	D
+# Rule	QLD	1990	1992	-	Mar	Sun>=1	3:00	0	S
+# ...
+
+# From Arthur David Olson (1992-03-08):
+# The chosen rules the union of the 1971/1972 change and the 1989-1992 changes.
+
+# From Christopher Hunt (2006-11-21), after an advance warning
+# from Jesper Norgaard Welen (2006-11-01):
+# WA are trialing DST for three years.
+# 
+
+# From Rives McDow (2002-04-09):
+# The most interesting region I have found consists of three towns on the
+# southern coast....  South Australia observes daylight saving time; Western
+# Australia does not.  The two states are one and a half hours apart.  The
+# residents decided to forget about this nonsense of changing the clock so
+# much and set the local time 20 hours and 45 minutes from the
+# international date line, or right in the middle of the time of South
+# Australia and Western Australia....
+#
+# From Paul Eggert (2002-04-09):
+# This is confirmed by the section entitled
+# "What's the deal with time zones???" in
+# .
+#
+# From Alex Livingston (2006-12-07):
+# ... it was just on four years ago that I drove along the Eyre Highway,
+# which passes through eastern Western Australia close to the southern
+# coast of the continent.
+#
+# I paid particular attention to the time kept there. There can be no
+# dispute that UTC+08:45 was considered "the time" from the border
+# village just inside the border with South Australia to as far west
+# as just east of Caiguna. There can also be no dispute that Eucla is
+# the largest population centre in this zone....
+#
+# Now that Western Australia is observing daylight saving, the
+# question arose whether this part of the state would follow suit. I
+# just called the border village and confirmed that indeed they have,
+# meaning that they are now observing UTC+09:45.
+#
+# (2006-12-09):
+# I personally doubt that either experimentation with daylight saving
+# in WA or its introduction in SA had anything to do with the genesis
+# of this time zone.  My hunch is that it's been around since well
+# before 1975.  I remember seeing it noted on road maps decades ago.
+
+# From Paul Eggert (2006-12-15):
+# For lack of better info, assume the tradition dates back to the
+# introduction of standard time in 1895.
+
+
+# southeast Australia
+#
+# From Paul Eggert (2007-07-23):
+# Starting autumn 2008 Victoria, NSW, South Australia, Tasmania and the ACT
+# end DST the first Sunday in April and start DST the first Sunday in October.
+# http://www.theage.com.au/news/national/daylight-savings-to-span-six-months/2007/06/27/1182623966703.html
+
+
+# South Australia
+
+# From Bradley White (1991-03-04):
+# A recent excerpt from an Australian newspaper...
+# ...South Australia...[has] agreed to end daylight saving
+# at 3am tomorrow (March 3)...
+
+# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
+# #   The state of SOUTH AUSTRALIA....[ Courtesy of S.A. Dept of Labour ]
+# #						[ Nov 1990 ]
+# ...
+# Zone	Australia/South		9:30	AS	%sST
+# ...
+# Rule	 AS	1971	max	-	Oct	lastSun	2:00	1:00	D
+# Rule	 AS	1972	1985	-	Mar	Sun>=1	3:00	0	C
+# Rule	 AS	1986	1990	-	Mar	Sun>=15	3:00	0	C
+# Rule	 AS	1991	max	-	Mar	Sun>=1	3:00	0	C
+
+# From Bradley White (1992-03-11):
+# Recent correspondence with a friend in Adelaide
+# contained the following exchange:  "Due to the Adelaide Festival,
+# South Australia delays setting back our clocks for a few weeks."
+
+# From Robert Elz (1992-03-13):
+# I heard that apparently (or at least, it appears that)
+# South Aus will have an extra 3 weeks daylight saving every even
+# numbered year (from 1990).  That's when the Adelaide Festival
+# is on...
+
+# From Robert Elz (1992-03-16, 00:57:07 +1000):
+# DST didn't end in Adelaide today (yesterday)....
+# But whether it's "4th Sunday" or "2nd last Sunday" I have no idea whatever...
+# (it's just as likely to be "the Sunday we pick for this year"...).
+
+# From Bradley White (1994-04-11):
+# If Sun, 15 March, 1992 was at +1030 as kre asserts, but yet Sun, 20 March,
+# 1994 was at +0930 as John Connolly's customer seems to assert, then I can
+# only conclude that the actual rule is more complicated....
+
+# From John Warburton (1994-10-07):
+# The new Daylight Savings dates for South Australia ...
+# was gazetted in the Government Hansard on Sep 26 1994....
+# start on last Sunday in October and end in last sunday in March.
+
+# From Paul Eggert (2007-07-23):
+# See "southeast Australia" above for 2008 and later.
+
+# Tasmania
+
+# The rules for 1967 through 1991 were reported by George Shepherd
+# via Simon Woodhead via Robert Elz (1991-03-06):
+# #  The state of TASMANIA.. [Courtesy Tasmanian Dept of Premier + Cabinet ]
+# #					[ Nov 1990 ]
+
+# From Bill Hart via Guy Harris (1991-10-10):
+# Oh yes, the new daylight savings rules are uniquely tasmanian, we have
+# 6 weeks a year now when we are out of sync with the rest of Australia
+# (but nothing new about that).
+
+# From Alex Livingston (1999-10-04):
+# I heard on the ABC (Australian Broadcasting Corporation) radio news on the
+# (long) weekend that Tasmania, which usually goes its own way in this regard,
+# has decided to join with most of NSW, the ACT, and most of Victoria
+# (Australia) and start daylight saving on the last Sunday in August in 2000
+# instead of the first Sunday in October.
+
+# Sim Alam (2000-07-03) reported a legal citation for the 2000/2001 rules:
+# http://www.thelaw.tas.gov.au/fragview/42++1968+GS3A@EN+2000070300
+
+# From Paul Eggert (2007-07-23):
+# See "southeast Australia" above for 2008 and later.
+
+# Victoria
+
+# The rules for 1971 through 1991 were reported by George Shepherd
+# via Simon Woodhead via Robert Elz (1991-03-06):
+# #   The state of VICTORIA.. [ Courtesy of Vic. Dept of Premier + Cabinet ]
+# #						[ Nov 1990 ]
+
+# From Scott Harrington (2001-08-29):
+# On KQED's "City Arts and Lectures" program last night I heard an
+# interesting story about daylight savings time.  Dr. John Heilbron was
+# discussing his book "The Sun in the Church: Cathedrals as Solar
+# Observatories"[1], and in particular the Shrine of Remembrance[2] located
+# in Melbourne, Australia.
+#
+# Apparently the shrine's main purpose is a beam of sunlight which
+# illuminates a special spot on the floor at the 11th hour of the 11th day
+# of the 11th month (Remembrance Day) every year in memory of Australia's
+# fallen WWI soldiers.  And if you go there on Nov. 11, at 11am local time,
+# you will indeed see the sunbeam illuminate the special spot at the
+# expected time.
+#
+# However, that is only because of some special mirror contraption that had
+# to be employed, since due to daylight savings time, the true solar time of
+# the remembrance moment occurs one hour later (or earlier?).  Perhaps
+# someone with more information on this jury-rig can tell us more.
+#
+# [1] http://www.hup.harvard.edu/catalog/HEISUN.html
+# [2] http://www.shrine.org.au
+
+# From Paul Eggert (2007-07-23):
+# See "southeast Australia" above for 2008 and later.
+
+# New South Wales
+
+# From Arthur David Olson:
+# New South Wales and subjurisdictions have their own ideas of a fun time.
+# Based on law library research by John Mackin,
+# who notes:
+#	In Australia, time is not legislated federally, but rather by the
+#	individual states.  Thus, while such terms as ``Eastern Standard Time''
+#	[I mean, of course, Australian EST, not any other kind] are in common
+#	use, _they have NO REAL MEANING_, as they are not defined in the
+#	legislation.  This is very important to understand.
+#	I have researched New South Wales time only...
+
+# From Eric Ulevik (1999-05-26):
+# DST will start in NSW on the last Sunday of August, rather than the usual
+# October in 2000.  [See: Matthew Moore,
+# 
+# Two months more daylight saving
+# 
+# Sydney Morning Herald (1999-05-26).]
+
+# From Paul Eggert (1999-09-27):
+# See the following official NSW source:
+# 
+# Daylight Saving in New South Wales.
+# 
+#
+# Narrabri Shire (NSW) council has announced it will ignore the extension of
+# daylight saving next year.  See:
+# 
+# Narrabri Council to ignore daylight saving
+#  (1999-07-22).  For now, we'll wait to see if this really happens.
+#
+# Victoria will following NSW.  See:
+# 
+# Vic to extend daylight saving
+#  (1999-07-28).
+#
+# However, South Australia rejected the DST request.  See:
+# 
+# South Australia rejects Olympics daylight savings request
+#  (1999-07-19).
+#
+# Queensland also will not observe DST for the Olympics.  See:
+# 
+# Qld says no to daylight savings for Olympics
+#  (1999-06-01), which quotes Queensland Premier Peter Beattie as saying
+# ``Look you've got to remember in my family when this came up last time
+# I voted for it, my wife voted against it and she said to me it's all very
+# well for you, you don't have to worry about getting the children out of
+# bed, getting them to school, getting them to sleep at night.
+# I've been through all this argument domestically...my wife rules.''
+#
+# Broken Hill will stick with South Australian time in 2000.  See:
+# 
+# Broken Hill to be behind the times
+#  (1999-07-21).
+
+# IATA SSIM (1998-09) says that the spring 2000 change for Australian
+# Capital Territory, New South Wales except Lord Howe Island and Broken
+# Hill, and Victoria will be August 27, presumably due to the Sydney Olympics.
+
+# From Eric Ulevik, referring to Sydney's Sun Herald (2000-08-13), page 29:
+# The Queensland Premier Peter Beattie is encouraging northern NSW
+# towns to use Queensland time.
+
+# From Paul Eggert (2007-07-23):
+# See "southeast Australia" above for 2008 and later.
+
+# Yancowinna
+
+# From John Mackin (1989-01-04):
+# `Broken Hill' means the County of Yancowinna.
+
+# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
+# # YANCOWINNA..  [ Confirmation courtesy of Broken Hill Postmaster ]
+# #					[ Dec 1990 ]
+# ...
+# # Yancowinna uses Central Standard Time, despite [its] location on the
+# # New South Wales side of the S.A. border. Most business and social dealings
+# # are with CST zones, therefore CST is legislated by local government
+# # although the switch to Summer Time occurs in line with N.S.W. There have
+# # been years when this did not apply, but the historical data is not
+# # presently available.
+# Zone	Australia/Yancowinna	9:30	 AY	%sST
+# ...
+# Rule	 AY	1971	1985	-	Oct	lastSun	2:00	1:00	D
+# Rule	 AY	1972	only	-	Feb	lastSun	3:00	0	C
+# [followed by other Rules]
+
+# Lord Howe Island
+
+# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
+# LHI...		[ Courtesy of Pauline Van Winsen ]
+#					[ Dec 1990 ]
+# Lord Howe Island is located off the New South Wales coast, and is half an
+# hour ahead of NSW time.
+
+# From James Lonergan, Secretary, Lord Howe Island Board (2000-01-27):
+# Lord Howe Island summer time in 2000/2001 will commence on the same
+# date as the rest of NSW (i.e. 2000-08-27).  For your information the
+# Lord Howe Island Board (controlling authority for the Island) is
+# seeking the community's views on various options for summer time
+# arrangements on the Island, e.g. advance clocks by 1 full hour
+# instead of only 30 minutes.  Dependant on the wishes of residents
+# the Board may approach the NSW government to change the existing
+# arrangements.  The starting date for summer time on the Island will
+# however always coincide with the rest of NSW.
+
+# From James Lonergan, Secretary, Lord Howe Island Board (2000-10-25):
+# Lord Howe Island advances clocks by 30 minutes during DST in NSW and retards
+# clocks by 30 minutes when DST finishes. Since DST was most recently
+# introduced in NSW, the "changeover" time on the Island has been 02:00 as
+# shown on clocks on LHI. I guess this means that for 30 minutes at the start
+# of DST, LHI is actually 1 hour ahead of the rest of NSW.
+
+# From Paul Eggert (2006-03-22):
+# For Lord Howe dates we use Shanks & Pottenger through 1989, and
+# Lonergan thereafter.  For times we use Lonergan.
+
+# From Paul Eggert (2007-07-23):
+# See "southeast Australia" above for 2008 and later.
+
+###############################################################################
+
+# New Zealand
+
+# From Mark Davies (1990-10-03):
+# the 1989/90 year was a trial of an extended "daylight saving" period.
+# This trial was deemed successful and the extended period adopted for
+# subsequent years (with the addition of a further week at the start).
+# source -- phone call to Ministry of Internal Affairs Head Office.
+
+# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
+# # The Country of New Zealand   (Australia's east island -) Gee they hate that!
+# #				   or is Australia the west island of N.Z.
+# #	[ courtesy of Geoff Tribble.. Auckland N.Z. ]
+# #				[ Nov 1990 ]
+# ...
+# Rule	NZ      1974    1988	-	Oct	lastSun	2:00	1:00	D
+# Rule	NZ	1989	max	-	Oct	Sun>=1	2:00	1:00	D
+# Rule	NZ      1975    1989	-	Mar	Sun>=1	3:00	0	S
+# Rule	NZ	1990	max	-	Mar	lastSun	3:00	0	S
+# ...
+# Zone	NZ			12:00	NZ		NZ%sT	# New Zealand
+# Zone	NZ-CHAT			12:45	-		NZ-CHAT # Chatham Island
+
+# From Arthur David Olson (1992-03-08):
+# The chosen rules use the Davies October 8 values for the start of DST in 1989
+# rather than the October 1 value.
+
+# From Paul Eggert (1995-12-19);
+# Shank & Pottenger report 2:00 for all autumn changes in Australia and NZ.
+# Robert Uzgalis writes that the New Zealand Daylight
+# Savings Time Order in Council dated 1990-06-18 specifies 2:00 standard
+# time on both the first Sunday in October and the third Sunday in March.
+# As with Australia, we'll assume the tradition is 2:00s, not 2:00.
+#
+# From Paul Eggert (2006-03-22):
+# The Department of Internal Affairs (DIA) maintains a brief history,
+# as does Carol Squires; see tz-link.htm for the full references.
+# Use these sources in preference to Shanks & Pottenger.
+#
+# For Chatham, IATA SSIM (1991/1999) gives the NZ rules but with
+# transitions at 2:45 local standard time; this confirms that Chatham
+# is always exactly 45 minutes ahead of Auckland.
+
+# From Colin Sharples (2007-04-30):
+# DST will now start on the last Sunday in September, and end on the
+# first Sunday in April.  The changes take effect this year, meaning
+# that DST will begin on 2007-09-30 2008-04-06.
+# http://www.dia.govt.nz/diawebsite.nsf/wpg_URL/Services-Daylight-Saving-Daylight-saving-to-be-extended
+
+###############################################################################
+
+
+# Fiji
+
+# Howse writes (p 153) that in 1879 the British governor of Fiji
+# enacted an ordinance standardizing the islands on Antipodean Time
+# instead of the American system (which was one day behind).
+
+# From Rives McDow (1998-10-08):
+# Fiji will introduce DST effective 0200 local time, 1998-11-01
+# until 0300 local time 1999-02-28.  Each year the DST period will
+# be from the first Sunday in November until the last Sunday in February.
+
+# From Paul Eggert (2000-01-08):
+# IATA SSIM (1999-09) says DST ends 0100 local time.  Go with McDow.
+
+# From the BBC World Service (1998-10-31 11:32 UTC):
+# The Fijiian government says the main reasons for the time change is to
+# improve productivity and reduce road accidents.  But correspondents say it
+# also hopes the move will boost Fiji's ability to compete with other pacific
+# islands in the effort to attract tourists to witness the dawning of the new
+# millenium.
+
+# http://www.fiji.gov.fj/press/2000_09/2000_09_13-05.shtml (2000-09-13)
+# reports that Fiji has discontinued DST.
+
+# Johnston
+
+# Johnston data is from usno1995.
+
+
+# Kiribati
+
+# From Paul Eggert (1996-01-22):
+# Today's _Wall Street Journal_ (page 1) reports that Kiribati
+# ``declared it the same day throught the country as of Jan. 1, 1995''
+# as part of the competition to be first into the 21st century.
+
+
+# Kwajalein
+
+# In comp.risks 14.87 (26 August 1993), Peter Neumann writes:
+# I wonder what happened in Kwajalein, where there was NO Friday,
+# 1993-08-20.  Thursday night at midnight Kwajalein switched sides with
+# respect to the International Date Line, to rejoin its fellow islands,
+# going from 11:59 p.m. Thursday to 12:00 m. Saturday in a blink.
+
+
+# N Mariana Is, Guam
+
+# Howse writes (p 153) ``The Spaniards, on the other hand, reached the
+# Philippines and the Ladrones from America,'' and implies that the Ladrones
+# (now called the Marianas) kept American date for quite some time.
+# For now, we assume the Ladrones switched at the same time as the Philippines;
+# see Asia/Manila.
+
+# US Public Law 106-564 (2000-12-23) made UTC+10 the official standard time,
+# under the name "Chamorro Standard Time".  There is no official abbreviation,
+# but Congressman Robert A. Underwood, author of the bill that became law,
+# wrote in a press release (2000-12-27) that he will seek the use of "ChST".
+
+
+# Micronesia
+
+# Alan Eugene Davis writes (1996-03-16),
+# ``I am certain, having lived there for the past decade, that "Truk"
+# (now properly known as Chuuk) ... is in the time zone GMT+10.''
+#
+# Shanks & Pottenger write that Truk switched from UTC+10 to UTC+11
+# on 1978-10-01; ignore this for now.
+
+# From Paul Eggert (1999-10-29):
+# The Federated States of Micronesia Visitors Board writes in
+# 
+# The Federated States of Micronesia - Visitor Information
+#  (1999-01-26)
+# that Truk and Yap are UTC+10, and Ponape and Kosrae are UTC+11.
+# We don't know when Kosrae switched from UTC+12; assume January 1 for now.
+
+
+# Midway
+
+# From Charles T O'Connor, KMTH DJ (1956),
+# quoted in the KTMH section of the Radio Heritage Collection
+#  (2002-12-31):
+# For the past two months we've been on what is known as Daylight
+# Saving Time.  This time has put us on air at 5am in the morning,
+# your time down there in New Zealand.  Starting September 2, 1956
+# we'll again go back to Standard Time.  This'll mean that we'll go to
+# air at 6am your time.
+#
+# From Paul Eggert (2003-03-23):
+# We don't know the date of that quote, but we'll guess they
+# started DST on June 3.  Possibly DST was observed other years
+# in Midway, but we have no record of it.
+
+
+# Pitcairn
+
+# From Rives McDow (1999-11-08):
+# A Proclamation was signed by the Governor of Pitcairn on the 27th March 1998
+# with regard to Pitcairn Standard Time.  The Proclamation is as follows.
+#
+#	The local time for general purposes in the Islands shall be
+#	Co-ordinated Universal time minus 8 hours and shall be known
+#	as Pitcairn Standard Time.
+#
+# ... I have also seen Pitcairn listed as UTC minus 9 hours in several
+# references, and can only assume that this was an error in interpretation
+# somehow in light of this proclamation.
+
+# From Rives McDow (1999-11-09):
+# The Proclamation regarding Pitcairn time came into effect on 27 April 1998
+# ... at midnight.
+
+# From Howie Phelps (1999-11-10), who talked to a Pitcairner via shortwave:
+# Betty Christian told me yesterday that their local time is the same as
+# Pacific Standard Time. They used to be 1/2 hour different from us here in
+# Sacramento but it was changed a couple of years ago.
+
+
+# Samoa
+
+# Howse writes (p 153, citing p 10 of the 1883-11-18 New York Herald)
+# that in 1879 the King of Samoa decided to change
+# ``the date in his kingdom from the Antipodean to the American system,
+# ordaining -- by a masterpiece of diplomatic flattery -- that
+# the Fourth of July should be celebrated twice in that year.''
+
+
+# Tonga
+
+# From Paul Eggert (1996-01-22):
+# Today's _Wall Street Journal_ (p 1) reports that ``Tonga has been plotting
+# to sneak ahead of [New Zealanders] by introducing daylight-saving time.''
+# Since Kiribati has moved the Date Line it's not clear what Tonga will do.
+
+# Don Mundell writes in the 1997-02-20 Tonga Chronicle
+# 
+# How Tonga became `The Land where Time Begins'
+# :
+
+# Until 1941 Tonga maintained a standard time 50 minutes ahead of NZST
+# 12 hours and 20 minutes ahead of GMT.  When New Zealand adjusted its
+# standard time in 1940s, Tonga had the choice of subtracting from its
+# local time to come on the same standard time as New Zealand or of
+# advancing its time to maintain the differential of 13 degrees
+# (approximately 50 minutes ahead of New Zealand time).
+#
+# Because His Majesty King Taufa'ahau Tupou IV, then Crown Prince
+# Tungi, preferred to ensure Tonga's title as the land where time
+# begins, the Legislative Assembly approved the latter change.
+#
+# But some of the older, more conservative members from the outer
+# islands objected. "If at midnight on Dec. 31, we move ahead 40
+# minutes, as your Royal Highness wishes, what becomes of the 40
+# minutes we have lost?"
+#
+# The Crown Prince, presented an unanswerable argument: "Remember that
+# on the World Day of Prayer, you would be the first people on Earth
+# to say your prayers in the morning."
+
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger say the transition was on 1968-10-01; go with Mundell.
+
+# From Eric Ulevik (1999-05-03):
+# Tonga's director of tourism, who is also secretary of the National Millenium
+# Committee, has a plan to get Tonga back in front.
+# He has proposed a one-off move to tropical daylight saving for Tonga from
+# October to March, which has won approval in principle from the Tongan
+# Government.
+
+# From Steffen Thorsen (1999-09-09):
+# * Tonga will introduce DST in November
+#
+# I was given this link by John Letts:
+# 
+# http://news.bbc.co.uk/hi/english/world/asia-pacific/newsid_424000/424764.stm
+# 
+#
+# I have not been able to find exact dates for the transition in November
+# yet. By reading this article it seems like Fiji will be 14 hours ahead
+# of UTC as well, but as far as I know Fiji will only be 13 hours ahead
+# (12 + 1 hour DST).
+
+# From Arthur David Olson (1999-09-20):
+# According to 
+# http://www.tongaonline.com/news/sept1799.html
+# :
+# "Daylight Savings Time will take effect on Oct. 2 through April 15, 2000
+# and annually thereafter from the first Saturday in October through the
+# third Saturday of April.  Under the system approved by Privy Council on
+# Sept. 10, clocks must be turned ahead one hour on the opening day and
+# set back an hour on the closing date."
+# Alas, no indication of the time of day.
+
+# From Rives McDow (1999-10-06):
+# Tonga started its Daylight Saving on Saturday morning October 2nd at 0200am.
+# Daylight Saving ends on April 16 at 0300am which is Sunday morning.
+
+# From Steffen Thorsen (2000-10-31):
+# Back in March I found a notice on the website http://www.tongaonline.com
+# that Tonga changed back to standard time one month early, on March 19
+# instead of the original reported date April 16. Unfortunately, the article
+# is no longer available on the site, and I did not make a copy of the
+# text, and I have forgotten to report it here.
+# (Original URL was: http://www.tongaonline.com/news/march162000.htm )
+
+# From Rives McDow (2000-12-01):
+# Tonga is observing DST as of 2000-11-04 and will stop on 2001-01-27.
+
+# From Sione Moala-Mafi (2001-09-20) via Rives McDow:
+# At 2:00am on the first Sunday of November, the standard time in the Kingdom
+# shall be moved forward by one hour to 3:00am.  At 2:00am on the last Sunday
+# of January the standard time in the Kingdom shall be moved backward by one
+# hour to 1:00am.
+
+# From Pulu 'Anau (2002-11-05):
+# The law was for 3 years, supposedly to get renewed.  It wasn't.
+
+
+# Wake
+
+# From Vernice Anderson, Personal Secretary to Philip Jessup,
+# US Ambassador At Large (oral history interview, 1971-02-02):
+#
+# Saturday, the 14th [of October, 1950] -- ...  The time was all the
+# more confusing at that point, because we had crossed the
+# International Date Line, thus getting two Sundays.  Furthermore, we
+# discovered that Wake Island had two hours of daylight saving time
+# making calculation of time in Washington difficult if not almost
+# impossible.
+#
+# http://www.trumanlibrary.org/wake/meeting.htm
+
+# From Paul Eggert (2003-03-23):
+# We have no other report of DST in Wake Island, so omit this info for now.
+
+###############################################################################
+
+# The International Date Line
+
+# From Gwillim Law (2000-01-03):
+#
+# The International Date Line is not defined by any international standard,
+# convention, or treaty.  Mapmakers are free to draw it as they please.
+# Reputable mapmakers will simply ensure that every point of land appears on
+# the correct side of the IDL, according to the date legally observed there.
+#
+# When Kiribati adopted a uniform date in 1995, thereby moving the Phoenix and
+# Line Islands to the west side of the IDL (or, if you prefer, moving the IDL
+# to the east side of the Phoenix and Line Islands), I suppose that most
+# mapmakers redrew the IDL following the boundary of Kiribati.  Even that line
+# has a rather arbitrary nature.  The straight-line boundaries between Pacific
+# island nations that are shown on many maps are based on an international
+# convention, but are not legally binding national borders.... The date is
+# governed by the IDL; therefore, even on the high seas, there may be some
+# places as late as fourteen hours later than UTC.  And, since the IDL is not
+# an international standard, there are some places on the high seas where the
+# correct date is ambiguous.
+
+# From Wikipedia  (2005-08-31):
+# Before 1920, all ships kept local apparent time on the high seas by setting
+# their clocks at night or at the morning sight so that, given the ship's
+# speed and direction, it would be 12 o'clock when the Sun crossed the ship's
+# meridian (12 o'clock = local apparent noon).  During 1917, at the
+# Anglo-French Conference on Time-keeping at Sea, it was recommended that all
+# ships, both military and civilian, should adopt hourly standard time zones
+# on the high seas.  Whenever a ship was within the territorial waters of any
+# nation it would use that nation's standard time.  The captain was permitted
+# to change his ship's clocks at a time of his choice following his ship's
+# entry into another zone time--he often chose midnight.  These zones were
+# adopted by all major fleets between 1920 and 1925 but not by many
+# independent merchant ships until World War II.
+
+# From Paul Eggert, using references suggested by Oscar van Vlijmen
+# (2005-03-20):
+#
+# The American Practical Navigator (2002)
+# 
+# talks only about the 180-degree meridian with respect to ships in
+# international waters; it ignores the international date line.
diff --git a/extra/zoneinfo/authors.txt b/extra/zoneinfo/authors.txt
new file mode 100644
index 0000000000..b4bd0e7b35
--- /dev/null
+++ b/extra/zoneinfo/authors.txt
@@ -0,0 +1 @@
+Doug Coleman
\ No newline at end of file
diff --git a/extra/zoneinfo/europe b/extra/zoneinfo/europe
new file mode 100644
index 0000000000..09f3e1e75c
--- /dev/null
+++ b/extra/zoneinfo/europe
@@ -0,0 +1,2647 @@
+# @(#)europe	8.20
+# 
+
+# This data is by no means authoritative; if you think you know better,
+# go ahead and edit the file (and please send any changes to
+# tz@elsie.nci.nih.gov for general use in the future).
+
+# From Paul Eggert (2006-03-22):
+# A good source for time zone historical data outside the U.S. is
+# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
+# San Diego: ACS Publications, Inc. (2003).
+#
+# Gwillim Law writes that a good source
+# for recent time zone data is the International Air Transport
+# Association's Standard Schedules Information Manual (IATA SSIM),
+# published semiannually.  Law sent in several helpful summaries
+# of the IATA's data after 1990.
+#
+# Except where otherwise noted, Shanks & Pottenger is the source for
+# entries through 1991, and IATA SSIM is the source for entries afterwards.
+#
+# Other sources occasionally used include:
+#
+#	Edward W. Whitman, World Time Differences,
+#	Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
+#	which I found in the UCLA library.
+#
+#	
+#	William Willett, The Waste of Daylight, 19th edition
+#	 (1914-03)
+#
+#	Brazil's Departamento Servico da Hora (DSH),
+#	
+#	History of Summer Time
+#	 (1998-09-21, in Portuguese)
+
+#
+# I invented the abbreviations marked `*' in the following table;
+# the rest are from earlier versions of this file, or from other sources.
+# Corrections are welcome!
+#                   std dst  2dst
+#                   LMT           Local Mean Time
+#       -4:00       AST ADT       Atlantic
+#       -3:00       WGT WGST      Western Greenland*
+#       -1:00       EGT EGST      Eastern Greenland*
+#        0:00       GMT BST  BDST Greenwich, British Summer
+#        0:00       GMT IST       Greenwich, Irish Summer
+#        0:00       WET WEST WEMT Western Europe
+#        0:19:32.13 AMT NST       Amsterdam, Netherlands Summer (1835-1937)*
+#        0:20       NET NEST      Netherlands (1937-1940)*
+#        1:00       CET CEST CEMT Central Europe
+#        1:00:14    SET           Swedish (1879-1899)*
+#        2:00       EET EEST      Eastern Europe
+#        3:00       MSK MSD       Moscow
+#
+# A reliable and entertaining source about time zones, especially in Britain,
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
+
+# From Peter Ilieve (1994-12-04),
+# The original six [EU members]: Belgium, France, (West) Germany, Italy,
+# Luxembourg, the Netherlands.
+# Plus, from 1 Jan 73: Denmark, Ireland, United Kingdom.
+# Plus, from 1 Jan 81: Greece.
+# Plus, from 1 Jan 86: Spain, Portugal.
+# Plus, from 1 Jan 95: Austria, Finland, Sweden. (Norway negotiated terms for
+# entry but in a referendum on 28 Nov 94 the people voted No by 52.2% to 47.8%
+# on a turnout of 88.6%. This was almost the same result as Norway's previous
+# referendum in 1972, they are the only country to have said No twice.
+# Referendums in the other three countries voted Yes.)
+# ...
+# Estonia ... uses EU dates but not at 01:00 GMT, they use midnight GMT.
+# I don't think they know yet what they will do from 1996 onwards.
+# ...
+# There shouldn't be any [current members who are not using EU rules].
+# A Directive has the force of law, member states are obliged to enact
+# national law to implement it. The only contentious issue was the
+# different end date for the UK and Ireland, and this was always allowed
+# in the Directive.
+
+
+###############################################################################
+
+# Britain (United Kingdom) and Ireland (Eire)
+
+# From Peter Ilieve (1994-07-06):
+#
+# On 17 Jan 1994 the Independent, a UK quality newspaper, had a piece about
+# historical vistas along the Thames in west London. There was a photo
+# and a sketch map showing some of the sightlines involved. One paragraph
+# of the text said:
+#
+# `An old stone obelisk marking a forgotten terrestrial meridian stands
+# beside the river at Kew. In the 18th century, before time and longitude
+# was standardised by the Royal Observatory in Greenwich, scholars observed
+# this stone and the movement of stars from Kew Observatory nearby. They
+# made their calculations and set the time for the Horse Guards and Parliament,
+# but now the stone is obscured by scrubwood and can only be seen by walking
+# along the towpath within a few yards of it.'
+#
+# I have a one inch to one mile map of London and my estimate of the stone's
+# position is 51 deg. 28' 30" N, 0 deg. 18' 45" W. The longitude should
+# be within about +-2". The Ordnance Survey grid reference is TQ172761.
+#
+# [This yields GMTOFF = -0:01:15 for London LMT in the 18th century.]
+
+# From Paul Eggert (1993-11-18):
+#
+# Howse writes that Britain was the first country to use standard time.
+# The railways cared most about the inconsistencies of local mean time,
+# and it was they who forced a uniform time on the country.
+# The original idea was credited to Dr. William Hyde Wollaston (1766-1828)
+# and was popularized by Abraham Follett Osler (1808-1903).
+# The first railway to adopt London time was the Great Western Railway
+# in November 1840; other railways followed suit, and by 1847 most
+# (though not all) railways used London time.  On 1847-09-22 the
+# Railway Clearing House, an industry standards body, recommended that GMT be
+# adopted at all stations as soon as the General Post Office permitted it.
+# The transition occurred on 12-01 for the L&NW, the Caledonian,
+# and presumably other railways; the January 1848 Bradshaw's lists many
+# railways as using GMT.  By 1855 the vast majority of public
+# clocks in Britain were set to GMT (though some, like the great clock
+# on Tom Tower at Christ Church, Oxford, were fitted with two minute hands,
+# one for local time and one for GMT).  The last major holdout was the legal
+# system, which stubbornly stuck to local time for many years, leading
+# to oddities like polls opening at 08:13 and closing at 16:13.
+# The legal system finally switched to GMT when the Statutes (Definition
+# of Time) Act took effect; it received the Royal Assent on 1880-08-02.
+#
+# In the tables below, we condense this complicated story into a single
+# transition date for London, namely 1847-12-01.  We don't know as much
+# about Dublin, so we use 1880-08-02, the legal transition time.
+
+# From Paul Eggert (2003-09-27):
+# Summer Time was first seriously proposed by William Willett (1857-1915),
+# a London builder and member of the Royal Astronomical Society
+# who circulated a pamphlet ``The Waste of Daylight'' (1907)
+# that proposed advancing clocks 20 minutes on each of four Sundays in April,
+# and retarding them by the same amount on four Sundays in September.
+# A bill was drafted in 1909 and introduced in Parliament several times,
+# but it met with ridicule and opposition, especially from farming interests.
+# Later editions of the pamphlet proposed one-hour summer time, and
+# it was eventually adopted as a wartime measure in 1916.
+# See: Summer Time Arrives Early, The Times (2000-05-18).
+# A monument to Willett was unveiled on 1927-05-21, in an open space in
+# a 45-acre wood near Chislehurst, Kent that was purchased by popular
+# subscription and open to the public.  On the south face of the monolith,
+# designed by G. W. Miller, is the the William Willett Memorial Sundial,
+# which is permanently set to Summer Time.
+
+# From Winston Churchill (1934-04-28):
+# It is one of the paradoxes of history that we should owe the boon of
+# summer time, which gives every year to the people of this country
+# between 160 and 170 hours more daylight leisure, to a war which
+# plunged Europe into darkness for four years, and shook the
+# foundations of civilization throughout the world.
+#	-- 
+#	"A Silent Toast to William Willett", Pictorial Weekly
+#	
+
+# From Paul Eggert (1996-09-03):
+# The OED Supplement says that the English originally said ``Daylight Saving''
+# when they were debating the adoption of DST in 1908; but by 1916 this
+# term appears only in quotes taken from DST's opponents, whereas the
+# proponents (who eventually won the argument) are quoted as using ``Summer''.
+
+# From Arthur David Olson (1989-01-19):
+#
+# A source at the British Information Office in New York avers that it's
+# known as "British" Summer Time in all parts of the United Kingdom.
+
+# Date: 4 Jan 89 08:57:25 GMT (Wed)
+# From: Jonathan Leffler
+# [British Summer Time] is fixed annually by Act of Parliament.
+# If you can predict what Parliament will do, you should be in
+# politics making a fortune, not computing.
+
+# From Chris Carrier (1996-06-14):
+# I remember reading in various wartime issues of the London Times the
+# acronym BDST for British Double Summer Time.  Look for the published
+# time of sunrise and sunset in The Times, when BDST was in effect, and
+# if you find a zone reference it will say, "All times B.D.S.T."
+
+# From Joseph S. Myers (1999-09-02):
+# ... some military cables (WO 219/4100 - this is a copy from the
+# main SHAEF archives held in the US National Archives, SHAEF/5252/8/516)
+# agree that the usage is BDST (this appears in a message dated 17 Feb 1945).
+
+# From Joseph S. Myers (2000-10-03):
+# On 18th April 1941, Sir Stephen Tallents of the BBC wrote to Sir
+# Alexander Maxwell of the Home Office asking whether there was any
+# official designation; the reply of the 21st was that there wasn't
+# but he couldn't think of anything better than the "Double British
+# Summer Time" that the BBC had been using informally.
+# http://student.cusu.cam.ac.uk/~jsm28/british-time/bbc-19410418.png
+# http://student.cusu.cam.ac.uk/~jsm28/british-time/ho-19410421.png
+
+# From Sir Alexander Maxwell in the above-mentioned letter (1941-04-21):
+# [N]o official designation has as far as I know been adopted for the time
+# which is to be introduced in May....
+# I cannot think of anything better than "Double British Summer Time"
+# which could not be said to run counter to any official description.
+
+# From Paul Eggert (2000-10-02):
+# Howse writes (p 157) `DBST' too, but `BDST' seems to have been common
+# and follows the more usual convention of putting the location name first,
+# so we use `BDST'.
+
+# Peter Ilieve (1998-04-19) described at length
+# the history of summer time legislation in the United Kingdom.
+# Since 1998 Joseph S. Myers has been updating
+# and extending this list, which can be found in
+# 
+# History of legal time in Britain
+# 
+
+# From Joseph S. Myers (1998-01-06):
+#
+# The legal time in the UK outside of summer time is definitely GMT, not UTC;
+# see Lord Tanlaw's speech
+# 
+# (Lords Hansard 11 June 1997 columns 964 to 976)
+# .
+
+# From Paul Eggert (2006-03-22):
+#
+# For lack of other data, follow Shanks & Pottenger for Eire in 1940-1948.
+#
+# Given Ilieve and Myers's data, the following claims by Shanks & Pottenger
+# are incorrect:
+#     * Wales did not switch from GMT to daylight saving time until
+#	1921 Apr 3, when they began to conform with the rest of Great Britain.
+# Actually, Wales was identical after 1880.
+#     * Eire had two transitions on 1916 Oct 1.
+# It actually just had one transition.
+#     * Northern Ireland used single daylight saving time throughout WW II.
+# Actually, it conformed to Britain.
+#     * GB-Eire changed standard time to 1 hour ahead of GMT on 1968-02-18.
+# Actually, that date saw the usual switch to summer time.
+# Standard time was not changed until 1968-10-27 (the clocks didn't change).
+#
+# Here is another incorrect claim by Shanks & Pottenger:
+#     * Jersey, Guernsey, and the Isle of Man did not switch from GMT
+#	to daylight saving time until 1921 Apr 3, when they began to
+#	conform with Great Britain.
+# S.R.&O. 1916, No. 382 and HO 45/10811/312364 (quoted above) say otherwise.
+#
+# The following claim by Shanks & Pottenger is possible though doubtful;
+# we'll ignore it for now.
+#     * Dublin's 1971-10-31 switch was at 02:00, even though London's was 03:00.
+#
+#
+# Whitman says Dublin Mean Time was -0:25:21, which is more precise than
+# Shanks & Pottenger.
+# Perhaps this was Dunsink Observatory Time, as Dunsink Observatory
+# (8 km NW of Dublin's center) seemingly was to Dublin as Greenwich was
+# to London.  For example:
+#
+#   "Timeball on the ballast office is down.  Dunsink time."
+#   -- James Joyce, Ulysses
+
+# From Joseph S. Myers (2005-01-26):
+# Irish laws are available online at www.irishstatutebook.ie.  These include
+# various relating to legal time, for example:
+#
+# ZZA13Y1923.html ZZA12Y1924.html ZZA8Y1925.html ZZSIV20PG1267.html
+#
+# ZZSI71Y1947.html ZZSI128Y1948.html ZZSI23Y1949.html ZZSI41Y1950.html
+# ZZSI27Y1951.html ZZSI73Y1952.html
+#
+# ZZSI11Y1961.html ZZSI232Y1961.html ZZSI182Y1962.html
+# ZZSI167Y1963.html ZZSI257Y1964.html ZZSI198Y1967.html
+# ZZA23Y1968.html ZZA17Y1971.html
+#
+# ZZSI67Y1981.html ZZSI212Y1982.html ZZSI45Y1986.html
+# ZZSI264Y1988.html ZZSI52Y1990.html ZZSI371Y1992.html
+# ZZSI395Y1994.html ZZSI484Y1997.html ZZSI506Y2001.html
+#
+# [These are all relative to the root, e.g., the first is
+# .]
+#
+# (These are those I found, but there could be more.  In any case these
+# should allow various updates to the comments in the europe file to cover
+# the laws applicable in Ireland.)
+#
+# (Note that the time in the Republic of Ireland since 1968 has been defined
+# in terms of standard time being GMT+1 with a period of winter time when it
+# is GMT, rather than standard time being GMT with a period of summer time
+# being GMT+1.)
+
+# From Paul Eggert (1999-03-28):
+# Clive Feather (, 1997-03-31)
+# reports that Folkestone (Cheriton) Shuttle Terminal uses Concession Time
+# (CT), equivalent to French civil time.
+# Julian Hill (, 1998-09-30) reports that
+# trains between Dollands Moor (the freight facility next door)
+# and Frethun run in CT.
+# My admittedly uninformed guess is that the terminal has two authorities,
+# the French concession operators and the British civil authorities,
+# and that the time depends on who you're talking to.
+# If, say, the British police were called to the station for some reason,
+# I would expect the official police report to use GMT/BST and not CET/CEST.
+# This is a borderline case, but for now let's stick to GMT/BST.
+
+# From an anonymous contributor (1996-06-02):
+# The law governing time in Ireland is under Statutory Instrument SI 395/94,
+# which gives force to European Union 7th Council Directive # 94/21/EC.
+# Under this directive, the Minister for Justice in Ireland makes appropriate
+# regulations. I spoke this morning with the Secretary of the Department of
+# Justice (tel +353 1 678 9711) who confirmed to me that the correct name is
+# "Irish Summer Time", abbreviated to "IST".
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+# Summer Time Act, 1916
+Rule	GB-Eire	1916	only	-	May	21	2:00s	1:00	BST
+Rule	GB-Eire	1916	only	-	Oct	 1	2:00s	0	GMT
+# S.R.&O. 1917, No. 358
+Rule	GB-Eire	1917	only	-	Apr	 8	2:00s	1:00	BST
+Rule	GB-Eire	1917	only	-	Sep	17	2:00s	0	GMT
+# S.R.&O. 1918, No. 274
+Rule	GB-Eire	1918	only	-	Mar	24	2:00s	1:00	BST
+Rule	GB-Eire	1918	only	-	Sep	30	2:00s	0	GMT
+# S.R.&O. 1919, No. 297
+Rule	GB-Eire	1919	only	-	Mar	30	2:00s	1:00	BST
+Rule	GB-Eire	1919	only	-	Sep	29	2:00s	0	GMT
+# S.R.&O. 1920, No. 458
+Rule	GB-Eire	1920	only	-	Mar	28	2:00s	1:00	BST
+# S.R.&O. 1920, No. 1844
+Rule	GB-Eire	1920	only	-	Oct	25	2:00s	0	GMT
+# S.R.&O. 1921, No. 363
+Rule	GB-Eire	1921	only	-	Apr	 3	2:00s	1:00	BST
+Rule	GB-Eire	1921	only	-	Oct	 3	2:00s	0	GMT
+# S.R.&O. 1922, No. 264
+Rule	GB-Eire	1922	only	-	Mar	26	2:00s	1:00	BST
+Rule	GB-Eire	1922	only	-	Oct	 8	2:00s	0	GMT
+# The Summer Time Act, 1922
+Rule	GB-Eire	1923	only	-	Apr	Sun>=16	2:00s	1:00	BST
+Rule	GB-Eire	1923	1924	-	Sep	Sun>=16	2:00s	0	GMT
+Rule	GB-Eire	1924	only	-	Apr	Sun>=9	2:00s	1:00	BST
+Rule	GB-Eire	1925	1926	-	Apr	Sun>=16	2:00s	1:00	BST
+# The Summer Time Act, 1925
+Rule	GB-Eire	1925	1938	-	Oct	Sun>=2	2:00s	0	GMT
+Rule	GB-Eire	1927	only	-	Apr	Sun>=9	2:00s	1:00	BST
+Rule	GB-Eire	1928	1929	-	Apr	Sun>=16	2:00s	1:00	BST
+Rule	GB-Eire	1930	only	-	Apr	Sun>=9	2:00s	1:00	BST
+Rule	GB-Eire	1931	1932	-	Apr	Sun>=16	2:00s	1:00	BST
+Rule	GB-Eire	1933	only	-	Apr	Sun>=9	2:00s	1:00	BST
+Rule	GB-Eire	1934	only	-	Apr	Sun>=16	2:00s	1:00	BST
+Rule	GB-Eire	1935	only	-	Apr	Sun>=9	2:00s	1:00	BST
+Rule	GB-Eire	1936	1937	-	Apr	Sun>=16	2:00s	1:00	BST
+Rule	GB-Eire	1938	only	-	Apr	Sun>=9	2:00s	1:00	BST
+Rule	GB-Eire	1939	only	-	Apr	Sun>=16	2:00s	1:00	BST
+# S.R.&O. 1939, No. 1379
+Rule	GB-Eire	1939	only	-	Nov	Sun>=16	2:00s	0	GMT
+# S.R.&O. 1940, No. 172 and No. 1883
+Rule	GB-Eire	1940	only	-	Feb	Sun>=23	2:00s	1:00	BST
+# S.R.&O. 1941, No. 476
+Rule	GB-Eire	1941	only	-	May	Sun>=2	1:00s	2:00	BDST
+Rule	GB-Eire	1941	1943	-	Aug	Sun>=9	1:00s	1:00	BST
+# S.R.&O. 1942, No. 506
+Rule	GB-Eire	1942	1944	-	Apr	Sun>=2	1:00s	2:00	BDST
+# S.R.&O. 1944, No. 932
+Rule	GB-Eire	1944	only	-	Sep	Sun>=16	1:00s	1:00	BST
+# S.R.&O. 1945, No. 312
+Rule	GB-Eire	1945	only	-	Apr	Mon>=2	1:00s	2:00	BDST
+Rule	GB-Eire	1945	only	-	Jul	Sun>=9	1:00s	1:00	BST
+# S.R.&O. 1945, No. 1208
+Rule	GB-Eire	1945	1946	-	Oct	Sun>=2	2:00s	0	GMT
+Rule	GB-Eire	1946	only	-	Apr	Sun>=9	2:00s	1:00	BST
+# The Summer Time Act, 1947
+Rule	GB-Eire	1947	only	-	Mar	16	2:00s	1:00	BST
+Rule	GB-Eire	1947	only	-	Apr	13	1:00s	2:00	BDST
+Rule	GB-Eire	1947	only	-	Aug	10	1:00s	1:00	BST
+Rule	GB-Eire	1947	only	-	Nov	 2	2:00s	0	GMT
+# Summer Time Order, 1948 (S.I. 1948/495)
+Rule	GB-Eire	1948	only	-	Mar	14	2:00s	1:00	BST
+Rule	GB-Eire	1948	only	-	Oct	31	2:00s	0	GMT
+# Summer Time Order, 1949 (S.I. 1949/373)
+Rule	GB-Eire	1949	only	-	Apr	 3	2:00s	1:00	BST
+Rule	GB-Eire	1949	only	-	Oct	30	2:00s	0	GMT
+# Summer Time Order, 1950 (S.I. 1950/518)
+# Summer Time Order, 1951 (S.I. 1951/430)
+# Summer Time Order, 1952 (S.I. 1952/451)
+Rule	GB-Eire	1950	1952	-	Apr	Sun>=14	2:00s	1:00	BST
+Rule	GB-Eire	1950	1952	-	Oct	Sun>=21	2:00s	0	GMT
+# revert to the rules of the Summer Time Act, 1925
+Rule	GB-Eire	1953	only	-	Apr	Sun>=16	2:00s	1:00	BST
+Rule	GB-Eire	1953	1960	-	Oct	Sun>=2	2:00s	0	GMT
+Rule	GB-Eire	1954	only	-	Apr	Sun>=9	2:00s	1:00	BST
+Rule	GB-Eire	1955	1956	-	Apr	Sun>=16	2:00s	1:00	BST
+Rule	GB-Eire	1957	only	-	Apr	Sun>=9	2:00s	1:00	BST
+Rule	GB-Eire	1958	1959	-	Apr	Sun>=16	2:00s	1:00	BST
+Rule	GB-Eire	1960	only	-	Apr	Sun>=9	2:00s	1:00	BST
+# Summer Time Order, 1961 (S.I. 1961/71)
+# Summer Time (1962) Order, 1961 (S.I. 1961/2465)
+# Summer Time Order, 1963 (S.I. 1963/81)
+Rule	GB-Eire	1961	1963	-	Mar	lastSun	2:00s	1:00	BST
+Rule	GB-Eire	1961	1968	-	Oct	Sun>=23	2:00s	0	GMT
+# Summer Time (1964) Order, 1963 (S.I. 1963/2101)
+# Summer Time Order, 1964 (S.I. 1964/1201)
+# Summer Time Order, 1967 (S.I. 1967/1148)
+Rule	GB-Eire	1964	1967	-	Mar	Sun>=19	2:00s	1:00	BST
+# Summer Time Order, 1968 (S.I. 1968/117)
+Rule	GB-Eire	1968	only	-	Feb	18	2:00s	1:00	BST
+# The British Standard Time Act, 1968
+#	(no summer time)
+# The Summer Time Act, 1972
+Rule	GB-Eire	1972	1980	-	Mar	Sun>=16	2:00s	1:00	BST
+Rule	GB-Eire	1972	1980	-	Oct	Sun>=23	2:00s	0	GMT
+# Summer Time Order, 1980 (S.I. 1980/1089)
+# Summer Time Order, 1982 (S.I. 1982/1673)
+# Summer Time Order, 1986 (S.I. 1986/223)
+# Summer Time Order, 1988 (S.I. 1988/931)
+Rule	GB-Eire	1981	1995	-	Mar	lastSun	1:00u	1:00	BST
+Rule	GB-Eire 1981	1989	-	Oct	Sun>=23	1:00u	0	GMT
+# Summer Time Order, 1989 (S.I. 1989/985)
+# Summer Time Order, 1992 (S.I. 1992/1729)
+# Summer Time Order 1994 (S.I. 1994/2798)
+Rule	GB-Eire 1990	1995	-	Oct	Sun>=22	1:00u	0	GMT
+# Summer Time Order 1997 (S.I. 1997/2982)
+# See EU for rules starting in 1996.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/London	-0:01:15 -	LMT	1847 Dec  1 0:00s
+			 0:00	GB-Eire	%s	1968 Oct 27
+			 1:00	-	BST	1971 Oct 31 2:00u
+			 0:00	GB-Eire	%s	1996
+			 0:00	EU	GMT/BST
+Link	Europe/London	Europe/Jersey
+Link	Europe/London	Europe/Guernsey
+Link	Europe/London	Europe/Isle_of_Man
+Zone	Europe/Dublin	-0:25:00 -	LMT	1880 Aug  2
+			-0:25:21 -	DMT	1916 May 21 2:00
+			-0:25:21 1:00	IST	1916 Oct  1 2:00s
+			 0:00	GB-Eire	%s	1921 Dec  6 # independence
+			 0:00	GB-Eire	GMT/IST	1940 Feb 25 2:00
+			 0:00	1:00	IST	1946 Oct  6 2:00
+			 0:00	-	GMT	1947 Mar 16 2:00
+			 0:00	1:00	IST	1947 Nov  2 2:00
+			 0:00	-	GMT	1948 Apr 18 2:00
+			 0:00	GB-Eire	GMT/IST	1968 Oct 27
+			 1:00	-	IST	1971 Oct 31 2:00u
+			 0:00	GB-Eire	GMT/IST	1996
+			 0:00	EU	GMT/IST
+
+###############################################################################
+
+# Europe
+
+# EU rules are for the European Union, previously known as the EC, EEC,
+# Common Market, etc.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	EU	1977	1980	-	Apr	Sun>=1	 1:00u	1:00	S
+Rule	EU	1977	only	-	Sep	lastSun	 1:00u	0	-
+Rule	EU	1978	only	-	Oct	 1	 1:00u	0	-
+Rule	EU	1979	1995	-	Sep	lastSun	 1:00u	0	-
+Rule	EU	1981	max	-	Mar	lastSun	 1:00u	1:00	S
+Rule	EU	1996	max	-	Oct	lastSun	 1:00u	0	-
+# The most recent directive covers the years starting in 2002.  See:
+# 
+# Directive 2000/84/EC of the European Parliament and of the Council
+# of 19 January 2001 on summer-time arrangements.
+# 
+
+# W-Eur differs from EU only in that W-Eur uses standard time.
+Rule	W-Eur	1977	1980	-	Apr	Sun>=1	 1:00s	1:00	S
+Rule	W-Eur	1977	only	-	Sep	lastSun	 1:00s	0	-
+Rule	W-Eur	1978	only	-	Oct	 1	 1:00s	0	-
+Rule	W-Eur	1979	1995	-	Sep	lastSun	 1:00s	0	-
+Rule	W-Eur	1981	max	-	Mar	lastSun	 1:00s	1:00	S
+Rule	W-Eur	1996	max	-	Oct	lastSun	 1:00s	0	-
+
+# Older C-Eur rules are for convenience in the tables.
+# From 1977 on, C-Eur differs from EU only in that C-Eur uses standard time.
+Rule	C-Eur	1916	only	-	Apr	30	23:00	1:00	S
+Rule	C-Eur	1916	only	-	Oct	 1	 1:00	0	-
+Rule	C-Eur	1917	1918	-	Apr	Mon>=15	 2:00s	1:00	S
+Rule	C-Eur	1917	1918	-	Sep	Mon>=15	 2:00s	0	-
+Rule	C-Eur	1940	only	-	Apr	 1	 2:00s	1:00	S
+Rule	C-Eur	1942	only	-	Nov	 2	 2:00s	0	-
+Rule	C-Eur	1943	only	-	Mar	29	 2:00s	1:00	S
+Rule	C-Eur	1943	only	-	Oct	 4	 2:00s	0	-
+Rule	C-Eur	1944	1945	-	Apr	Mon>=1	 2:00s	1:00	S
+# Whitman gives 1944 Oct 7; go with Shanks & Pottenger.
+Rule	C-Eur	1944	only	-	Oct	 2	 2:00s	0	-
+# From Jesper Norgaard Welen (2008-07-13):
+#
+# I found what is probably a typo of 2:00 which should perhaps be 2:00s
+# in the C-Eur rule from tz database version 2008d (this part was
+# corrected in version 2008d). The circumstancial evidence is simply the
+# tz database itself, as seen below:
+#
+# Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15  0:01
+#    0:00 France WE%sT 1945 Sep 16  3:00
+#
+# Zone Europe/Monaco 0:29:32 - LMT 1891 Mar 15
+#    0:00 France WE%sT 1945 Sep 16 3:00
+#
+# Zone Europe/Belgrade 1:22:00 - LMT 1884
+#    1:00 1:00 CEST 1945 Sep 16  2:00s
+#
+# Rule France 1945 only - Sep 16  3:00 0 -
+# Rule Belgium 1945 only - Sep 16  2:00s 0 -
+# Rule Neth 1945 only - Sep 16 2:00s 0 -
+#
+# The rule line to be changed is:
+#
+# Rule C-Eur 1945 only - Sep 16  2:00 0 -
+#
+# It seems that Paris, Monaco, Rule France, Rule Belgium all agree on
+# 2:00 standard time, e.g. 3:00 local time.  However there are no
+# countries that use C-Eur rules in September 1945, so the only items
+# affected are apparently these ficticious zones that translates acronyms
+# CET and MET:
+#
+# Zone CET  1:00 C-Eur CE%sT
+# Zone MET  1:00 C-Eur ME%sT
+#
+# It this is right then the corrected version would look like:
+#
+# Rule C-Eur 1945 only - Sep 16  2:00s 0 -
+#
+# A small step for mankind though 8-)
+Rule	C-Eur	1945	only	-	Sep	16	 2:00s	0	-
+Rule	C-Eur	1977	1980	-	Apr	Sun>=1	 2:00s	1:00	S
+Rule	C-Eur	1977	only	-	Sep	lastSun	 2:00s	0	-
+Rule	C-Eur	1978	only	-	Oct	 1	 2:00s	0	-
+Rule	C-Eur	1979	1995	-	Sep	lastSun	 2:00s	0	-
+Rule	C-Eur	1981	max	-	Mar	lastSun	 2:00s	1:00	S
+Rule	C-Eur	1996	max	-	Oct	lastSun	 2:00s	0	-
+
+# E-Eur differs from EU only in that E-Eur switches at midnight local time.
+Rule	E-Eur	1977	1980	-	Apr	Sun>=1	 0:00	1:00	S
+Rule	E-Eur	1977	only	-	Sep	lastSun	 0:00	0	-
+Rule	E-Eur	1978	only	-	Oct	 1	 0:00	0	-
+Rule	E-Eur	1979	1995	-	Sep	lastSun	 0:00	0	-
+Rule	E-Eur	1981	max	-	Mar	lastSun	 0:00	1:00	S
+Rule	E-Eur	1996	max	-	Oct	lastSun	 0:00	0	-
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Russia	1917	only	-	Jul	 1	23:00	1:00	MST	# Moscow Summer Time
+Rule	Russia	1917	only	-	Dec	28	 0:00	0	MMT	# Moscow Mean Time
+Rule	Russia	1918	only	-	May	31	22:00	2:00	MDST	# Moscow Double Summer Time
+Rule	Russia	1918	only	-	Sep	16	 1:00	1:00	MST
+Rule	Russia	1919	only	-	May	31	23:00	2:00	MDST
+Rule	Russia	1919	only	-	Jul	 1	 2:00	1:00	S
+Rule	Russia	1919	only	-	Aug	16	 0:00	0	-
+Rule	Russia	1921	only	-	Feb	14	23:00	1:00	S
+Rule	Russia	1921	only	-	Mar	20	23:00	2:00	M # Midsummer
+Rule	Russia	1921	only	-	Sep	 1	 0:00	1:00	S
+Rule	Russia	1921	only	-	Oct	 1	 0:00	0	-
+# Act No.925 of the Council of Ministers of the USSR (1980-10-24):
+Rule	Russia	1981	1984	-	Apr	 1	 0:00	1:00	S
+Rule	Russia	1981	1983	-	Oct	 1	 0:00	0	-
+# Act No.967 of the Council of Ministers of the USSR (1984-09-13), repeated in
+# Act No.227 of the Council of Ministers of the USSR (1989-03-14):
+Rule	Russia	1984	1991	-	Sep	lastSun	 2:00s	0	-
+Rule	Russia	1985	1991	-	Mar	lastSun	 2:00s	1:00	S
+#
+Rule	Russia	1992	only	-	Mar	lastSat	 23:00	1:00	S
+Rule	Russia	1992	only	-	Sep	lastSat	 23:00	0	-
+Rule	Russia	1993	max	-	Mar	lastSun	 2:00s	1:00	S
+Rule	Russia	1993	1995	-	Sep	lastSun	 2:00s	0	-
+Rule	Russia	1996	max	-	Oct	lastSun	 2:00s	0	-
+
+# These are for backward compatibility with older versions.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	WET		0:00	EU	WE%sT
+Zone	CET		1:00	C-Eur	CE%sT
+Zone	MET		1:00	C-Eur	ME%sT
+Zone	EET		2:00	EU	EE%sT
+
+# Previous editions of this database used abbreviations like MET DST
+# for Central European Summer Time, but this didn't agree with common usage.
+
+# From Markus Kuhn (1996-07-12):
+# The official German names ... are
+#
+#	Mitteleuropaeische Zeit (MEZ)         = UTC+01:00
+#	Mitteleuropaeische Sommerzeit (MESZ)  = UTC+02:00
+#
+# as defined in the German Time Act (Gesetz ueber die Zeitbestimmung (ZeitG),
+# 1978-07-25, Bundesgesetzblatt, Jahrgang 1978, Teil I, S. 1110-1111)....
+# I wrote ... to the German Federal Physical-Technical Institution
+#
+#	Physikalisch-Technische Bundesanstalt (PTB)
+#	Laboratorium 4.41 "Zeiteinheit"
+#	Postfach 3345
+#	D-38023 Braunschweig
+#	phone: +49 531 592-0
+#
+# ... I received today an answer letter from Dr. Peter Hetzel, head of the PTB
+# department for time and frequency transmission.  He explained that the
+# PTB translates MEZ and MESZ into English as
+#
+#	Central European Time (CET)         = UTC+01:00
+#	Central European Summer Time (CEST) = UTC+02:00
+
+
+# Albania
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Albania	1940	only	-	Jun	16	0:00	1:00	S
+Rule	Albania	1942	only	-	Nov	 2	3:00	0	-
+Rule	Albania	1943	only	-	Mar	29	2:00	1:00	S
+Rule	Albania	1943	only	-	Apr	10	3:00	0	-
+Rule	Albania	1974	only	-	May	 4	0:00	1:00	S
+Rule	Albania	1974	only	-	Oct	 2	0:00	0	-
+Rule	Albania	1975	only	-	May	 1	0:00	1:00	S
+Rule	Albania	1975	only	-	Oct	 2	0:00	0	-
+Rule	Albania	1976	only	-	May	 2	0:00	1:00	S
+Rule	Albania	1976	only	-	Oct	 3	0:00	0	-
+Rule	Albania	1977	only	-	May	 8	0:00	1:00	S
+Rule	Albania	1977	only	-	Oct	 2	0:00	0	-
+Rule	Albania	1978	only	-	May	 6	0:00	1:00	S
+Rule	Albania	1978	only	-	Oct	 1	0:00	0	-
+Rule	Albania	1979	only	-	May	 5	0:00	1:00	S
+Rule	Albania	1979	only	-	Sep	30	0:00	0	-
+Rule	Albania	1980	only	-	May	 3	0:00	1:00	S
+Rule	Albania	1980	only	-	Oct	 4	0:00	0	-
+Rule	Albania	1981	only	-	Apr	26	0:00	1:00	S
+Rule	Albania	1981	only	-	Sep	27	0:00	0	-
+Rule	Albania	1982	only	-	May	 2	0:00	1:00	S
+Rule	Albania	1982	only	-	Oct	 3	0:00	0	-
+Rule	Albania	1983	only	-	Apr	18	0:00	1:00	S
+Rule	Albania	1983	only	-	Oct	 1	0:00	0	-
+Rule	Albania	1984	only	-	Apr	 1	0:00	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Tirane	1:19:20 -	LMT	1914
+			1:00	-	CET	1940 Jun 16
+			1:00	Albania	CE%sT	1984 Jul
+			1:00	EU	CE%sT
+
+# Andorra
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Andorra	0:06:04 -	LMT	1901
+			0:00	-	WET	1946 Sep 30
+			1:00	-	CET	1985 Mar 31 2:00
+			1:00	EU	CE%sT
+
+# Austria
+
+# From Paul Eggert (2006-03-22): Shanks & Pottenger give 1918-06-16 and
+# 1945-11-18, but the Austrian Federal Office of Metrology and
+# Surveying (BEV) gives 1918-09-16 and for Vienna gives the "alleged"
+# date of 1945-04-12 with no time.  For the 1980-04-06 transition
+# Shanks & Pottenger give 02:00, the BEV 00:00.  Go with the BEV,
+# and guess 02:00 for 1945-04-12.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Austria	1920	only	-	Apr	 5	2:00s	1:00	S
+Rule	Austria	1920	only	-	Sep	13	2:00s	0	-
+Rule	Austria	1946	only	-	Apr	14	2:00s	1:00	S
+Rule	Austria	1946	1948	-	Oct	Sun>=1	2:00s	0	-
+Rule	Austria	1947	only	-	Apr	 6	2:00s	1:00	S
+Rule	Austria	1948	only	-	Apr	18	2:00s	1:00	S
+Rule	Austria	1980	only	-	Apr	 6	0:00	1:00	S
+Rule	Austria	1980	only	-	Sep	28	0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Vienna	1:05:20 -	LMT	1893 Apr
+			1:00	C-Eur	CE%sT	1920
+			1:00	Austria	CE%sT	1940 Apr  1 2:00s
+			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
+			1:00	1:00	CEST	1945 Apr 12 2:00s
+			1:00	-	CET	1946
+			1:00	Austria	CE%sT	1981
+			1:00	EU	CE%sT
+
+# Belarus
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Minsk	1:50:16 -	LMT	1880
+			1:50	-	MMT	1924 May 2 # Minsk Mean Time
+			2:00	-	EET	1930 Jun 21
+			3:00	-	MSK	1941 Jun 28
+			1:00	C-Eur	CE%sT	1944 Jul  3
+			3:00	Russia	MSK/MSD	1990
+			3:00	-	MSK	1991 Mar 31 2:00s
+			2:00	1:00	EEST	1991 Sep 29 2:00s
+			2:00	-	EET	1992 Mar 29 0:00s
+			2:00	1:00	EEST	1992 Sep 27 0:00s
+			2:00	Russia	EE%sT
+
+# Belgium
+#
+# From Paul Eggert (1997-07-02):
+# Entries from 1918 through 1991 are taken from:
+#	Annuaire de L'Observatoire Royal de Belgique,
+#	Avenue Circulaire, 3, B-1180 BRUXELLES, CLVIIe annee, 1991
+#	(Imprimerie HAYEZ, s.p.r.l., Rue Fin, 4, 1080 BRUXELLES, MCMXC),
+#	pp 8-9.
+# LMT before 1892 was 0:17:30, according to the official journal of Belgium:
+#	Moniteur Belge, Samedi 30 Avril 1892, N.121.
+# Thanks to Pascal Delmoitie for these references.
+# The 1918 rules are listed for completeness; they apply to unoccupied Belgium.
+# Assume Brussels switched to WET in 1918 when the armistice took effect.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Belgium	1918	only	-	Mar	 9	 0:00s	1:00	S
+Rule	Belgium	1918	1919	-	Oct	Sat>=1	23:00s	0	-
+Rule	Belgium	1919	only	-	Mar	 1	23:00s	1:00	S
+Rule	Belgium	1920	only	-	Feb	14	23:00s	1:00	S
+Rule	Belgium	1920	only	-	Oct	23	23:00s	0	-
+Rule	Belgium	1921	only	-	Mar	14	23:00s	1:00	S
+Rule	Belgium	1921	only	-	Oct	25	23:00s	0	-
+Rule	Belgium	1922	only	-	Mar	25	23:00s	1:00	S
+Rule	Belgium	1922	1927	-	Oct	Sat>=1	23:00s	0	-
+Rule	Belgium	1923	only	-	Apr	21	23:00s	1:00	S
+Rule	Belgium	1924	only	-	Mar	29	23:00s	1:00	S
+Rule	Belgium	1925	only	-	Apr	 4	23:00s	1:00	S
+# DSH writes that a royal decree of 1926-02-22 specified the Sun following 3rd
+# Sat in Apr (except if it's Easter, in which case it's one Sunday earlier),
+# to Sun following 1st Sat in Oct, and that a royal decree of 1928-09-15
+# changed the transition times to 02:00 GMT.
+Rule	Belgium	1926	only	-	Apr	17	23:00s	1:00	S
+Rule	Belgium	1927	only	-	Apr	 9	23:00s	1:00	S
+Rule	Belgium	1928	only	-	Apr	14	23:00s	1:00	S
+Rule	Belgium	1928	1938	-	Oct	Sun>=2	 2:00s	0	-
+Rule	Belgium	1929	only	-	Apr	21	 2:00s	1:00	S
+Rule	Belgium	1930	only	-	Apr	13	 2:00s	1:00	S
+Rule	Belgium	1931	only	-	Apr	19	 2:00s	1:00	S
+Rule	Belgium	1932	only	-	Apr	 3	 2:00s	1:00	S
+Rule	Belgium	1933	only	-	Mar	26	 2:00s	1:00	S
+Rule	Belgium	1934	only	-	Apr	 8	 2:00s	1:00	S
+Rule	Belgium	1935	only	-	Mar	31	 2:00s	1:00	S
+Rule	Belgium	1936	only	-	Apr	19	 2:00s	1:00	S
+Rule	Belgium	1937	only	-	Apr	 4	 2:00s	1:00	S
+Rule	Belgium	1938	only	-	Mar	27	 2:00s	1:00	S
+Rule	Belgium	1939	only	-	Apr	16	 2:00s	1:00	S
+Rule	Belgium	1939	only	-	Nov	19	 2:00s	0	-
+Rule	Belgium	1940	only	-	Feb	25	 2:00s	1:00	S
+Rule	Belgium	1944	only	-	Sep	17	 2:00s	0	-
+Rule	Belgium	1945	only	-	Apr	 2	 2:00s	1:00	S
+Rule	Belgium	1945	only	-	Sep	16	 2:00s	0	-
+Rule	Belgium	1946	only	-	May	19	 2:00s	1:00	S
+Rule	Belgium	1946	only	-	Oct	 7	 2:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Brussels	0:17:30 -	LMT	1880
+			0:17:30	-	BMT	1892 May  1 12:00 # Brussels MT
+			0:00	-	WET	1914 Nov  8
+			1:00	-	CET	1916 May  1  0:00
+			1:00	C-Eur	CE%sT	1918 Nov 11 11:00u
+			0:00	Belgium	WE%sT	1940 May 20  2:00s
+			1:00	C-Eur	CE%sT	1944 Sep  3
+			1:00	Belgium	CE%sT	1977
+			1:00	EU	CE%sT
+
+# Bosnia and Herzegovina
+# see Serbia
+
+# Bulgaria
+#
+# From Plamen Simenov via Steffen Thorsen (1999-09-09):
+# A document of Government of Bulgaria (No.94/1997) says:
+# EET --> EETDST is in 03:00 Local time in last Sunday of March ...
+# EETDST --> EET is in 04:00 Local time in last Sunday of October
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Bulg	1979	only	-	Mar	31	23:00	1:00	S
+Rule	Bulg	1979	only	-	Oct	 1	 1:00	0	-
+Rule	Bulg	1980	1982	-	Apr	Sat>=1	23:00	1:00	S
+Rule	Bulg	1980	only	-	Sep	29	 1:00	0	-
+Rule	Bulg	1981	only	-	Sep	27	 2:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Sofia	1:33:16 -	LMT	1880
+			1:56:56	-	IMT	1894 Nov 30 # Istanbul MT?
+			2:00	-	EET	1942 Nov  2  3:00
+			1:00	C-Eur	CE%sT	1945
+			1:00	-	CET	1945 Apr 2 3:00
+			2:00	-	EET	1979 Mar 31 23:00
+			2:00	Bulg	EE%sT	1982 Sep 26  2:00
+			2:00	C-Eur	EE%sT	1991
+			2:00	E-Eur	EE%sT	1997
+			2:00	EU	EE%sT
+
+# Croatia
+# see Serbia
+
+# Cyprus
+# Please see the `asia' file for Asia/Nicosia.
+
+# Czech Republic
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Czech	1945	only	-	Apr	 8	2:00s	1:00	S
+Rule	Czech	1945	only	-	Nov	18	2:00s	0	-
+Rule	Czech	1946	only	-	May	 6	2:00s	1:00	S
+Rule	Czech	1946	1949	-	Oct	Sun>=1	2:00s	0	-
+Rule	Czech	1947	only	-	Apr	20	2:00s	1:00	S
+Rule	Czech	1948	only	-	Apr	18	2:00s	1:00	S
+Rule	Czech	1949	only	-	Apr	 9	2:00s	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Prague	0:57:44 -	LMT	1850
+			0:57:44	-	PMT	1891 Oct     # Prague Mean Time
+			1:00	C-Eur	CE%sT	1944 Sep 17 2:00s
+			1:00	Czech	CE%sT	1979
+			1:00	EU	CE%sT
+
+# Denmark, Faroe Islands, and Greenland
+
+# From Jesper Norgaard Welen (2005-04-26):
+# http://www.hum.aau.dk/~poe/tid/tine/DanskTid.htm says that the law
+# [introducing standard time] was in effect from 1894-01-01....
+# The page http://www.retsinfo.dk/_GETDOCI_/ACCN/A18930008330-REGL
+# confirms this, and states that the law was put forth 1893-03-29.
+#
+# The EU treaty with effect from 1973:
+# http://www.retsinfo.dk/_GETDOCI_/ACCN/A19722110030-REGL
+#
+# This provoked a new law from 1974 to make possible summer time changes
+# in subsequenet decrees with the law
+# http://www.retsinfo.dk/_GETDOCI_/ACCN/A19740022330-REGL
+#
+# It seems however that no decree was set forward until 1980.  I have
+# not found any decree, but in another related law, the effecting DST
+# changes are stated explicitly to be from 1980-04-06 at 02:00 to
+# 1980-09-28 at 02:00.  If this is true, this differs slightly from
+# the EU rule in that DST runs to 02:00, not 03:00.  We don't know
+# when Denmark began using the EU rule correctly, but we have only
+# confirmation of the 1980-time, so I presume it was correct in 1981:
+# The law is about the management of the extra hour, concerning
+# working hours reported and effect on obligatory-rest rules (which
+# was suspended on that night):
+# http://www.retsinfo.dk/_GETDOCI_/ACCN/C19801120554-REGL
+
+# From Jesper Norgaard Welen (2005-06-11):
+# The Herning Folkeblad (1980-09-26) reported that the night between
+# Saturday and Sunday the clock is set back from three to two.
+
+# From Paul Eggert (2005-06-11):
+# Hence the "02:00" of the 1980 law refers to standard time, not
+# wall-clock time, and so the EU rules were in effect in 1980.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Denmark	1916	only	-	May	14	23:00	1:00	S
+Rule	Denmark	1916	only	-	Sep	30	23:00	0	-
+Rule	Denmark	1940	only	-	May	15	 0:00	1:00	S
+Rule	Denmark	1945	only	-	Apr	 2	 2:00s	1:00	S
+Rule	Denmark	1945	only	-	Aug	15	 2:00s	0	-
+Rule	Denmark	1946	only	-	May	 1	 2:00s	1:00	S
+Rule	Denmark	1946	only	-	Sep	 1	 2:00s	0	-
+Rule	Denmark	1947	only	-	May	 4	 2:00s	1:00	S
+Rule	Denmark	1947	only	-	Aug	10	 2:00s	0	-
+Rule	Denmark	1948	only	-	May	 9	 2:00s	1:00	S
+Rule	Denmark	1948	only	-	Aug	 8	 2:00s	0	-
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Europe/Copenhagen	 0:50:20 -	LMT	1890
+			 0:50:20 -	CMT	1894 Jan  1 # Copenhagen MT
+			 1:00	Denmark	CE%sT	1942 Nov  2 2:00s
+			 1:00	C-Eur	CE%sT	1945 Apr  2 2:00
+			 1:00	Denmark	CE%sT	1980
+			 1:00	EU	CE%sT
+Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
+			 0:00	-	WET	1981
+			 0:00	EU	WE%sT
+#
+# From Paul Eggert (2004-10-31):
+# During World War II, Germany maintained secret manned weather stations in
+# East Greenland and Franz Josef Land, but we don't know their time zones.
+# My source for this is Wilhelm Dege's book mentioned under Svalbard.
+#
+# From Paul Eggert (2006-03-22):
+# Greenland joined the EU as part of Denmark, obtained home rule on 1979-05-01,
+# and left the EU on 1985-02-01.  It therefore should have been using EU
+# rules at least through 1984.  Shanks & Pottenger say Scoresbysund and Godthab
+# used C-Eur rules after 1980, but IATA SSIM (1991/1996) says they use EU
+# rules since at least 1991.  Assume EU rules since 1980.
+
+# From Gwillin Law (2001-06-06), citing
+#  (2001-03-15),
+# and with translations corrected by Steffen Thorsen:
+#
+# Greenland has four local times, and the relation to UTC
+# is according to the following time line:
+#
+# The military zone near Thule	UTC-4
+# Standard Greenland time	UTC-3
+# Scoresbysund			UTC-1
+# Danmarkshavn			UTC
+#
+# In the military area near Thule and in Danmarkshavn DST will not be
+# introduced.
+
+# From Rives McDow (2001-11-01):
+#
+# I correspond regularly with the Dansk Polarcenter, and wrote them at
+# the time to clarify the situation in Thule.  Unfortunately, I have
+# not heard back from them regarding my recent letter.  [But I have
+# info from earlier correspondence.]
+#
+# According to the center, a very small local time zone around Thule
+# Air Base keeps the time according to UTC-4, implementing daylight
+# savings using North America rules, changing the time at 02:00 local time....
+#
+# The east coast of Greenland north of the community of Scoresbysund
+# uses UTC in the same way as in Iceland, year round, with no dst.
+# There are just a few stations on this coast, including the
+# Danmarkshavn ICAO weather station mentioned in your September 29th
+# email.  The other stations are two sledge patrol stations in
+# Mestersvig and Daneborg, the air force base at Station Nord, and the
+# DPC research station at Zackenberg.
+#
+# Scoresbysund and two small villages nearby keep time UTC-1 and use
+# the same daylight savings time period as in West Greenland (Godthab).
+#
+# The rest of Greenland, including Godthab (this area, although it
+# includes central Greenland, is known as west Greenland), keeps time
+# UTC-3, with daylight savings methods according to European rules.
+#
+# It is common procedure to use UTC 0 in the wilderness of East and
+# North Greenland, because it is mainly Icelandic aircraft operators
+# maintaining traffic in these areas.  However, the official status of
+# this area is that it sticks with Godthab time.  This area might be
+# considered a dual time zone in some respects because of this.
+
+# From Rives McDow (2001-11-19):
+# I heard back from someone stationed at Thule; the time change took place
+# there at 2:00 AM.
+
+# From Paul Eggert (2006-03-22):
+# From 1997 on the CIA map shows Danmarkshavn on GMT;
+# the 1995 map as like Godthab.
+# For lack of better info, assume they were like Godthab before 1996.
+# startkart.no says Thule does not observe DST, but this is clearly an error,
+# so go with Shanks & Pottenger for Thule transitions until this year.
+# For 2007 on assume Thule will stay in sync with US DST rules.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Thule	1991	1992	-	Mar	lastSun	2:00	1:00	D
+Rule	Thule	1991	1992	-	Sep	lastSun	2:00	0	S
+Rule	Thule	1993	2006	-	Apr	Sun>=1	2:00	1:00	D
+Rule	Thule	1993	2006	-	Oct	lastSun	2:00	0	S
+Rule	Thule	2007	max	-	Mar	Sun>=8	2:00	1:00	D
+Rule	Thule	2007	max	-	Nov	Sun>=1	2:00	0	S
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Danmarkshavn -1:14:40 -	LMT	1916 Jul 28
+			-3:00	-	WGT	1980 Apr  6 2:00
+			-3:00	EU	WG%sT	1996
+			0:00	-	GMT
+Zone America/Scoresbysund -1:27:52 -	LMT	1916 Jul 28 # Ittoqqortoormiit
+			-2:00	-	CGT	1980 Apr  6 2:00
+			-2:00	C-Eur	CG%sT	1981 Mar 29
+			-1:00	EU	EG%sT
+Zone America/Godthab	-3:26:56 -	LMT	1916 Jul 28 # Nuuk
+			-3:00	-	WGT	1980 Apr  6 2:00
+			-3:00	EU	WG%sT
+Zone America/Thule	-4:35:08 -	LMT	1916 Jul 28 # Pituffik air base
+			-4:00	Thule	A%sT
+
+# Estonia
+# From Peter Ilieve (1994-10-15):
+# A relative in Tallinn confirms the accuracy of the data for 1989 onwards
+# [through 1994] and gives the legal authority for it,
+# a regulation of the Government of Estonia, No. 111 of 1989....
+#
+# From Peter Ilieve (1996-10-28):
+# [IATA SSIM (1992/1996) claims that the Baltic republics switch at 01:00s,
+# but a relative confirms that Estonia still switches at 02:00s, writing:]
+# ``I do not [know] exactly but there are some little different
+# (confusing) rules for International Air and Railway Transport Schedules
+# conversion in Sunday connected with end of summer time in Estonia....
+# A discussion is running about the summer time efficiency and effect on
+# human physiology.  It seems that Estonia maybe will not change to
+# summer time next spring.''
+
+# From Peter Ilieve (1998-11-04), heavily edited:
+# 
+# The 1998-09-22 Estonian time law
+# 
+# refers to the Eighth Directive and cites the association agreement between
+# the EU and Estonia, ratified by the Estonian law (RT II 1995, 22--27, 120).
+#
+# I also asked [my relative] whether they use any standard abbreviation
+# for their standard and summer times. He says no, they use "suveaeg"
+# (summer time) and "talveaeg" (winter time).
+
+# From The Baltic Times (1999-09-09)
+# via Steffen Thorsen:
+# This year will mark the last time Estonia shifts to summer time,
+# a council of the ruling coalition announced Sept. 6....
+# But what this could mean for Estonia's chances of joining the European
+# Union are still unclear.  In 1994, the EU declared summer time compulsory
+# for all member states until 2001.  Brussels has yet to decide what to do
+# after that.
+
+# From Mart Oruaas (2000-01-29):
+# Regulation no. 301 (1999-10-12) obsoletes previous regulation
+# no. 206 (1998-09-22) and thus sticks Estonia to +02:00 GMT for all
+# the year round.  The regulation is effective 1999-11-01.
+
+# From Toomas Soome (2002-02-21):
+# The Estonian government has changed once again timezone politics.
+# Now we are using again EU rules.
+#
+# From Urmet Jaanes (2002-03-28):
+# The legislative reference is Government decree No. 84 on 2002-02-21.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Tallinn	1:39:00	-	LMT	1880
+			1:39:00	-	TMT	1918 Feb # Tallinn Mean Time
+			1:00	C-Eur	CE%sT	1919 Jul
+			1:39:00	-	TMT	1921 May
+			2:00	-	EET	1940 Aug  6
+			3:00	-	MSK	1941 Sep 15
+			1:00	C-Eur	CE%sT	1944 Sep 22
+			3:00	Russia	MSK/MSD	1989 Mar 26 2:00s
+			2:00	1:00	EEST	1989 Sep 24 2:00s
+			2:00	C-Eur	EE%sT	1998 Sep 22
+			2:00	EU	EE%sT	1999 Nov  1
+			2:00	-	EET	2002 Feb 21
+			2:00	EU	EE%sT
+
+# Finland
+#
+# From Hannu Strang (1994-09-25 06:03:37 UTC):
+# Well, here in Helsinki we're just changing from summer time to regular one,
+# and it's supposed to change at 4am...
+#
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger say Finland has switched at 02:00 standard time
+# since 1981.  Go with Strang instead.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Finland	1942	only	-	Apr	3	0:00	1:00	S
+Rule	Finland	1942	only	-	Oct	3	0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Helsinki	1:39:52 -	LMT	1878 May 31
+			1:39:52	-	HMT	1921 May    # Helsinki Mean Time
+			2:00	Finland	EE%sT	1981 Mar 29 2:00
+			2:00	EU	EE%sT
+
+# Aaland Is
+Link	Europe/Helsinki	Europe/Mariehamn
+
+
+# France
+
+# From Ciro Discepolo (2000-12-20):
+#
+# Henri Le Corre, Regimes Horaires pour le monde entier, Editions
+# Traditionnelles - Paris 2 books, 1993
+#
+# Gabriel, Traite de l'heure dans le monde, Guy Tredaniel editeur,
+# Paris, 1991
+#
+# Francoise Gauquelin, Problemes de l'heure resolus en astrologie,
+# Guy tredaniel, Paris 1987
+
+
+#
+# Shank & Pottenger seem to use `24:00' ambiguously; resolve it with Whitman.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	France	1916	only	-	Jun	14	23:00s	1:00	S
+Rule	France	1916	1919	-	Oct	Sun>=1	23:00s	0	-
+Rule	France	1917	only	-	Mar	24	23:00s	1:00	S
+Rule	France	1918	only	-	Mar	 9	23:00s	1:00	S
+Rule	France	1919	only	-	Mar	 1	23:00s	1:00	S
+Rule	France	1920	only	-	Feb	14	23:00s	1:00	S
+Rule	France	1920	only	-	Oct	23	23:00s	0	-
+Rule	France	1921	only	-	Mar	14	23:00s	1:00	S
+Rule	France	1921	only	-	Oct	25	23:00s	0	-
+Rule	France	1922	only	-	Mar	25	23:00s	1:00	S
+# DSH writes that a law of 1923-05-24 specified 3rd Sat in Apr at 23:00 to 1st
+# Sat in Oct at 24:00; and that in 1930, because of Easter, the transitions
+# were Apr 12 and Oct 5.  Go with Shanks & Pottenger.
+Rule	France	1922	1938	-	Oct	Sat>=1	23:00s	0	-
+Rule	France	1923	only	-	May	26	23:00s	1:00	S
+Rule	France	1924	only	-	Mar	29	23:00s	1:00	S
+Rule	France	1925	only	-	Apr	 4	23:00s	1:00	S
+Rule	France	1926	only	-	Apr	17	23:00s	1:00	S
+Rule	France	1927	only	-	Apr	 9	23:00s	1:00	S
+Rule	France	1928	only	-	Apr	14	23:00s	1:00	S
+Rule	France	1929	only	-	Apr	20	23:00s	1:00	S
+Rule	France	1930	only	-	Apr	12	23:00s	1:00	S
+Rule	France	1931	only	-	Apr	18	23:00s	1:00	S
+Rule	France	1932	only	-	Apr	 2	23:00s	1:00	S
+Rule	France	1933	only	-	Mar	25	23:00s	1:00	S
+Rule	France	1934	only	-	Apr	 7	23:00s	1:00	S
+Rule	France	1935	only	-	Mar	30	23:00s	1:00	S
+Rule	France	1936	only	-	Apr	18	23:00s	1:00	S
+Rule	France	1937	only	-	Apr	 3	23:00s	1:00	S
+Rule	France	1938	only	-	Mar	26	23:00s	1:00	S
+Rule	France	1939	only	-	Apr	15	23:00s	1:00	S
+Rule	France	1939	only	-	Nov	18	23:00s	0	-
+Rule	France	1940	only	-	Feb	25	 2:00	1:00	S
+# The French rules for 1941-1944 were not used in Paris, but Shanks & Pottenger
+# write that they were used in Monaco and in many French locations.
+# Le Corre writes that the upper limit of the free zone was Arneguy, Orthez,
+# Mont-de-Marsan, Bazas, Langon, Lamotte-Montravel, Marouil, La
+# Rochefoucault, Champagne-Mouton, La Roche-Posay, La Haye-Decartes,
+# Loches, Montrichard, Vierzon, Bourges, Moulins, Digoin,
+# Paray-le-Monial, Montceau-les-Mines, Chalons-sur-Saone, Arbois,
+# Dole, Morez, St-Claude, and Collognes (Haute-Savioe).
+Rule	France	1941	only	-	May	 5	 0:00	2:00	M # Midsummer
+# Shanks & Pottenger say this transition occurred at Oct 6 1:00,
+# but go with Denis Excoffier (1997-12-12),
+# who quotes the Ephemerides Astronomiques for 1998 from Bureau des Longitudes
+# as saying 5/10/41 22hUT.
+Rule	France	1941	only	-	Oct	 6	 0:00	1:00	S
+Rule	France	1942	only	-	Mar	 9	 0:00	2:00	M
+Rule	France	1942	only	-	Nov	 2	 3:00	1:00	S
+Rule	France	1943	only	-	Mar	29	 2:00	2:00	M
+Rule	France	1943	only	-	Oct	 4	 3:00	1:00	S
+Rule	France	1944	only	-	Apr	 3	 2:00	2:00	M
+Rule	France	1944	only	-	Oct	 8	 1:00	1:00	S
+Rule	France	1945	only	-	Apr	 2	 2:00	2:00	M
+Rule	France	1945	only	-	Sep	16	 3:00	0	-
+# Shanks & Pottenger give Mar 28 2:00 and Sep 26 3:00;
+# go with Excoffier's 28/3/76 0hUT and 25/9/76 23hUT.
+Rule	France	1976	only	-	Mar	28	 1:00	1:00	S
+Rule	France	1976	only	-	Sep	26	 1:00	0	-
+# Shanks & Pottenger give 0:09:20 for Paris Mean Time, and Whitman 0:09:05,
+# but Howse quotes the actual French legislation as saying 0:09:21.
+# Go with Howse.  Howse writes that the time in France was officially based
+# on PMT-0:09:21 until 1978-08-09, when the time base finally switched to UTC.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Paris	0:09:21 -	LMT	1891 Mar 15  0:01
+			0:09:21	-	PMT	1911 Mar 11  0:01  # Paris MT
+# Shanks & Pottenger give 1940 Jun 14 0:00; go with Excoffier and Le Corre.
+			0:00	France	WE%sT	1940 Jun 14 23:00
+# Le Corre says Paris stuck with occupied-France time after the liberation;
+# go with Shanks & Pottenger.
+			1:00	C-Eur	CE%sT	1944 Aug 25
+			0:00	France	WE%sT	1945 Sep 16  3:00
+			1:00	France	CE%sT	1977
+			1:00	EU	CE%sT
+
+# Germany
+
+# From Markus Kuhn (1998-09-29):
+# The German time zone web site by the Physikalisch-Technische
+# Bundesanstalt contains DST information back to 1916.
+# [See tz-link.htm for the URL.]
+
+# From Joerg Schilling (2002-10-23):
+# In 1945, Berlin was switched to Moscow Summer time (GMT+4) by
+# 
+# General [Nikolai] Bersarin.
+
+# From Paul Eggert (2003-03-08):
+# 
+# http://www.parlament-berlin.de/pds-fraktion.nsf/727459127c8b66ee8525662300459099/defc77cb784f180ac1256c2b0030274b/$FILE/bersarint.pdf
+# 
+# says that Bersarin issued an order to use Moscow time on May 20.
+# However, Moscow did not observe daylight saving in 1945, so
+# this was equivalent to CEMT (GMT+3), not GMT+4.
+
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Germany	1946	only	-	Apr	14	2:00s	1:00	S
+Rule	Germany	1946	only	-	Oct	 7	2:00s	0	-
+Rule	Germany	1947	1949	-	Oct	Sun>=1	2:00s	0	-
+# http://www.ptb.de/de/org/4/44/441/salt.htm says the following transition
+# occurred at 3:00 MEZ, not the 2:00 MEZ given in Shanks & Pottenger.
+# Go with the PTB.
+Rule	Germany	1947	only	-	Apr	 6	3:00s	1:00	S
+Rule	Germany	1947	only	-	May	11	2:00s	2:00	M
+Rule	Germany	1947	only	-	Jun	29	3:00	1:00	S
+Rule	Germany	1948	only	-	Apr	18	2:00s	1:00	S
+Rule	Germany	1949	only	-	Apr	10	2:00s	1:00	S
+
+Rule SovietZone	1945	only	-	May	24	2:00	2:00	M # Midsummer
+Rule SovietZone	1945	only	-	Sep	24	3:00	1:00	S
+Rule SovietZone	1945	only	-	Nov	18	2:00s	0	-
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Berlin	0:53:28 -	LMT	1893 Apr
+			1:00	C-Eur	CE%sT	1945 May 24 2:00
+			1:00 SovietZone	CE%sT	1946
+			1:00	Germany	CE%sT	1980
+			1:00	EU	CE%sT
+
+# Georgia
+# Please see the "asia" file for Asia/Tbilisi.
+# Herodotus (Histories, IV.45) says Georgia north of the Phasis (now Rioni)
+# is in Europe.  Our reference location Tbilisi is in the Asian part.
+
+# Gibraltar
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Europe/Gibraltar	-0:21:24 -	LMT	1880 Aug  2 0:00s
+			0:00	GB-Eire	%s	1957 Apr 14 2:00
+			1:00	-	CET	1982
+			1:00	EU	CE%sT
+
+# Greece
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+# Whitman gives 1932 Jul 5 - Nov 1; go with Shanks & Pottenger.
+Rule	Greece	1932	only	-	Jul	 7	0:00	1:00	S
+Rule	Greece	1932	only	-	Sep	 1	0:00	0	-
+# Whitman gives 1941 Apr 25 - ?; go with Shanks & Pottenger.
+Rule	Greece	1941	only	-	Apr	 7	0:00	1:00	S
+# Whitman gives 1942 Feb 2 - ?; go with Shanks & Pottenger.
+Rule	Greece	1942	only	-	Nov	 2	3:00	0	-
+Rule	Greece	1943	only	-	Mar	30	0:00	1:00	S
+Rule	Greece	1943	only	-	Oct	 4	0:00	0	-
+# Whitman gives 1944 Oct 3 - Oct 31; go with Shanks & Pottenger.
+Rule	Greece	1952	only	-	Jul	 1	0:00	1:00	S
+Rule	Greece	1952	only	-	Nov	 2	0:00	0	-
+Rule	Greece	1975	only	-	Apr	12	0:00s	1:00	S
+Rule	Greece	1975	only	-	Nov	26	0:00s	0	-
+Rule	Greece	1976	only	-	Apr	11	2:00s	1:00	S
+Rule	Greece	1976	only	-	Oct	10	2:00s	0	-
+Rule	Greece	1977	1978	-	Apr	Sun>=1	2:00s	1:00	S
+Rule	Greece	1977	only	-	Sep	26	2:00s	0	-
+Rule	Greece	1978	only	-	Sep	24	4:00	0	-
+Rule	Greece	1979	only	-	Apr	 1	9:00	1:00	S
+Rule	Greece	1979	only	-	Sep	29	2:00	0	-
+Rule	Greece	1980	only	-	Apr	 1	0:00	1:00	S
+Rule	Greece	1980	only	-	Sep	28	0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Athens	1:34:52 -	LMT	1895 Sep 14
+			1:34:52	-	AMT	1916 Jul 28 0:01     # Athens MT
+			2:00	Greece	EE%sT	1941 Apr 30
+			1:00	Greece	CE%sT	1944 Apr  4
+			2:00	Greece	EE%sT	1981
+			# Shanks & Pottenger say it switched to C-Eur in 1981;
+			# go with EU instead, since Greece joined it on Jan 1.
+			2:00	EU	EE%sT
+
+# Hungary
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Hungary	1918	only	-	Apr	 1	 3:00	1:00	S
+Rule	Hungary	1918	only	-	Sep	29	 3:00	0	-
+Rule	Hungary	1919	only	-	Apr	15	 3:00	1:00	S
+Rule	Hungary	1919	only	-	Sep	15	 3:00	0	-
+Rule	Hungary	1920	only	-	Apr	 5	 3:00	1:00	S
+Rule	Hungary	1920	only	-	Sep	30	 3:00	0	-
+Rule	Hungary	1945	only	-	May	 1	23:00	1:00	S
+Rule	Hungary	1945	only	-	Nov	 3	 0:00	0	-
+Rule	Hungary	1946	only	-	Mar	31	 2:00s	1:00	S
+Rule	Hungary	1946	1949	-	Oct	Sun>=1	 2:00s	0	-
+Rule	Hungary	1947	1949	-	Apr	Sun>=4	 2:00s	1:00	S
+Rule	Hungary	1950	only	-	Apr	17	 2:00s	1:00	S
+Rule	Hungary	1950	only	-	Oct	23	 2:00s	0	-
+Rule	Hungary	1954	1955	-	May	23	 0:00	1:00	S
+Rule	Hungary	1954	1955	-	Oct	 3	 0:00	0	-
+Rule	Hungary	1956	only	-	Jun	Sun>=1	 0:00	1:00	S
+Rule	Hungary	1956	only	-	Sep	lastSun	 0:00	0	-
+Rule	Hungary	1957	only	-	Jun	Sun>=1	 1:00	1:00	S
+Rule	Hungary	1957	only	-	Sep	lastSun	 3:00	0	-
+Rule	Hungary	1980	only	-	Apr	 6	 1:00	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Budapest	1:16:20 -	LMT	1890 Oct
+			1:00	C-Eur	CE%sT	1918
+			1:00	Hungary	CE%sT	1941 Apr  6  2:00
+			1:00	C-Eur	CE%sT	1945
+			1:00	Hungary	CE%sT	1980 Sep 28  2:00s
+			1:00	EU	CE%sT
+
+# Iceland
+#
+# From Adam David (1993-11-06):
+# The name of the timezone in Iceland for system / mail / news purposes is GMT.
+#
+# (1993-12-05):
+# This material is paraphrased from the 1988 edition of the University of
+# Iceland Almanak.
+#
+# From January 1st, 1908 the whole of Iceland was standardised at 1 hour
+# behind GMT. Previously, local mean solar time was used in different parts
+# of Iceland, the almanak had been based on Reykjavik mean solar time which
+# was 1 hour and 28 minutes behind GMT.
+#
+# "first day of winter" referred to [below] means the first day of the 26 weeks
+# of winter, according to the old icelandic calendar that dates back to the
+# time the norsemen first settled Iceland.  The first day of winter is always
+# Saturday, but is not dependent on the Julian or Gregorian calendars.
+#
+# (1993-12-10):
+# I have a reference from the Oxford Icelandic-English dictionary for the
+# beginning of winter, which ties it to the ecclesiastical calendar (and thus
+# to the julian/gregorian calendar) over the period in question.
+#	the winter begins on the Saturday next before St. Luke's day
+#	(old style), or on St. Luke's day, if a Saturday.
+# St. Luke's day ought to be traceable from ecclesiastical sources. "old style"
+# might be a reference to the Julian calendar as opposed to Gregorian, or it
+# might mean something else (???).
+#
+# From Paul Eggert (2006-03-22):
+# The Iceland Almanak, Shanks & Pottenger, and Whitman disagree on many points.
+# We go with the Almanak, except for one claim from Shanks & Pottenger, namely
+# that Reykavik was 21W57 from 1837 to 1908, local mean time before that.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Iceland	1917	1918	-	Feb	19	23:00	1:00	S
+Rule	Iceland	1917	only	-	Oct	21	 1:00	0	-
+Rule	Iceland	1918	only	-	Nov	16	 1:00	0	-
+Rule	Iceland	1939	only	-	Apr	29	23:00	1:00	S
+Rule	Iceland	1939	only	-	Nov	29	 2:00	0	-
+Rule	Iceland	1940	only	-	Feb	25	 2:00	1:00	S
+Rule	Iceland	1940	only	-	Nov	 3	 2:00	0	-
+Rule	Iceland	1941	only	-	Mar	 2	 1:00s	1:00	S
+Rule	Iceland	1941	only	-	Nov	 2	 1:00s	0	-
+Rule	Iceland	1942	only	-	Mar	 8	 1:00s	1:00	S
+Rule	Iceland	1942	only	-	Oct	25	 1:00s	0	-
+# 1943-1946 - first Sunday in March until first Sunday in winter
+Rule	Iceland	1943	1946	-	Mar	Sun>=1	 1:00s	1:00	S
+Rule	Iceland	1943	1948	-	Oct	Sun>=22	 1:00s	0	-
+# 1947-1967 - first Sunday in April until first Sunday in winter
+Rule	Iceland	1947	1967	-	Apr	Sun>=1	 1:00s	1:00	S
+# 1949 Oct transition delayed by 1 week
+Rule	Iceland	1949	only	-	Oct	30	 1:00s	0	-
+Rule	Iceland	1950	1966	-	Oct	Sun>=22	 1:00s	0	-
+Rule	Iceland	1967	only	-	Oct	29	 1:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Atlantic/Reykjavik	-1:27:24 -	LMT	1837
+			-1:27:48 -	RMT	1908 # Reykjavik Mean Time?
+			-1:00	Iceland	IS%sT	1968 Apr 7 1:00s
+			 0:00	-	GMT
+
+# Italy
+#
+# From Paul Eggert (2001-03-06):
+# Sicily and Sardinia each had their own time zones from 1866 to 1893,
+# called Palermo Time (+00:53:28) and Cagliari Time (+00:36:32).
+# During World War II, German-controlled Italy used German time.
+# But these events all occurred before the 1970 cutoff,
+# so record only the time in Rome.
+#
+# From Paul Eggert (2006-03-22):
+# For Italian DST we have three sources: Shanks & Pottenger, Whitman, and
+# F. Pollastri
+# 
+# Day-light Saving Time in Italy (2006-02-03)
+# 
+# (`FP' below), taken from an Italian National Electrotechnical Institute
+# publication. When the three sources disagree, guess who's right, as follows:
+#
+# year	FP	Shanks&P. (S)	Whitman (W)	Go with:
+# 1916	06-03	06-03 24:00	06-03 00:00	FP & W
+#	09-30	09-30 24:00	09-30 01:00	FP; guess 24:00s
+# 1917	04-01	03-31 24:00	03-31 00:00	FP & S
+#	09-30	09-29 24:00	09-30 01:00	FP & W
+# 1918	03-09	03-09 24:00	03-09 00:00	FP & S
+#	10-06	10-05 24:00	10-06 01:00	FP & W
+# 1919	03-01	03-01 24:00	03-01 00:00	FP & S
+#	10-04	10-04 24:00	10-04 01:00	FP; guess 24:00s
+# 1920	03-20	03-20 24:00	03-20 00:00	FP & S
+#	09-18	09-18 24:00	10-01 01:00	FP; guess 24:00s
+# 1944	04-02	04-03 02:00			S (see C-Eur)
+#	09-16	10-02 03:00			FP; guess 24:00s
+# 1945	09-14	09-16 24:00			FP; guess 24:00s
+# 1970	05-21	05-31 00:00			S
+#	09-20	09-27 00:00			S
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Italy	1916	only	-	Jun	 3	0:00s	1:00	S
+Rule	Italy	1916	only	-	Oct	 1	0:00s	0	-
+Rule	Italy	1917	only	-	Apr	 1	0:00s	1:00	S
+Rule	Italy	1917	only	-	Sep	30	0:00s	0	-
+Rule	Italy	1918	only	-	Mar	10	0:00s	1:00	S
+Rule	Italy	1918	1919	-	Oct	Sun>=1	0:00s	0	-
+Rule	Italy	1919	only	-	Mar	 2	0:00s	1:00	S
+Rule	Italy	1920	only	-	Mar	21	0:00s	1:00	S
+Rule	Italy	1920	only	-	Sep	19	0:00s	0	-
+Rule	Italy	1940	only	-	Jun	15	0:00s	1:00	S
+Rule	Italy	1944	only	-	Sep	17	0:00s	0	-
+Rule	Italy	1945	only	-	Apr	 2	2:00	1:00	S
+Rule	Italy	1945	only	-	Sep	15	0:00s	0	-
+Rule	Italy	1946	only	-	Mar	17	2:00s	1:00	S
+Rule	Italy	1946	only	-	Oct	 6	2:00s	0	-
+Rule	Italy	1947	only	-	Mar	16	0:00s	1:00	S
+Rule	Italy	1947	only	-	Oct	 5	0:00s	0	-
+Rule	Italy	1948	only	-	Feb	29	2:00s	1:00	S
+Rule	Italy	1948	only	-	Oct	 3	2:00s	0	-
+Rule	Italy	1966	1968	-	May	Sun>=22	0:00	1:00	S
+Rule	Italy	1966	1969	-	Sep	Sun>=22	0:00	0	-
+Rule	Italy	1969	only	-	Jun	 1	0:00	1:00	S
+Rule	Italy	1970	only	-	May	31	0:00	1:00	S
+Rule	Italy	1970	only	-	Sep	lastSun	0:00	0	-
+Rule	Italy	1971	1972	-	May	Sun>=22	0:00	1:00	S
+Rule	Italy	1971	only	-	Sep	lastSun	1:00	0	-
+Rule	Italy	1972	only	-	Oct	 1	0:00	0	-
+Rule	Italy	1973	only	-	Jun	 3	0:00	1:00	S
+Rule	Italy	1973	1974	-	Sep	lastSun	0:00	0	-
+Rule	Italy	1974	only	-	May	26	0:00	1:00	S
+Rule	Italy	1975	only	-	Jun	 1	0:00s	1:00	S
+Rule	Italy	1975	1977	-	Sep	lastSun	0:00s	0	-
+Rule	Italy	1976	only	-	May	30	0:00s	1:00	S
+Rule	Italy	1977	1979	-	May	Sun>=22	0:00s	1:00	S
+Rule	Italy	1978	only	-	Oct	 1	0:00s	0	-
+Rule	Italy	1979	only	-	Sep	30	0:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Rome	0:49:56 -	LMT	1866 Sep 22
+			0:49:56	-	RMT	1893 Nov  1 0:00s # Rome Mean
+			1:00	Italy	CE%sT	1942 Nov  2 2:00s
+			1:00	C-Eur	CE%sT	1944 Jul
+			1:00	Italy	CE%sT	1980
+			1:00	EU	CE%sT
+
+Link	Europe/Rome	Europe/Vatican
+Link	Europe/Rome	Europe/San_Marino
+
+# Latvia
+
+# From Liene Kanepe (1998-09-17):
+
+# I asked about this matter Scientific Secretary of the Institute of Astronomy
+# of The University of Latvia Dr. paed Mr. Ilgonis Vilks. I also searched the
+# correct data in juridical acts and I found some juridical documents about
+# changes in the counting of time in Latvia from 1981....
+#
+# Act No.35 of the Council of Ministers of Latvian SSR of 1981-01-22 ...
+# according to the Act No.925 of the Council of Ministers of USSR of 1980-10-24
+# ...: all year round the time of 2nd time zone + 1 hour, in addition turning
+# the hands of the clock 1 hour forward on 1 April at 00:00 (GMT 31 March 21:00)
+# and 1 hour backward on the 1 October at 00:00 (GMT 30 September 20:00).
+#
+# Act No.592 of the Council of Ministers of Latvian SSR of 1984-09-24 ...
+# according to the Act No.967 of the Council of Ministers of USSR of 1984-09-13
+# ...: all year round the time of 2nd time zone + 1 hour, in addition turning
+# the hands of the clock 1 hour forward on the last Sunday of March at 02:00
+# (GMT 23:00 on the previous day) and 1 hour backward on the last Sunday of
+# September at 03:00 (GMT 23:00 on the previous day).
+#
+# Act No.81 of the Council of Ministers of Latvian SSR of 1989-03-22 ...
+# according to the Act No.227 of the Council of Ministers of USSR of 1989-03-14
+# ...: since the last Sunday of March 1989 in Lithuanian SSR, Latvian SSR,
+# Estonian SSR and Kaliningrad region of Russian Federation all year round the
+# time of 2nd time zone (Moscow time minus one hour). On the territory of Latvia
+# transition to summer time is performed on the last Sunday of March at 02:00
+# (GMT 00:00), turning the hands of the clock 1 hour forward.  The end of
+# daylight saving time is performed on the last Sunday of September at 03:00
+# (GMT 00:00), turning the hands of the clock 1 hour backward. Exception is
+# 1989-03-26, when we must not turn the hands of the clock....
+#
+# The Regulations of the Cabinet of Ministers of the Republic of Latvia of
+# 1997-01-21 on transition to Summer time ... established the same order of
+# daylight savings time settings as in the States of the European Union.
+
+# From Andrei Ivanov (2000-03-06):
+# This year Latvia will not switch to Daylight Savings Time (as specified in
+# 
+# The Regulations of the Cabinet of Ministers of the Rep. of Latvia of
+# 29-Feb-2000 (#79), in Latvian for subscribers only).
+
+# 
+# From RFE/RL Newsline (2001-01-03), noted after a heads-up by Rives McDow:
+# 
+# The Latvian government on 2 January decided that the country will
+# institute daylight-saving time this spring, LETA reported.
+# Last February the three Baltic states decided not to turn back their
+# clocks one hour in the spring....
+# Minister of Economy Aigars Kalvitis noted that Latvia had too few
+# daylight hours and thus decided to comply with a draft European
+# Commission directive that provides for instituting daylight-saving
+# time in EU countries between 2002 and 2006. The Latvian government
+# urged Lithuania and Estonia to adopt a similar time policy, but it
+# appears that they will not do so....
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Latvia	1989	1996	-	Mar	lastSun	 2:00s	1:00	S
+Rule	Latvia	1989	1996	-	Sep	lastSun	 2:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Riga	1:36:24	-	LMT	1880
+			1:36:24	-	RMT	1918 Apr 15 2:00 #Riga Mean Time
+			1:36:24	1:00	LST	1918 Sep 16 3:00 #Latvian Summer
+			1:36:24	-	RMT	1919 Apr  1 2:00
+			1:36:24	1:00	LST	1919 May 22 3:00
+			1:36:24	-	RMT	1926 May 11
+			2:00	-	EET	1940 Aug  5
+			3:00	-	MSK	1941 Jul
+			1:00	C-Eur	CE%sT	1944 Oct 13
+			3:00	Russia	MSK/MSD	1989 Mar lastSun 2:00s
+			2:00	1:00	EEST	1989 Sep lastSun 2:00s
+			2:00	Latvia	EE%sT	1997 Jan 21
+			2:00	EU	EE%sT	2000 Feb 29
+			2:00	-	EET	2001 Jan  2
+			2:00	EU	EE%sT
+
+# Liechtenstein
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Vaduz	0:38:04 -	LMT	1894 Jun
+			1:00	-	CET	1981
+			1:00	EU	CE%sT
+
+# Lithuania
+
+# From Paul Eggert (1996-11-22):
+# IATA SSIM (1992/1996) says Lithuania uses W-Eur rules, but since it is
+# known to be wrong about Estonia and Latvia, assume it's wrong here too.
+
+# From Marius Gedminas (1998-08-07):
+# I would like to inform that in this year Lithuanian time zone
+# (Europe/Vilnius) was changed.
+
+# From ELTA No. 972 (2582) (1999-09-29),
+# via Steffen Thorsen:
+# Lithuania has shifted back to the second time zone (GMT plus two hours)
+# to be valid here starting from October 31,
+# as decided by the national government on Wednesday....
+# The Lithuanian government also announced plans to consider a
+# motion to give up shifting to summer time in spring, as it was
+# already done by Estonia.
+
+# From the 
+# Fact File, Lithuanian State Department of Tourism
+#  (2000-03-27): Local time is GMT+2 hours ..., no daylight saving.
+
+# From a user via Klaus Marten (2003-02-07):
+# As a candidate for membership of the European Union, Lithuania will
+# observe Summer Time in 2003, changing its clocks at the times laid
+# down in EU Directive 2000/84 of 19.I.01 (i.e. at the same times as its
+# neighbour Latvia). The text of the Lithuanian government Order of
+# 7.XI.02 to this effect can be found at
+# http://www.lrvk.lt/nut/11/n1749.htm
+
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Vilnius	1:41:16	-	LMT	1880
+			1:24:00	-	WMT	1917	    # Warsaw Mean Time
+			1:35:36	-	KMT	1919 Oct 10 # Kaunas Mean Time
+			1:00	-	CET	1920 Jul 12
+			2:00	-	EET	1920 Oct  9
+			1:00	-	CET	1940 Aug  3
+			3:00	-	MSK	1941 Jun 24
+			1:00	C-Eur	CE%sT	1944 Aug
+			3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
+			2:00	1:00	EEST	1991 Sep 29 2:00s
+			2:00	C-Eur	EE%sT	1998
+			2:00	-	EET	1998 Mar 29 1:00u
+			1:00	EU	CE%sT	1999 Oct 31 1:00u
+			2:00	-	EET	2003 Jan  1
+			2:00	EU	EE%sT
+
+# Luxembourg
+# Whitman disagrees with most of these dates in minor ways;
+# go with Shanks & Pottenger.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Lux	1916	only	-	May	14	23:00	1:00	S
+Rule	Lux	1916	only	-	Oct	 1	 1:00	0	-
+Rule	Lux	1917	only	-	Apr	28	23:00	1:00	S
+Rule	Lux	1917	only	-	Sep	17	 1:00	0	-
+Rule	Lux	1918	only	-	Apr	Mon>=15	 2:00s	1:00	S
+Rule	Lux	1918	only	-	Sep	Mon>=15	 2:00s	0	-
+Rule	Lux	1919	only	-	Mar	 1	23:00	1:00	S
+Rule	Lux	1919	only	-	Oct	 5	 3:00	0	-
+Rule	Lux	1920	only	-	Feb	14	23:00	1:00	S
+Rule	Lux	1920	only	-	Oct	24	 2:00	0	-
+Rule	Lux	1921	only	-	Mar	14	23:00	1:00	S
+Rule	Lux	1921	only	-	Oct	26	 2:00	0	-
+Rule	Lux	1922	only	-	Mar	25	23:00	1:00	S
+Rule	Lux	1922	only	-	Oct	Sun>=2	 1:00	0	-
+Rule	Lux	1923	only	-	Apr	21	23:00	1:00	S
+Rule	Lux	1923	only	-	Oct	Sun>=2	 2:00	0	-
+Rule	Lux	1924	only	-	Mar	29	23:00	1:00	S
+Rule	Lux	1924	1928	-	Oct	Sun>=2	 1:00	0	-
+Rule	Lux	1925	only	-	Apr	 5	23:00	1:00	S
+Rule	Lux	1926	only	-	Apr	17	23:00	1:00	S
+Rule	Lux	1927	only	-	Apr	 9	23:00	1:00	S
+Rule	Lux	1928	only	-	Apr	14	23:00	1:00	S
+Rule	Lux	1929	only	-	Apr	20	23:00	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Europe/Luxembourg	0:24:36 -	LMT	1904 Jun
+			1:00	Lux	CE%sT	1918 Nov 25
+			0:00	Lux	WE%sT	1929 Oct  6 2:00s
+			0:00	Belgium	WE%sT	1940 May 14 3:00
+			1:00	C-Eur	WE%sT	1944 Sep 18 3:00
+			1:00	Belgium	CE%sT	1977
+			1:00	EU	CE%sT
+
+# Macedonia
+# see Serbia
+
+# Malta
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Malta	1973	only	-	Mar	31	0:00s	1:00	S
+Rule	Malta	1973	only	-	Sep	29	0:00s	0	-
+Rule	Malta	1974	only	-	Apr	21	0:00s	1:00	S
+Rule	Malta	1974	only	-	Sep	16	0:00s	0	-
+Rule	Malta	1975	1979	-	Apr	Sun>=15	2:00	1:00	S
+Rule	Malta	1975	1980	-	Sep	Sun>=15	2:00	0	-
+Rule	Malta	1980	only	-	Mar	31	2:00	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
+			1:00	Italy	CE%sT	1942 Nov  2 2:00s
+			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
+			1:00	Italy	CE%sT	1973 Mar 31
+			1:00	Malta	CE%sT	1981
+			1:00	EU	CE%sT
+
+# Moldova
+
+# From Paul Eggert (2006-03-22):
+# A previous version of this database followed Shanks & Pottenger, who write
+# that Tiraspol switched to Moscow time on 1992-01-19 at 02:00.
+# However, this is most likely an error, as Moldova declared independence
+# on 1991-08-27 (the 1992-01-19 date is that of a Russian decree).
+# In early 1992 there was large-scale interethnic violence in the area
+# and it's possible that some Russophones continued to observe Moscow time.
+# But [two people] separately reported via
+# Jesper Norgaard that as of 2001-01-24 Tiraspol was like Chisinau.
+# The Tiraspol entry has therefore been removed for now.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Chisinau	1:55:20 -	LMT	1880
+			1:55	-	CMT	1918 Feb 15 # Chisinau MT
+			1:44:24	-	BMT	1931 Jul 24 # Bucharest MT
+			2:00	Romania	EE%sT	1940 Aug 15
+			2:00	1:00	EEST	1941 Jul 17
+			1:00	C-Eur	CE%sT	1944 Aug 24
+			3:00	Russia	MSK/MSD	1990
+			3:00	-	MSK	1990 May 6
+			2:00	-	EET	1991
+			2:00	Russia	EE%sT	1992
+			2:00	E-Eur	EE%sT	1997
+# See Romania commentary for the guessed 1997 transition to EU rules.
+			2:00	EU	EE%sT
+
+# Monaco
+# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
+# more precise 0:09:21.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Monaco	0:29:32 -	LMT	1891 Mar 15
+			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
+			0:00	France	WE%sT	1945 Sep 16 3:00
+			1:00	France	CE%sT	1977
+			1:00	EU	CE%sT
+
+# Montenegro
+# see Serbia
+
+# Netherlands
+
+# Howse writes that the Netherlands' railways used GMT between 1892 and 1940,
+# but for other purposes the Netherlands used Amsterdam mean time.
+
+# However, Robert H. van Gent writes (2001-04-01):
+# Howse's statement is only correct up to 1909. From 1909-05-01 (00:00:00
+# Amsterdam mean time) onwards, the whole of the Netherlands (including
+# the Dutch railways) was required by law to observe Amsterdam mean time
+# (19 minutes 32.13 seconds ahead of GMT). This had already been the
+# common practice (except for the railways) for many decades but it was
+# not until 1909 when the Dutch government finally defined this by law.
+# On 1937-07-01 this was changed to 20 minutes (exactly) ahead of GMT and
+# was generally known as Dutch Time ("Nederlandse Tijd").
+#
+# (2001-04-08):
+# 1892-05-01 was the date when the Dutch railways were by law required to
+# observe GMT while the remainder of the Netherlands adhered to the common
+# practice of following Amsterdam mean time.
+#
+# (2001-04-09):
+# In 1835 the authorities of the province of North Holland requested the
+# municipal authorities of the towns and cities in the province to observe
+# Amsterdam mean time but I do not know in how many cases this request was
+# actually followed.
+#
+# From 1852 onwards the Dutch telegraph offices were by law required to
+# observe Amsterdam mean time. As the time signals from the observatory of
+# Leiden were also distributed by the telegraph system, I assume that most
+# places linked up with the telegraph (and railway) system automatically
+# adopted Amsterdam mean time.
+#
+# Although the early Dutch railway companies initially observed a variety
+# of times, most of them had adopted Amsterdam mean time by 1858 but it
+# was not until 1866 when they were all required by law to observe
+# Amsterdam mean time.
+
+# The data before 1945 are taken from
+# .
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Neth	1916	only	-	May	 1	0:00	1:00	NST	# Netherlands Summer Time
+Rule	Neth	1916	only	-	Oct	 1	0:00	0	AMT	# Amsterdam Mean Time
+Rule	Neth	1917	only	-	Apr	16	2:00s	1:00	NST
+Rule	Neth	1917	only	-	Sep	17	2:00s	0	AMT
+Rule	Neth	1918	1921	-	Apr	Mon>=1	2:00s	1:00	NST
+Rule	Neth	1918	1921	-	Sep	lastMon	2:00s	0	AMT
+Rule	Neth	1922	only	-	Mar	lastSun	2:00s	1:00	NST
+Rule	Neth	1922	1936	-	Oct	Sun>=2	2:00s	0	AMT
+Rule	Neth	1923	only	-	Jun	Fri>=1	2:00s	1:00	NST
+Rule	Neth	1924	only	-	Mar	lastSun	2:00s	1:00	NST
+Rule	Neth	1925	only	-	Jun	Fri>=1	2:00s	1:00	NST
+# From 1926 through 1939 DST began 05-15, except that it was delayed by a week
+# in years when 05-15 fell in the Pentecost weekend.
+Rule	Neth	1926	1931	-	May	15	2:00s	1:00	NST
+Rule	Neth	1932	only	-	May	22	2:00s	1:00	NST
+Rule	Neth	1933	1936	-	May	15	2:00s	1:00	NST
+Rule	Neth	1937	only	-	May	22	2:00s	1:00	NST
+Rule	Neth	1937	only	-	Jul	 1	0:00	1:00	S
+Rule	Neth	1937	1939	-	Oct	Sun>=2	2:00s	0	-
+Rule	Neth	1938	1939	-	May	15	2:00s	1:00	S
+Rule	Neth	1945	only	-	Apr	 2	2:00s	1:00	S
+Rule	Neth	1945	only	-	Sep	16	2:00s	0	-
+#
+# Amsterdam Mean Time was +00:19:32.13 exactly, but the .13 is omitted
+# below because the current format requires GMTOFF to be an integer.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Europe/Amsterdam	0:19:32 -	LMT	1835
+			0:19:32	Neth	%s	1937 Jul  1
+			0:20	Neth	NE%sT	1940 May 16 0:00 # Dutch Time
+			1:00	C-Eur	CE%sT	1945 Apr  2 2:00
+			1:00	Neth	CE%sT	1977
+			1:00	EU	CE%sT
+
+# Norway
+# http://met.no/met/met_lex/q_u/sommertid.html (2004-01) agrees with Shanks &
+# Pottenger.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Norway	1916	only	-	May	22	1:00	1:00	S
+Rule	Norway	1916	only	-	Sep	30	0:00	0	-
+Rule	Norway	1945	only	-	Apr	 2	2:00s	1:00	S
+Rule	Norway	1945	only	-	Oct	 1	2:00s	0	-
+Rule	Norway	1959	1964	-	Mar	Sun>=15	2:00s	1:00	S
+Rule	Norway	1959	1965	-	Sep	Sun>=15	2:00s	0	-
+Rule	Norway	1965	only	-	Apr	25	2:00s	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
+			1:00	Norway	CE%sT	1940 Aug 10 23:00
+			1:00	C-Eur	CE%sT	1945 Apr  2  2:00
+			1:00	Norway	CE%sT	1980
+			1:00	EU	CE%sT
+
+# Svalbard & Jan Mayen
+
+# From Steffen Thorsen (2001-05-01):
+# Although I could not find it explicitly, it seems that Jan Mayen and
+# Svalbard have been using the same time as Norway at least since the
+# time they were declared as parts of Norway.  Svalbard was declared
+# as a part of Norway by law of 1925-07-17 no 11, section 4 and Jan
+# Mayen by law of 1930-02-27 no 2, section 2. (From
+# http://www.lovdata.no/all/nl-19250717-011.html and
+# http://www.lovdata.no/all/nl-19300227-002.html).  The law/regulation
+# for normal/standard time in Norway is from 1894-06-29 no 1 (came
+# into operation on 1895-01-01) and Svalbard/Jan Mayen seem to be a
+# part of this law since 1925/1930. (From
+# http://www.lovdata.no/all/nl-18940629-001.html ) I have not been
+# able to find if Jan Mayen used a different time zone (e.g. -0100)
+# before 1930. Jan Mayen has only been "inhabitated" since 1921 by
+# Norwegian meteorologists and maybe used the same time as Norway ever
+# since 1921.  Svalbard (Arctic/Longyearbyen) has been inhabited since
+# before 1895, and therefore probably changed the local time somewhere
+# between 1895 and 1925 (inclusive).
+
+# From Paul Eggert (2001-05-01):
+#
+# Actually, Jan Mayen was never occupied by Germany during World War II,
+# so it must have diverged from Oslo time during the war, as Oslo was
+# keeping Berlin time.
+#
+#  says that the meteorologists
+# burned down their station in 1940 and left the island, but returned in
+# 1941 with a small Norwegian garrison and continued operations despite
+# frequent air ttacks from Germans.  In 1943 the Americans established a
+# radiolocating station on the island, called "Atlantic City".  Possibly
+# the UTC offset changed during the war, but I think it unlikely that
+# Jan Mayen used German daylight-saving rules.
+#
+# Svalbard is more complicated, as it was raided in August 1941 by an
+# Allied party that evacuated the civilian population to England (says
+# ).  The Svalbard FAQ
+#  says that the Germans were
+# expelled on 1942-05-14.  However, small parties of Germans did return,
+# and according to Wilhelm Dege's book "War North of 80" (1954)
+# 
+# the German armed forces at the Svalbard weather station code-named
+# Haudegen did not surrender to the Allies until September 1945.
+#
+# All these events predate our cutoff date of 1970.  Unless we can
+# come up with more definitive info about the timekeeping during the
+# war years it's probably best just do do the following for now:
+Link	Europe/Oslo	Arctic/Longyearbyen
+
+# Poland
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Poland	1918	1919	-	Sep	16	2:00s	0	-
+Rule	Poland	1919	only	-	Apr	15	2:00s	1:00	S
+Rule	Poland	1944	only	-	Apr	 3	2:00s	1:00	S
+# Whitman gives 1944 Nov 30; go with Shanks & Pottenger.
+Rule	Poland	1944	only	-	Oct	 4	2:00	0	-
+# For 1944-1948 Whitman gives the previous day; go with Shanks & Pottenger.
+Rule	Poland	1945	only	-	Apr	29	0:00	1:00	S
+Rule	Poland	1945	only	-	Nov	 1	0:00	0	-
+# For 1946 on the source is Kazimierz Borkowski,
+# Torun Center for Astronomy, Dept. of Radio Astronomy, Nicolaus Copernicus U.,
+# 
+# Thanks to Przemyslaw Augustyniak (2005-05-28) for this reference.
+# He also gives these further references:
+# Mon Pol nr 13, poz 162 (1995) 
+# Druk nr 2180 (2003) 
+Rule	Poland	1946	only	-	Apr	14	0:00s	1:00	S
+Rule	Poland	1946	only	-	Oct	 7	2:00s	0	-
+Rule	Poland	1947	only	-	May	 4	2:00s	1:00	S
+Rule	Poland	1947	1949	-	Oct	Sun>=1	2:00s	0	-
+Rule	Poland	1948	only	-	Apr	18	2:00s	1:00	S
+Rule	Poland	1949	only	-	Apr	10	2:00s	1:00	S
+Rule	Poland	1957	only	-	Jun	 2	1:00s	1:00	S
+Rule	Poland	1957	1958	-	Sep	lastSun	1:00s	0	-
+Rule	Poland	1958	only	-	Mar	30	1:00s	1:00	S
+Rule	Poland	1959	only	-	May	31	1:00s	1:00	S
+Rule	Poland	1959	1961	-	Oct	Sun>=1	1:00s	0	-
+Rule	Poland	1960	only	-	Apr	 3	1:00s	1:00	S
+Rule	Poland	1961	1964	-	May	lastSun	1:00s	1:00	S
+Rule	Poland	1962	1964	-	Sep	lastSun	1:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Warsaw	1:24:00 -	LMT	1880
+			1:24:00	-	WMT	1915 Aug  5   # Warsaw Mean Time
+			1:00	C-Eur	CE%sT	1918 Sep 16 3:00
+			2:00	Poland	EE%sT	1922 Jun
+			1:00	Poland	CE%sT	1940 Jun 23 2:00
+			1:00	C-Eur	CE%sT	1944 Oct
+			1:00	Poland	CE%sT	1977
+			1:00	W-Eur	CE%sT	1988
+			1:00	EU	CE%sT
+
+# Portugal
+#
+# From Rui Pedro Salgueiro (1992-11-12):
+# Portugal has recently (September, 27) changed timezone
+# (from WET to MET or CET) to harmonize with EEC.
+#
+# Martin Bruckmann (1996-02-29) reports via Peter Ilieve
+# that Portugal is reverting to 0:00 by not moving its clocks this spring.
+# The new Prime Minister was fed up with getting up in the dark in the winter.
+#
+# From Paul Eggert (1996-11-12):
+# IATA SSIM (1991-09) reports several 1991-09 and 1992-09 transitions
+# at 02:00u, not 01:00u.  Assume that these are typos.
+# IATA SSIM (1991/1992) reports that the Azores were at -1:00.
+# IATA SSIM (1993-02) says +0:00; later issues (through 1996-09) say -1:00.
+# Guess that the Azores changed to EU rules in 1992 (since that's when Portugal
+# harmonized with the EU), and that they stayed +0:00 that winter.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+# DSH writes that despite Decree 1,469 (1915), the change to the clocks was not
+# done every year, depending on what Spain did, because of railroad schedules.
+# Go with Shanks & Pottenger.
+Rule	Port	1916	only	-	Jun	17	23:00	1:00	S
+# Whitman gives 1916 Oct 31; go with Shanks & Pottenger.
+Rule	Port	1916	only	-	Nov	 1	 1:00	0	-
+Rule	Port	1917	only	-	Feb	28	23:00s	1:00	S
+Rule	Port	1917	1921	-	Oct	14	23:00s	0	-
+Rule	Port	1918	only	-	Mar	 1	23:00s	1:00	S
+Rule	Port	1919	only	-	Feb	28	23:00s	1:00	S
+Rule	Port	1920	only	-	Feb	29	23:00s	1:00	S
+Rule	Port	1921	only	-	Feb	28	23:00s	1:00	S
+Rule	Port	1924	only	-	Apr	16	23:00s	1:00	S
+Rule	Port	1924	only	-	Oct	14	23:00s	0	-
+Rule	Port	1926	only	-	Apr	17	23:00s	1:00	S
+Rule	Port	1926	1929	-	Oct	Sat>=1	23:00s	0	-
+Rule	Port	1927	only	-	Apr	 9	23:00s	1:00	S
+Rule	Port	1928	only	-	Apr	14	23:00s	1:00	S
+Rule	Port	1929	only	-	Apr	20	23:00s	1:00	S
+Rule	Port	1931	only	-	Apr	18	23:00s	1:00	S
+# Whitman gives 1931 Oct 8; go with Shanks & Pottenger.
+Rule	Port	1931	1932	-	Oct	Sat>=1	23:00s	0	-
+Rule	Port	1932	only	-	Apr	 2	23:00s	1:00	S
+Rule	Port	1934	only	-	Apr	 7	23:00s	1:00	S
+# Whitman gives 1934 Oct 5; go with Shanks & Pottenger.
+Rule	Port	1934	1938	-	Oct	Sat>=1	23:00s	0	-
+# Shanks & Pottenger give 1935 Apr 30; go with Whitman.
+Rule	Port	1935	only	-	Mar	30	23:00s	1:00	S
+Rule	Port	1936	only	-	Apr	18	23:00s	1:00	S
+# Whitman gives 1937 Apr 2; go with Shanks & Pottenger.
+Rule	Port	1937	only	-	Apr	 3	23:00s	1:00	S
+Rule	Port	1938	only	-	Mar	26	23:00s	1:00	S
+Rule	Port	1939	only	-	Apr	15	23:00s	1:00	S
+# Whitman gives 1939 Oct 7; go with Shanks & Pottenger.
+Rule	Port	1939	only	-	Nov	18	23:00s	0	-
+Rule	Port	1940	only	-	Feb	24	23:00s	1:00	S
+# Shanks & Pottenger give 1940 Oct 7; go with Whitman.
+Rule	Port	1940	1941	-	Oct	 5	23:00s	0	-
+Rule	Port	1941	only	-	Apr	 5	23:00s	1:00	S
+Rule	Port	1942	1945	-	Mar	Sat>=8	23:00s	1:00	S
+Rule	Port	1942	only	-	Apr	25	22:00s	2:00	M # Midsummer
+Rule	Port	1942	only	-	Aug	15	22:00s	1:00	S
+Rule	Port	1942	1945	-	Oct	Sat>=24	23:00s	0	-
+Rule	Port	1943	only	-	Apr	17	22:00s	2:00	M
+Rule	Port	1943	1945	-	Aug	Sat>=25	22:00s	1:00	S
+Rule	Port	1944	1945	-	Apr	Sat>=21	22:00s	2:00	M
+Rule	Port	1946	only	-	Apr	Sat>=1	23:00s	1:00	S
+Rule	Port	1946	only	-	Oct	Sat>=1	23:00s	0	-
+Rule	Port	1947	1949	-	Apr	Sun>=1	 2:00s	1:00	S
+Rule	Port	1947	1949	-	Oct	Sun>=1	 2:00s	0	-
+# Shanks & Pottenger say DST was observed in 1950; go with Whitman.
+# Whitman gives Oct lastSun for 1952 on; go with Shanks & Pottenger.
+Rule	Port	1951	1965	-	Apr	Sun>=1	 2:00s	1:00	S
+Rule	Port	1951	1965	-	Oct	Sun>=1	 2:00s	0	-
+Rule	Port	1977	only	-	Mar	27	 0:00s	1:00	S
+Rule	Port	1977	only	-	Sep	25	 0:00s	0	-
+Rule	Port	1978	1979	-	Apr	Sun>=1	 0:00s	1:00	S
+Rule	Port	1978	only	-	Oct	 1	 0:00s	0	-
+Rule	Port	1979	1982	-	Sep	lastSun	 1:00s	0	-
+Rule	Port	1980	only	-	Mar	lastSun	 0:00s	1:00	S
+Rule	Port	1981	1982	-	Mar	lastSun	 1:00s	1:00	S
+Rule	Port	1983	only	-	Mar	lastSun	 2:00s	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+# Shanks & Pottenger say the transition from LMT to WET occurred 1911-05-24;
+# Willett says 1912-01-01.  Go with Willett.
+Zone	Europe/Lisbon	-0:36:32 -	LMT	1884
+			-0:36:32 -	LMT	1912 Jan  1  # Lisbon Mean Time
+			 0:00	Port	WE%sT	1966 Apr  3 2:00
+			 1:00	-	CET	1976 Sep 26 1:00
+			 0:00	Port	WE%sT	1983 Sep 25 1:00s
+			 0:00	W-Eur	WE%sT	1992 Sep 27 1:00s
+			 1:00	EU	CE%sT	1996 Mar 31 1:00u
+			 0:00	EU	WE%sT
+Zone Atlantic/Azores	-1:42:40 -	LMT	1884		# Ponta Delgada
+			-1:54:32 -	HMT	1911 May 24  # Horta Mean Time
+			-2:00	Port	AZO%sT	1966 Apr  3 2:00 # Azores Time
+			-1:00	Port	AZO%sT	1983 Sep 25 1:00s
+			-1:00	W-Eur	AZO%sT	1992 Sep 27 1:00s
+			 0:00	EU	WE%sT	1993 Mar 28 1:00u
+			-1:00	EU	AZO%sT
+Zone Atlantic/Madeira	-1:07:36 -	LMT	1884		# Funchal
+			-1:07:36 -	FMT	1911 May 24  # Funchal Mean Time
+			-1:00	Port	MAD%sT	1966 Apr  3 2:00 # Madeira Time
+			 0:00	Port	WE%sT	1983 Sep 25 1:00s
+			 0:00	EU	WE%sT
+
+# Romania
+#
+# From Paul Eggert (1999-10-07):
+# 
+# Nine O'clock (1998-10-23) reports that the switch occurred at
+# 04:00 local time in fall 1998.  For lack of better info,
+# assume that Romania and Moldova switched to EU rules in 1997,
+# the same year as Bulgaria.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Romania	1932	only	-	May	21	 0:00s	1:00	S
+Rule	Romania	1932	1939	-	Oct	Sun>=1	 0:00s	0	-
+Rule	Romania	1933	1939	-	Apr	Sun>=2	 0:00s	1:00	S
+Rule	Romania	1979	only	-	May	27	 0:00	1:00	S
+Rule	Romania	1979	only	-	Sep	lastSun	 0:00	0	-
+Rule	Romania	1980	only	-	Apr	 5	23:00	1:00	S
+Rule	Romania	1980	only	-	Sep	lastSun	 1:00	0	-
+Rule	Romania	1991	1993	-	Mar	lastSun	 0:00s	1:00	S
+Rule	Romania	1991	1993	-	Sep	lastSun	 0:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
+			1:44:24	-	BMT	1931 Jul 24	# Bucharest MT
+			2:00	Romania	EE%sT	1981 Mar 29 2:00s
+			2:00	C-Eur	EE%sT	1991
+			2:00	Romania	EE%sT	1994
+			2:00	E-Eur	EE%sT	1997
+			2:00	EU	EE%sT
+
+# Russia
+
+# From Paul Eggert (2006-03-22):
+# Except for Moscow after 1919-07-01, I invented the time zone abbreviations.
+# Moscow time zone abbreviations after 1919-07-01, and Moscow rules after 1991,
+# are from Andrey A. Chernov.  The rest is from Shanks & Pottenger,
+# except we follow Chernov's report that 1992 DST transitions were Sat
+# 23:00, not Sun 02:00s.
+#
+# From Stanislaw A. Kuzikowski (1994-06-29):
+# But now it is some months since Novosibirsk is 3 hours ahead of Moscow!
+# I do not know why they have decided to make this change;
+# as far as I remember it was done exactly during winter->summer switching
+# so we (Novosibirsk) simply did not switch.
+#
+# From Andrey A. Chernov (1996-10-04):
+# `MSK' and `MSD' were born and used initially on Moscow computers with
+# UNIX-like OSes by several developer groups (e.g. Demos group, Kiae group)....
+# The next step was the UUCP network, the Relcom predecessor
+# (used mainly for mail), and MSK/MSD was actively used there.
+#
+# From Chris Carrier (1996-10-30):
+# According to a friend of mine who rode the Trans-Siberian Railroad from
+# Moscow to Irkutsk in 1995, public air and rail transport in Russia ...
+# still follows Moscow time, no matter where in Russia it is located.
+#
+# For Grozny, Chechnya, we have the following story from
+# John Daniszewski, "Scavengers in the Rubble", Los Angeles Times (2001-02-07):
+# News--often false--is spread by word of mouth.  A rumor that it was
+# time to move the clocks back put this whole city out of sync with
+# the rest of Russia for two weeks--even soldiers stationed here began
+# enforcing curfew at the wrong time.
+#
+# From Gwillim Law (2001-06-05):
+# There's considerable evidence that Sakhalin Island used to be in
+# UTC+11, and has changed to UTC+10, in this decade.  I start with the
+# SSIM, which listed Yuzhno-Sakhalinsk in zone RU10 along with Magadan
+# until February 1997, and then in RU9 with Khabarovsk and Vladivostok
+# since September 1997....  Although the Kuril Islands are
+# administratively part of Sakhalin oblast', they appear to have
+# remained on UTC+11 along with Magadan.
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+#
+# Kaliningradskaya oblast'.
+Zone Europe/Kaliningrad	 1:22:00 -	LMT	1893 Apr
+			 1:00	C-Eur	CE%sT	1945
+			 2:00	Poland	CE%sT	1946
+			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
+			 2:00	Russia	EE%sT
+#
+# From Oscar van Vlijmen (2001-08-25): [This region consists of]
+# Respublika Adygeya, Arkhangel'skaya oblast',
+# Belgorodskaya oblast', Bryanskaya oblast', Vladimirskaya oblast',
+# Vologodskaya oblast', Voronezhskaya oblast',
+# Respublika Dagestan, Ivanovskaya oblast', Respublika Ingushetiya,
+# Kabarbino-Balkarskaya Respublika, Respublika Kalmykiya,
+# Kalyzhskaya oblast', Respublika Karachaevo-Cherkessiya,
+# Respublika Kareliya, Respublika Komi,
+# Kostromskaya oblast', Krasnodarskij kraj, Kurskaya oblast',
+# Leningradskaya oblast', Lipetskaya oblast', Respublika Marij El,
+# Respublika Mordoviya, Moskva, Moskovskaya oblast',
+# Murmanskaya oblast', Nenetskij avtonomnyj okrug,
+# Nizhegorodskaya oblast', Novgorodskaya oblast', Orlovskaya oblast',
+# Penzenskaya oblast', Pskovskaya oblast', Rostovskaya oblast',
+# Ryazanskaya oblast', Sankt-Peterburg,
+# Respublika Severnaya Osetiya, Smolenskaya oblast',
+# Stavropol'skij kraj, Tambovskaya oblast', Respublika Tatarstan,
+# Tverskaya oblast', Tyl'skaya oblast', Ul'yanovskaya oblast',
+# Chechenskaya Respublika, Chuvashskaya oblast',
+# Yaroslavskaya oblast'
+Zone Europe/Moscow	 2:30:20 -	LMT	1880
+			 2:30	-	MMT	1916 Jul  3 # Moscow Mean Time
+			 2:30:48 Russia	%s	1919 Jul  1 2:00
+			 3:00	Russia	MSK/MSD	1922 Oct
+			 2:00	-	EET	1930 Jun 21
+			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
+			 2:00	Russia	EE%sT	1992 Jan 19 2:00s
+			 3:00	Russia	MSK/MSD
+#
+# Astrakhanskaya oblast', Kirovskaya oblast', Saratovskaya oblast',
+# Volgogradskaya oblast'.  Shanks & Pottenger say Kirov is still at +0400
+# but Wikipedia (2006-05-09) says +0300.  Perhaps it switched after the
+# others?  But we have no data.
+Zone Europe/Volgograd	 2:57:40 -	LMT	1920 Jan  3
+			 3:00	-	TSAT	1925 Apr  6 # Tsaritsyn Time
+			 3:00	-	STAT	1930 Jun 21 # Stalingrad Time
+			 4:00	-	STAT	1961 Nov 11
+			 4:00	Russia	VOL%sT	1989 Mar 26 2:00s # Volgograd T
+			 3:00	Russia	VOL%sT	1991 Mar 31 2:00s
+			 4:00	-	VOLT	1992 Mar 29 2:00s
+			 3:00	Russia	VOL%sT
+#
+# From Oscar van Vlijmen (2001-08-25): [This region consists of]
+# Samarskaya oblast', Udmyrtskaya respublika
+Zone Europe/Samara	 3:20:36 -	LMT	1919 Jul  1 2:00
+			 3:00	-	SAMT	1930 Jun 21
+			 4:00	-	SAMT	1935 Jan 27
+			 4:00	Russia	KUY%sT	1989 Mar 26 2:00s # Kuybyshev
+			 3:00	Russia	KUY%sT	1991 Mar 31 2:00s
+			 2:00	Russia	KUY%sT	1991 Sep 29 2:00s
+			 3:00	-	KUYT	1991 Oct 20 3:00
+			 4:00	Russia	SAM%sT	# Samara Time
+#
+# From Oscar van Vlijmen (2001-08-25): [This region consists of]
+# Respublika Bashkortostan, Komi-Permyatskij avtonomnyj okrug,
+# Kurganskaya oblast', Orenburgskaya oblast', Permskaya oblast',
+# Sverdlovskaya oblast', Tyumenskaya oblast',
+# Khanty-Manskijskij avtonomnyj okrug, Chelyabinskaya oblast',
+# Yamalo-Nenetskij avtonomnyj okrug.
+Zone Asia/Yekaterinburg	 4:02:24 -	LMT	1919 Jul 15 4:00
+			 4:00	-	SVET	1930 Jun 21 # Sverdlovsk Time
+			 5:00	Russia	SVE%sT	1991 Mar 31 2:00s
+			 4:00	Russia	SVE%sT	1992 Jan 19 2:00s
+			 5:00	Russia	YEK%sT	# Yekaterinburg Time
+#
+# From Oscar van Vlijmen (2001-08-25): [This region consists of]
+# Respublika Altaj, Altajskij kraj, Omskaya oblast'.
+Zone Asia/Omsk		 4:53:36 -	LMT	1919 Nov 14
+			 5:00	-	OMST	1930 Jun 21 # Omsk TIme
+			 6:00	Russia	OMS%sT	1991 Mar 31 2:00s
+			 5:00	Russia	OMS%sT	1992 Jan 19 2:00s
+			 6:00	Russia	OMS%sT
+#
+# From Paul Eggert (2006-08-19): I'm guessing about Tomsk here; it's
+# not clear when it switched from +7 to +6.
+# Novosibirskaya oblast', Tomskaya oblast'.
+Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
+			 6:00	-	NOVT	1930 Jun 21 # Novosibirsk Time
+			 7:00	Russia	NOV%sT	1991 Mar 31 2:00s
+			 6:00	Russia	NOV%sT	1992 Jan 19 2:00s
+			 7:00	Russia	NOV%sT	1993 May 23 # say Shanks & P.
+			 6:00	Russia	NOV%sT
+#
+# From Oscar van Vlijmen (2001-08-25): [This region consists of]
+# Kemerovskaya oblast', Krasnoyarskij kraj,
+# Tajmyrskij (Dolgano-Nenetskij) avtonomnyj okrug,
+# Respublika Tuva, Respublika Khakasiya, Evenkijskij avtonomnyj okrug.
+Zone Asia/Krasnoyarsk	 6:11:20 -	LMT	1920 Jan  6
+			 6:00	-	KRAT	1930 Jun 21 # Krasnoyarsk Time
+			 7:00	Russia	KRA%sT	1991 Mar 31 2:00s
+			 6:00	Russia	KRA%sT	1992 Jan 19 2:00s
+			 7:00	Russia	KRA%sT
+#
+# From Oscar van Vlijmen (2001-08-25): [This region consists of]
+# Respublika Buryatiya, Irkutskaya oblast',
+# Ust'-Ordynskij Buryatskij avtonomnyj okrug.
+Zone Asia/Irkutsk	 6:57:20 -	LMT	1880
+			 6:57:20 -	IMT	1920 Jan 25 # Irkutsk Mean Time
+			 7:00	-	IRKT	1930 Jun 21 # Irkutsk Time
+			 8:00	Russia	IRK%sT	1991 Mar 31 2:00s
+			 7:00	Russia	IRK%sT	1992 Jan 19 2:00s
+			 8:00	Russia	IRK%sT
+#
+# From Oscar van Vlijmen (2003-10-18): [This region consists of]
+# Aginskij Buryatskij avtonomnyj okrug, Amurskaya oblast',
+# [parts of] Respublika Sakha (Yakutiya), Chitinskaya oblast'.
+# The Sakha districts are: Aldanskij, Amginskij, Anabarskij,
+# Bulunskij, Verkhnekolymskij, Verkhnevilyujskij, Vilyujskij, Gornyj,
+# Zhiganskij, Kobyajskij, Lenskij, Megino-Kangalasskij, Mirninskij,
+# Namskij, Nyurbinskij, Olenekskij, Olekminskij, Srednekolymskij,
+# Suntarskij, Tattinskij, Ust'-Aldanskij, Khangalasskij,
+# Churapchinskij, Eveno-Bytantajskij.
+Zone Asia/Yakutsk	 8:38:40 -	LMT	1919 Dec 15
+			 8:00	-	YAKT	1930 Jun 21 # Yakutsk Time
+			 9:00	Russia	YAK%sT	1991 Mar 31 2:00s
+			 8:00	Russia	YAK%sT	1992 Jan 19 2:00s
+			 9:00	Russia	YAK%sT
+#
+# From Oscar van Vlijmen (2003-10-18): [This region consists of]
+# Evrejskaya avtonomnaya oblast', Khabarovskij kraj, Primorskij kraj,
+# [parts of] Respublika Sakha (Yakutiya).
+# The Sakha districts are: Verkhoyanskij, Tomponskij, Ust'-Majskij,
+# Ust'-Yanskij.
+Zone Asia/Vladivostok	 8:47:44 -	LMT	1922 Nov 15
+			 9:00	-	VLAT	1930 Jun 21 # Vladivostok Time
+			10:00	Russia	VLA%sT	1991 Mar 31 2:00s
+			 9:00	Russia	VLA%sST	1992 Jan 19 2:00s
+			10:00	Russia	VLA%sT
+#
+# Sakhalinskaya oblast'.
+# The Zone name should be Yuzhno-Sakhalinsk, but that's too long.
+Zone Asia/Sakhalin	 9:30:48 -	LMT	1905 Aug 23
+			 9:00	-	CJT	1938
+			 9:00	-	JST	1945 Aug 25
+			11:00	Russia	SAK%sT	1991 Mar 31 2:00s # Sakhalin T.
+			10:00	Russia	SAK%sT	1992 Jan 19 2:00s
+			11:00	Russia	SAK%sT	1997 Mar lastSun 2:00s
+			10:00	Russia	SAK%sT
+#
+# From Oscar van Vlijmen (2003-10-18): [This region consists of]
+# Magadanskaya oblast', Respublika Sakha (Yakutiya).
+# Probably also: Kuril Islands.
+# The Sakha districts are: Abyjskij, Allaikhovskij, Momskij,
+# Nizhnekolymskij, Ojmyakonskij.
+Zone Asia/Magadan	10:03:12 -	LMT	1924 May  2
+			10:00	-	MAGT	1930 Jun 21 # Magadan Time
+			11:00	Russia	MAG%sT	1991 Mar 31 2:00s
+			10:00	Russia	MAG%sT	1992 Jan 19 2:00s
+			11:00	Russia	MAG%sT
+#
+# From Oscar van Vlijmen (2001-08-25): [This region consists of]
+# Kamchatskaya oblast', Koryakskij avtonomnyj okrug.
+#
+# The Zone name should be Asia/Petropavlovsk-Kamchatski, but that's too long.
+Zone Asia/Kamchatka	10:34:36 -	LMT	1922 Nov 10
+			11:00	-	PETT	1930 Jun 21 # P-K Time
+			12:00	Russia	PET%sT	1991 Mar 31 2:00s
+			11:00	Russia	PET%sT	1992 Jan 19 2:00s
+			12:00	Russia	PET%sT
+#
+# Chukotskij avtonomnyj okrug
+Zone Asia/Anadyr	11:49:56 -	LMT	1924 May  2
+			12:00	-	ANAT	1930 Jun 21 # Anadyr Time
+			13:00	Russia	ANA%sT	1982 Apr  1 0:00s
+			12:00	Russia	ANA%sT	1991 Mar 31 2:00s
+			11:00	Russia	ANA%sT	1992 Jan 19 2:00s
+			12:00	Russia	ANA%sT
+
+# Serbia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Belgrade	1:22:00	-	LMT	1884
+			1:00	-	CET	1941 Apr 18 23:00
+			1:00	C-Eur	CE%sT	1945
+			1:00	-	CET	1945 May 8 2:00s
+			1:00	1:00	CEST	1945 Sep 16  2:00s
+# Metod Kozelj reports that the legal date of
+# transition to EU rules was 1982-11-27, for all of Yugoslavia at the time.
+# Shanks & Pottenger don't give as much detail, so go with Kozelj.
+			1:00	-	CET	1982 Nov 27
+			1:00	EU	CE%sT
+Link Europe/Belgrade Europe/Ljubljana	# Slovenia
+Link Europe/Belgrade Europe/Podgorica	# Montenegro
+Link Europe/Belgrade Europe/Sarajevo	# Bosnia and Herzegovina
+Link Europe/Belgrade Europe/Skopje	# Macedonia
+Link Europe/Belgrade Europe/Zagreb	# Croatia
+
+# Slovakia
+Link Europe/Prague Europe/Bratislava
+
+# Slovenia
+# see Serbia
+
+# Spain
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+# For 1917-1919 Whitman gives Apr Sat>=1 - Oct Sat>=1;
+# go with Shanks & Pottenger.
+Rule	Spain	1917	only	-	May	 5	23:00s	1:00	S
+Rule	Spain	1917	1919	-	Oct	 6	23:00s	0	-
+Rule	Spain	1918	only	-	Apr	15	23:00s	1:00	S
+Rule	Spain	1919	only	-	Apr	 5	23:00s	1:00	S
+# Whitman gives 1921 Feb 28 - Oct 14; go with Shanks & Pottenger.
+Rule	Spain	1924	only	-	Apr	16	23:00s	1:00	S
+# Whitman gives 1924 Oct 14; go with Shanks & Pottenger.
+Rule	Spain	1924	only	-	Oct	 4	23:00s	0	-
+Rule	Spain	1926	only	-	Apr	17	23:00s	1:00	S
+# Whitman says no DST in 1929; go with Shanks & Pottenger.
+Rule	Spain	1926	1929	-	Oct	Sat>=1	23:00s	0	-
+Rule	Spain	1927	only	-	Apr	 9	23:00s	1:00	S
+Rule	Spain	1928	only	-	Apr	14	23:00s	1:00	S
+Rule	Spain	1929	only	-	Apr	20	23:00s	1:00	S
+# Whitman gives 1937 Jun 16, 1938 Apr 16, 1940 Apr 13;
+# go with Shanks & Pottenger.
+Rule	Spain	1937	only	-	May	22	23:00s	1:00	S
+Rule	Spain	1937	1939	-	Oct	Sat>=1	23:00s	0	-
+Rule	Spain	1938	only	-	Mar	22	23:00s	1:00	S
+Rule	Spain	1939	only	-	Apr	15	23:00s	1:00	S
+Rule	Spain	1940	only	-	Mar	16	23:00s	1:00	S
+# Whitman says no DST 1942-1945; go with Shanks & Pottenger.
+Rule	Spain	1942	only	-	May	 2	22:00s	2:00	M # Midsummer
+Rule	Spain	1942	only	-	Sep	 1	22:00s	1:00	S
+Rule	Spain	1943	1946	-	Apr	Sat>=13	22:00s	2:00	M
+Rule	Spain	1943	only	-	Oct	 3	22:00s	1:00	S
+Rule	Spain	1944	only	-	Oct	10	22:00s	1:00	S
+Rule	Spain	1945	only	-	Sep	30	 1:00	1:00	S
+Rule	Spain	1946	only	-	Sep	30	 0:00	0	-
+Rule	Spain	1949	only	-	Apr	30	23:00	1:00	S
+Rule	Spain	1949	only	-	Sep	30	 1:00	0	-
+Rule	Spain	1974	1975	-	Apr	Sat>=13	23:00	1:00	S
+Rule	Spain	1974	1975	-	Oct	Sun>=1	 1:00	0	-
+Rule	Spain	1976	only	-	Mar	27	23:00	1:00	S
+Rule	Spain	1976	1977	-	Sep	lastSun	 1:00	0	-
+Rule	Spain	1977	1978	-	Apr	 2	23:00	1:00	S
+Rule	Spain	1978	only	-	Oct	 1	 1:00	0	-
+# The following rules are copied from Morocco from 1967 through 1978.
+Rule SpainAfrica 1967	only	-	Jun	 3	12:00	1:00	S
+Rule SpainAfrica 1967	only	-	Oct	 1	 0:00	0	-
+Rule SpainAfrica 1974	only	-	Jun	24	 0:00	1:00	S
+Rule SpainAfrica 1974	only	-	Sep	 1	 0:00	0	-
+Rule SpainAfrica 1976	1977	-	May	 1	 0:00	1:00	S
+Rule SpainAfrica 1976	only	-	Aug	 1	 0:00	0	-
+Rule SpainAfrica 1977	only	-	Sep	28	 0:00	0	-
+Rule SpainAfrica 1978	only	-	Jun	 1	 0:00	1:00	S
+Rule SpainAfrica 1978	only	-	Aug	 4	 0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Madrid	-0:14:44 -	LMT	1901 Jan  1  0:00s
+			 0:00	Spain	WE%sT	1946 Sep 30
+			 1:00	Spain	CE%sT	1979
+			 1:00	EU	CE%sT
+Zone	Africa/Ceuta	-0:21:16 -	LMT	1901
+			 0:00	-	WET	1918 May  6 23:00
+			 0:00	1:00	WEST	1918 Oct  7 23:00
+			 0:00	-	WET	1924
+			 0:00	Spain	WE%sT	1929
+			 0:00 SpainAfrica WE%sT 1984 Mar 16
+			 1:00	-	CET	1986
+			 1:00	EU	CE%sT
+Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
+			-1:00	-	CANT	1946 Sep 30 1:00 # Canaries Time
+			 0:00	-	WET	1980 Apr  6 0:00s
+			 0:00	1:00	WEST	1980 Sep 28 0:00s
+			 0:00	EU	WE%sT
+# IATA SSIM (1996-09) says the Canaries switch at 2:00u, not 1:00u.
+# Ignore this for now, as the Canaries are part of the EU.
+
+# Sweden
+
+# From Ivan Nilsson (2001-04-13), superseding Shanks & Pottenger:
+#
+# The law "Svensk forfattningssamling 1878, no 14" about standard time in 1879:
+# From the beginning of 1879 (that is 01-01 00:00) the time for all
+# places in the country is "the mean solar time for the meridian at
+# three degrees, or twelve minutes of time, to the west of the
+# meridian of the Observatory of Stockholm".  The law is dated 1878-05-31.
+#
+# The observatory at that time had the meridian 18 degrees 03' 30"
+# eastern longitude = 01:12:14 in time.  Less 12 minutes gives the
+# national standard time as 01:00:14 ahead of GMT....
+#
+# About the beginning of CET in Sweden. The lawtext ("Svensk
+# forfattningssamling 1899, no 44") states, that "from the beginning
+# of 1900... ... the same as the mean solar time for the meridian at
+# the distance of one hour of time from the meridian of the English
+# observatory at Greenwich, or at 12 minutes 14 seconds to the west
+# from the meridian of the Observatory of Stockholm". The law is dated
+# 1899-06-16.  In short: At 1900-01-01 00:00:00 the new standard time
+# in Sweden is 01:00:00 ahead of GMT.
+#
+# 1916: The lawtext ("Svensk forfattningssamling 1916, no 124") states
+# that "1916-05-15 is considered to begin one hour earlier". It is
+# pretty obvious that at 05-14 23:00 the clocks are set to 05-15 00:00....
+# Further the law says, that "1916-09-30 is considered to end one hour later".
+#
+# The laws regulating [DST] are available on the site of the Swedish
+# Parliament beginning with 1985 - the laws regulating 1980/1984 are
+# not available on the site (to my knowledge they are only available
+# in Swedish):  (type
+# "sommartid" without the quotes in the field "Fritext" and then click
+# the Sok-button).
+#
+# (2001-05-13):
+#
+# I have now found a newspaper stating that at 1916-10-01 01:00
+# summertime the church-clocks etc were set back one hour to show
+# 1916-10-01 00:00 standard time.  The article also reports that some
+# people thought the switch to standard time would take place already
+# at 1916-10-01 00:00 summer time, but they had to wait for another
+# hour before the event took place.
+#
+# Source: The newspaper "Dagens Nyheter", 1916-10-01, page 7 upper left.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
+			1:00:14	-	SET	1900 Jan  1	# Swedish Time
+			1:00	-	CET	1916 May 14 23:00
+			1:00	1:00	CEST	1916 Oct  1 01:00
+			1:00	-	CET	1980
+			1:00	EU	CE%sT
+
+# Switzerland
+# From Howse:
+# By the end of the 18th century clocks and watches became commonplace
+# and their performance improved enormously.  Communities began to keep
+# mean time in preference to apparent time -- Geneva from 1780 ....
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+# From Whitman (who writes ``Midnight?''):
+# Rule	Swiss	1940	only	-	Nov	 2	0:00	1:00	S
+# Rule	Swiss	1940	only	-	Dec	31	0:00	0	-
+# From Shanks & Pottenger:
+# Rule	Swiss	1941	1942	-	May	Sun>=1	2:00	1:00	S
+# Rule	Swiss	1941	1942	-	Oct	Sun>=1	0:00	0	-
+
+# From Alois Treindl (2008-12-17):
+# I have researched the DST usage in Switzerland during the 1940ies.
+#
+# As I wrote in an earlier message, I suspected the current tzdata values
+# to be wrong. This is now verified.
+#
+# I have found copies of the original ruling by the Swiss Federal
+# government, in 'Eidgen[o]ssische Gesetzessammlung 1941 and 1942' (Swiss
+# federal law collection)...
+#
+# DST began on Monday 5 May 1941, 1:00 am by shifting the clocks to 2:00 am
+# DST ended on Monday 6 Oct 1941, 2:00 am by shifting the clocks to 1:00 am.
+#
+# DST began on Monday, 4 May 1942 at 01:00 am
+# DST ended on Monday, 5 Oct 1942 at 02:00 am
+#
+# There was no DST in 1940, I have checked the law collection carefully.
+# It is also indicated by the fact that the 1942 entry in the law
+# collection points back to 1941 as a reference, but no reference to any
+# other years are made.
+#
+# Newspaper articles I have read in the archives on 6 May 1941 reported
+# about the introduction of DST (Sommerzeit in German) during the previous
+# night as an absolute novelty, because this was the first time that such
+# a thing had happened in Switzerland.
+#
+# I have also checked 1916, because one book source (Gabriel, Traite de
+# l'heure dans le monde) claims that Switzerland had DST in 1916. This is
+# false, no official document could be found. Probably Gabriel got misled
+# by references to Germany, which introduced DST in 1916 for the first time.
+#
+# The tzdata rules for Switzerland must be changed to:
+# Rule  Swiss   1941    1942    -       May     Mon>=1  1:00    1:00    S
+# Rule  Swiss   1941    1942    -       Oct     Mon>=1  2:00    0       -
+#
+# The 1940 rules must be deleted.
+#
+# One further detail for Switzerland, which is probably out of scope for
+# most users of tzdata:
+# The zone file
+# Zone    Europe/Zurich   0:34:08 -       LMT     1848 Sep 12
+#                          0:29:44 -       BMT     1894 Jun #Bern Mean Time
+#                          1:00    Swiss   CE%sT   1981
+#                          1:00    EU      CE%sT
+# describes all of Switzerland correctly, with the exception of
+# the Cantone Geneve (Geneva, Genf). Between 1848 and 1894 Geneve did not
+# follow Bern Mean Time but kept its own local mean time.
+# To represent this, an extra zone would be needed.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Swiss	1941	1942	-	May	Mon>=1	1:00	1:00	S
+Rule	Swiss	1941	1942	-	Oct	Mon>=1	2:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Zurich	0:34:08 -	LMT	1848 Sep 12
+			0:29:44	-	BMT	1894 Jun # Bern Mean Time
+			1:00	Swiss	CE%sT	1981
+			1:00	EU	CE%sT
+
+# Turkey
+
+# From Amar Devegowda (2007-01-03):
+# The time zone rules for Istanbul, Turkey have not been changed for years now.
+# ... The latest rules are available at -
+# http://www.timeanddate.com/worldclock/timezone.html?n=107
+# From Steffen Thorsen (2007-01-03):
+# I have been able to find press records back to 1996 which all say that
+# DST started 01:00 local time and end at 02:00 local time.  I am not sure
+# what happened before that.  One example for each year from 1996 to 2001:
+# http://newspot.byegm.gov.tr/arsiv/1996/21/N4.htm
+# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING97/03/97X03X25.TXT
+# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING98/03/98X03X02.HTM
+# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING99/10/99X10X26.HTM#%2016
+# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2000/03/00X03X06.HTM#%2021
+# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2001/03/23x03x01.HTM#%2027
+# From Paul Eggert (2007-01-03):
+# Prefer the above source to Shanks & Pottenger for time stamps after 1990.
+
+# From Steffen Thorsen (2007-03-09):
+# Starting 2007 though, it seems that they are adopting EU's 1:00 UTC
+# start/end time, according to the following page (2007-03-07):
+# http://www.ntvmsnbc.com/news/402029.asp
+# The official document is located here - it is in Turkish...:
+# http://rega.basbakanlik.gov.tr/eskiler/2007/03/20070307-7.htm
+# I was able to locate the following seemingly official document
+# (on a non-government server though) describing dates between 2002 and 2006:
+# http://www.alomaliye.com/bkk_2002_3769.htm
+
+# From Sue Williams (2008-08-11):
+# I spotted this news article about a potential change in Turkey.
+#
+# 
+# http://www.hurriyet.com.tr/english/domestic/9626174.asp?scr=1
+# 
+
+# From Sue Williams (2008-08-20):
+# This article says that around the end of March 2011, Turkey wants to
+# adjust the clocks forward by 1/2 hour and stay that way permanently.
+# The article indicates that this is a change in timezone offset in addition
+# to stopping observance of DST.
+# This proposal has not yet been approved.
+#
+# Read more here...
+#
+# Turkey to abandon daylight saving time in 2011
+# 
+# http://www.turkishdailynews.com.tr/article.php?enewsid=112989
+# 
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Turkey	1916	only	-	May	 1	0:00	1:00	S
+Rule	Turkey	1916	only	-	Oct	 1	0:00	0	-
+Rule	Turkey	1920	only	-	Mar	28	0:00	1:00	S
+Rule	Turkey	1920	only	-	Oct	25	0:00	0	-
+Rule	Turkey	1921	only	-	Apr	 3	0:00	1:00	S
+Rule	Turkey	1921	only	-	Oct	 3	0:00	0	-
+Rule	Turkey	1922	only	-	Mar	26	0:00	1:00	S
+Rule	Turkey	1922	only	-	Oct	 8	0:00	0	-
+# Whitman gives 1923 Apr 28 - Sep 16 and no DST in 1924-1925;
+# go with Shanks & Pottenger.
+Rule	Turkey	1924	only	-	May	13	0:00	1:00	S
+Rule	Turkey	1924	1925	-	Oct	 1	0:00	0	-
+Rule	Turkey	1925	only	-	May	 1	0:00	1:00	S
+Rule	Turkey	1940	only	-	Jun	30	0:00	1:00	S
+Rule	Turkey	1940	only	-	Oct	 5	0:00	0	-
+Rule	Turkey	1940	only	-	Dec	 1	0:00	1:00	S
+Rule	Turkey	1941	only	-	Sep	21	0:00	0	-
+Rule	Turkey	1942	only	-	Apr	 1	0:00	1:00	S
+# Whitman omits the next two transition and gives 1945 Oct 1;
+# go with Shanks & Pottenger.
+Rule	Turkey	1942	only	-	Nov	 1	0:00	0	-
+Rule	Turkey	1945	only	-	Apr	 2	0:00	1:00	S
+Rule	Turkey	1945	only	-	Oct	 8	0:00	0	-
+Rule	Turkey	1946	only	-	Jun	 1	0:00	1:00	S
+Rule	Turkey	1946	only	-	Oct	 1	0:00	0	-
+Rule	Turkey	1947	1948	-	Apr	Sun>=16	0:00	1:00	S
+Rule	Turkey	1947	1950	-	Oct	Sun>=2	0:00	0	-
+Rule	Turkey	1949	only	-	Apr	10	0:00	1:00	S
+Rule	Turkey	1950	only	-	Apr	19	0:00	1:00	S
+Rule	Turkey	1951	only	-	Apr	22	0:00	1:00	S
+Rule	Turkey	1951	only	-	Oct	 8	0:00	0	-
+Rule	Turkey	1962	only	-	Jul	15	0:00	1:00	S
+Rule	Turkey	1962	only	-	Oct	 8	0:00	0	-
+Rule	Turkey	1964	only	-	May	15	0:00	1:00	S
+Rule	Turkey	1964	only	-	Oct	 1	0:00	0	-
+Rule	Turkey	1970	1972	-	May	Sun>=2	0:00	1:00	S
+Rule	Turkey	1970	1972	-	Oct	Sun>=2	0:00	0	-
+Rule	Turkey	1973	only	-	Jun	 3	1:00	1:00	S
+Rule	Turkey	1973	only	-	Nov	 4	3:00	0	-
+Rule	Turkey	1974	only	-	Mar	31	2:00	1:00	S
+Rule	Turkey	1974	only	-	Nov	 3	5:00	0	-
+Rule	Turkey	1975	only	-	Mar	30	0:00	1:00	S
+Rule	Turkey	1975	1976	-	Oct	lastSun	0:00	0	-
+Rule	Turkey	1976	only	-	Jun	 1	0:00	1:00	S
+Rule	Turkey	1977	1978	-	Apr	Sun>=1	0:00	1:00	S
+Rule	Turkey	1977	only	-	Oct	16	0:00	0	-
+Rule	Turkey	1979	1980	-	Apr	Sun>=1	3:00	1:00	S
+Rule	Turkey	1979	1982	-	Oct	Mon>=11	0:00	0	-
+Rule	Turkey	1981	1982	-	Mar	lastSun	3:00	1:00	S
+Rule	Turkey	1983	only	-	Jul	31	0:00	1:00	S
+Rule	Turkey	1983	only	-	Oct	 2	0:00	0	-
+Rule	Turkey	1985	only	-	Apr	20	0:00	1:00	S
+Rule	Turkey	1985	only	-	Sep	28	0:00	0	-
+Rule	Turkey	1986	1990	-	Mar	lastSun	2:00s	1:00	S
+Rule	Turkey	1986	1990	-	Sep	lastSun	2:00s	0	-
+Rule	Turkey	1991	2006	-	Mar	lastSun	1:00s	1:00	S
+Rule	Turkey	1991	1995	-	Sep	lastSun	1:00s	0	-
+Rule	Turkey	1996	2006	-	Oct	lastSun	1:00s	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	Europe/Istanbul	1:55:52 -	LMT	1880
+			1:56:56	-	IMT	1910 Oct # Istanbul Mean Time?
+			2:00	Turkey	EE%sT	1978 Oct 15
+			3:00	Turkey	TR%sT	1985 Apr 20 # Turkey Time
+			2:00	Turkey	EE%sT	2007
+			2:00	EU	EE%sT
+Link	Europe/Istanbul	Asia/Istanbul	# Istanbul is in both continents.
+
+# Ukraine
+#
+# From Igor Karpov, who works for the Ukranian Ministry of Justice,
+# via Garrett Wollman (2003-01-27):
+# BTW, I've found the official document on this matter. It's goverment
+# regulations number 509, May 13, 1996. In my poor translation it says:
+# "Time in Ukraine is set to second timezone (Kiev time). Each last Sunday
+# of March at 3am the time is changing to 4am and each last Sunday of
+# October the time at 4am is changing to 3am"
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+# Most of Ukraine since 1970 has been like Kiev.
+# "Kyiv" is the transliteration of the Ukrainian name, but
+# "Kiev" is more common in English.
+Zone Europe/Kiev	2:02:04 -	LMT	1880
+			2:02:04	-	KMT	1924 May  2 # Kiev Mean Time
+			2:00	-	EET	1930 Jun 21
+			3:00	-	MSK	1941 Sep 20
+			1:00	C-Eur	CE%sT	1943 Nov  6
+			3:00	Russia	MSK/MSD	1990
+			3:00	-	MSK	1990 Jul  1 2:00
+			2:00	-	EET	1992
+			2:00	E-Eur	EE%sT	1995
+			2:00	EU	EE%sT
+# Ruthenia used CET 1990/1991.
+# "Uzhhorod" is the transliteration of the Ukrainian name, but
+# "Uzhgorod" is more common in English.
+Zone Europe/Uzhgorod	1:29:12 -	LMT	1890 Oct
+			1:00	-	CET	1940
+			1:00	C-Eur	CE%sT	1944 Oct
+			1:00	1:00	CEST	1944 Oct 26
+			1:00	-	CET	1945 Jun 29
+			3:00	Russia	MSK/MSD	1990
+			3:00	-	MSK	1990 Jul  1 2:00
+			1:00	-	CET	1991 Mar 31 3:00
+			2:00	-	EET	1992
+			2:00	E-Eur	EE%sT	1995
+			2:00	EU	EE%sT
+# Zaporozh'ye and eastern Lugansk oblasts observed DST 1990/1991.
+# "Zaporizhia" is the transliteration of the Ukrainian name, but
+# "Zaporozh'ye" is more common in English.  Use the common English
+# spelling, except omit the apostrophe as it is not allowed in
+# portable Posix file names.
+Zone Europe/Zaporozhye	2:20:40 -	LMT	1880
+			2:20	-	CUT	1924 May  2 # Central Ukraine T
+			2:00	-	EET	1930 Jun 21
+			3:00	-	MSK	1941 Aug 25
+			1:00	C-Eur	CE%sT	1943 Oct 25
+			3:00	Russia	MSK/MSD	1991 Mar 31 2:00
+			2:00	E-Eur	EE%sT	1995
+			2:00	EU	EE%sT
+# Central Crimea used Moscow time 1994/1997.
+Zone Europe/Simferopol	2:16:24 -	LMT	1880
+			2:16	-	SMT	1924 May  2 # Simferopol Mean T
+			2:00	-	EET	1930 Jun 21
+			3:00	-	MSK	1941 Nov
+			1:00	C-Eur	CE%sT	1944 Apr 13
+			3:00	Russia	MSK/MSD	1990
+			3:00	-	MSK	1990 Jul  1 2:00
+			2:00	-	EET	1992
+# From Paul Eggert (2006-03-22):
+# The _Economist_ (1994-05-28, p 45) reports that central Crimea switched
+# from Kiev to Moscow time sometime after the January 1994 elections.
+# Shanks (1999) says ``date of change uncertain'', but implies that it happened
+# sometime between the 1994 DST switches.  Shanks & Pottenger simply say
+# 1994-09-25 03:00, but that can't be right.  For now, guess it
+# changed in May.
+			2:00	E-Eur	EE%sT	1994 May
+# From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev.
+			3:00	E-Eur	MSK/MSD	1996 Mar 31 3:00s
+			3:00	1:00	MSD	1996 Oct 27 3:00s
+# IATA SSIM (1997-09) says Crimea switched to EET/EEST.
+# Assume it happened in March by not changing the clocks.
+			3:00	Russia	MSK/MSD	1997
+			3:00	-	MSK	1997 Mar lastSun 1:00u
+			2:00	EU	EE%sT
+
+###############################################################################
+
+# One source shows that Bulgaria, Cyprus, Finland, and Greece observe DST from
+# the last Sunday in March to the last Sunday in September in 1986.
+# The source shows Romania changing a day later than everybody else.
+#
+# According to Bernard Sieloff's source, Poland is in the MET time zone but
+# uses the WE DST rules.  The Western USSR uses EET+1 and ME DST rules.
+# Bernard Sieloff's source claims Romania switches on the same day, but at
+# 00:00 standard time (i.e., 01:00 DST).  It also claims that Turkey
+# switches on the same day, but switches on at 01:00 standard time
+# and off at 00:00 standard time (i.e., 01:00 DST)
+
+# ...
+# Date: Wed, 28 Jan 87 16:56:27 -0100
+# From: Tom Hofmann
+# ...
+#
+# ...the European time rules are...standardized since 1981, when
+# most European coun[tr]ies started DST.  Before that year, only
+# a few countries (UK, France, Italy) had DST, each according
+# to own national rules.  In 1981, however, DST started on
+# 'Apr firstSun', and not on 'Mar lastSun' as in the following
+# years...
+# But also since 1981 there are some more national exceptions
+# than listed in 'europe': Switzerland, for example, joined DST
+# one year later, Denmark ended DST on 'Oct 1' instead of 'Sep
+# lastSun' in 1981---I don't know how they handle now.
+#
+# Finally, DST ist always from 'Apr 1' to 'Oct 1' in the
+# Soviet Union (as far as I know).
+#
+# Tom Hofmann, Scientific Computer Center, CIBA-GEIGY AG,
+# 4002 Basle, Switzerland
+# ...
+
+# ...
+# Date: Wed, 4 Feb 87 22:35:22 +0100
+# From: Dik T. Winter
+# ...
+#
+# The information from Tom Hofmann is (as far as I know) not entirely correct.
+# After a request from chongo at amdahl I tried to retrieve all information
+# about DST in Europe.  I was able to find all from about 1969.
+#
+# ...standardization on DST in Europe started in about 1977 with switches on
+# first Sunday in April and last Sunday in September...
+# In 1981 UK joined Europe insofar that
+# the starting day for both shifted to last Sunday in March.  And from 1982
+# the whole of Europe used DST, with switch dates April 1 and October 1 in
+# the Sov[i]et Union.  In 1985 the SU reverted to standard Europe[a]n switch
+# dates...
+#
+# It should also be remembered that time-zones are not constants; e.g.
+# Portugal switched in 1976 from MET (or CET) to WET with DST...
+# Note also that though there were rules for switch dates not
+# all countries abided to these dates, and many individual deviations
+# occurred, though not since 1982 I believe.  Another note: it is always
+# assumed that DST is 1 hour ahead of normal time, this need not be the
+# case; at least in the Netherlands there have been times when DST was 2 hours
+# in advance of normal time.
+#
+# ...
+# dik t. winter, cwi, amsterdam, nederland
+# ...
+
+# From Bob Devine (1988-01-28):
+# ...
+# Greece: Last Sunday in April to last Sunday in September (iffy on dates).
+# Since 1978.  Change at midnight.
+# ...
+# Monaco: has same DST as France.
+# ...
diff --git a/extra/zoneinfo/leapseconds b/extra/zoneinfo/leapseconds
new file mode 100644
index 0000000000..aa8cceba0b
--- /dev/null
+++ b/extra/zoneinfo/leapseconds
@@ -0,0 +1,84 @@
+# @(#)leapseconds	8.7
+
+# Allowance for leapseconds added to each timezone file.
+
+# The International Earth Rotation Service periodically uses leap seconds
+# to keep UTC to within 0.9 s of UT1
+# (which measures the true angular orientation of the earth in space); see
+# Terry J Quinn, The BIPM and the accurate measure of time,
+# Proc IEEE 79, 7 (July 1991), 894-905.
+# There were no leap seconds before 1972, because the official mechanism
+# accounting for the discrepancy between atomic time and the earth's rotation
+# did not exist until the early 1970s.
+
+# The correction (+ or -) is made at the given time, so lines
+# will typically look like:
+#	Leap	YEAR	MON	DAY	23:59:60	+	R/S
+# or
+#	Leap	YEAR	MON	DAY	23:59:59	-	R/S
+
+# If the leapsecond is Rolling (R) the given time is local time
+# If the leapsecond is Stationary (S) the given time is UTC
+
+# Leap	YEAR	MONTH	DAY	HH:MM:SS	CORR	R/S
+Leap	1972	Jun	30	23:59:60	+	S
+Leap	1972	Dec	31	23:59:60	+	S
+Leap	1973	Dec	31	23:59:60	+	S
+Leap	1974	Dec	31	23:59:60	+	S
+Leap	1975	Dec	31	23:59:60	+	S
+Leap	1976	Dec	31	23:59:60	+	S
+Leap	1977	Dec	31	23:59:60	+	S
+Leap	1978	Dec	31	23:59:60	+	S
+Leap	1979	Dec	31	23:59:60	+	S
+Leap	1981	Jun	30	23:59:60	+	S
+Leap	1982	Jun	30	23:59:60	+	S
+Leap	1983	Jun	30	23:59:60	+	S
+Leap	1985	Jun	30	23:59:60	+	S
+Leap	1987	Dec	31	23:59:60	+	S
+Leap	1989	Dec	31	23:59:60	+	S
+Leap	1990	Dec	31	23:59:60	+	S
+Leap	1992	Jun	30	23:59:60	+	S
+Leap	1993	Jun	30	23:59:60	+	S
+Leap	1994	Jun	30	23:59:60	+	S
+Leap	1995	Dec	31	23:59:60	+	S
+Leap	1997	Jun	30	23:59:60	+	S
+Leap	1998	Dec	31	23:59:60	+	S
+Leap	2005	Dec	31	23:59:60	+	S
+Leap	2008	Dec	31	23:59:60	+	S
+
+# INTERNATIONAL EARTH ROTATION AND REFERENCE SYSTEMS SERVICE (IERS)
+#
+# SERVICE INTERNATIONAL DE LA ROTATION TERRESTRE ET DES SYSTEMES DE REFERENCE
+#
+# SERVICE DE LA ROTATION TERRESTRE
+# OBSERVATOIRE DE PARIS
+# 61, Av. de l'Observatoire 75014 PARIS (France)
+# Tel.      : 33 (0) 1 40 51 22 29
+# FAX       : 33 (0) 1 40 51 22 91
+# Internet  : services.iers@obspm.fr
+#
+# Paris, 15 January 2009
+#
+# Bulletin C 37
+#
+# To authorities responsible
+# for the measurement and
+# distribution of time
+#
+# INFORMATION ON UTC - TAI
+#
+# NO positive leap second will be introduced at the end of June 2009.
+# The difference between Coordinated Universal Time UTC and the
+# International Atomic Time TAI is :		
+#
+# from 2009 January 1, 0h UTC, until further notice : UTC-TAI = -34 s
+#
+# Leap seconds can be introduced in UTC at the end of the months of December
+# or June,  depending on the evolution of UT1-TAI. Bulletin C is mailed every
+# six months, either to announce a time step in UTC, or to confirm that there
+# will be no time step at the next possible date.
+#
+# Daniel GAMBIS
+# Head			
+# Earth Orientation Center of the IERS
+# Observatoire de Paris, France
diff --git a/extra/zoneinfo/northamerica b/extra/zoneinfo/northamerica
new file mode 100644
index 0000000000..7fd6ea6173
--- /dev/null
+++ b/extra/zoneinfo/northamerica
@@ -0,0 +1,2678 @@
+# @(#)northamerica	8.27
+# 
+
+# also includes Central America and the Caribbean
+
+# This data is by no means authoritative; if you think you know better,
+# go ahead and edit the file (and please send any changes to
+# tz@elsie.nci.nih.gov for general use in the future).
+
+# From Paul Eggert (1999-03-22):
+# A reliable and entertaining source about time zones is
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
+
+###############################################################################
+
+# United States
+
+# From Paul Eggert (1999-03-31):
+# Howse writes (pp 121-125) that time zones were invented by
+# Professor Charles Ferdinand Dowd (1825-1904),
+# Principal of Temple Grove Ladies' Seminary (Saratoga Springs, NY).
+# His pamphlet ``A System of National Time for Railroads'' (1870)
+# was the result of his proposals at the Convention of Railroad Trunk Lines
+# in New York City (1869-10).  His 1870 proposal was based on Washington, DC,
+# but in 1872-05 he moved the proposed origin to Greenwich.
+# His proposal was adopted by the railroads on 1883-11-18 at 12:00,
+# and the most of the country soon followed suit.
+
+# From Paul Eggert (2005-04-16):
+# That 1883 transition occurred at 12:00 new time, not at 12:00 old time.
+# See p 46 of David Prerau, Seize the daylight, Thunder's Mouth Press (2005).
+
+# From Paul Eggert (2006-03-22):
+# A good source for time zone historical data in the US is
+# Thomas G. Shanks, The American Atlas (5th edition),
+# San Diego: ACS Publications, Inc. (1991).
+# Make sure you have the errata sheet; the book is somewhat useless without it.
+# It is the source for most of the pre-1991 US entries below.
+
+# From Paul Eggert (2001-03-06):
+# Daylight Saving Time was first suggested as a joke by Benjamin Franklin
+# in his whimsical essay ``An Economical Project for Diminishing the Cost
+# of Light'' published in the Journal de Paris (1784-04-26).
+# Not everyone is happy with the results:
+#
+#	I don't really care how time is reckoned so long as there is some
+#	agreement about it, but I object to being told that I am saving
+#	daylight when my reason tells me that I am doing nothing of the kind.
+#	I even object to the implication that I am wasting something
+#	valuable if I stay in bed after the sun has risen.  As an admirer
+#	of moonlight I resent the bossy insistence of those who want to
+#	reduce my time for enjoying it.  At the back of the Daylight Saving
+#	scheme I detect the bony, blue-fingered hand of Puritanism, eager
+#	to push people into bed earlier, and get them up earlier, to make
+#	them healthy, wealthy and wise in spite of themselves.
+#
+#	-- Robertson Davies, The diary of Samuel Marchbanks,
+#	   Clarke, Irwin (1947), XIX, Sunday
+#
+# For more about the first ten years of DST in the United States, see
+# Robert Garland's 
+# Ten years of daylight saving from the Pittsburgh standpoint
+# (Carnegie Library of Pittsburgh, 1927).
+#
+# Shanks says that DST was called "War Time" in the US in 1918 and 1919.
+# However, DST was imposed by the Standard Time Act of 1918, which
+# was the first nationwide legal time standard, and apparently
+# time was just called "Standard Time" or "Daylight Saving Time".
+
+# From Arthur David Olson:
+# US Daylight Saving Time ended on the last Sunday of *October* in 1974.
+# See, for example, the front page of the Saturday, 1974-10-26
+# and Sunday, 1974-10-27 editions of the Washington Post.
+
+# From Arthur David Olson:
+# Before the Uniform Time Act of 1966 took effect in 1967, observance of
+# Daylight Saving Time in the US was by local option, except during wartime.
+
+# From Arthur David Olson (2000-09-25):
+# Last night I heard part of a rebroadcast of a 1945 Arch Oboler radio drama.
+# In the introduction, Oboler spoke of "Eastern Peace Time."
+# An AltaVista search turned up
+# :
+# "When the time is announced over the radio now, it is 'Eastern Peace
+# Time' instead of the old familiar 'Eastern War Time.'  Peace is wonderful."
+#  (August 1945) by way of confirmation.
+
+# From Joseph Gallant citing
+# George H. Douglas, _The Early Days of Radio Broadcasting_ (1987):
+# At 7 P.M. (Eastern War Time) [on 1945-08-14], the networks were set
+# to switch to London for Attlee's address, but the American people
+# never got to hear his speech live. According to one press account,
+# CBS' Bob Trout was first to announce the word of Japan's surrender,
+# but a few seconds later, NBC, ABC and Mutual also flashed the word
+# of surrender, all of whom interrupting the bells of Big Ben in
+# London which were to precede Mr. Attlee's speech.
+
+# From Paul Eggert (2003-02-09): It was Robert St John, not Bob Trout.  From
+# Myrna Oliver's obituary of St John on page B16 of today's Los Angeles Times:
+#
+# ... a war-weary U.S. clung to radios, awaiting word of Japan's surrender.
+# Any announcement from Asia would reach St. John's New York newsroom on a
+# wire service teletype machine, which had prescribed signals for major news.
+# Associated Press, for example, would ring five bells before spewing out
+# typed copy of an important story, and 10 bells for news "of transcendental
+# importance."
+#
+# On Aug. 14, stalling while talking steadily into the NBC networks' open
+# microphone, St. John heard five bells and waited only to hear a sixth bell,
+# before announcing confidently: "Ladies and gentlemen, World War II is over.
+# The Japanese have agreed to our surrender terms."
+#
+# He had scored a 20-second scoop on other broadcasters.
+
+# From Arthur David Olson (2005-08-22):
+# Paul has been careful to use the "US" rules only in those locations
+# that are part of the United States; this reflects the real scope of
+# U.S. government action.  So even though the "US" rules have changed
+# in the latest release, other countries won't be affected.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	US	1918	1919	-	Mar	lastSun	2:00	1:00	D
+Rule	US	1918	1919	-	Oct	lastSun	2:00	0	S
+Rule	US	1942	only	-	Feb	9	2:00	1:00	W # War
+Rule	US	1945	only	-	Aug	14	23:00u	1:00	P # Peace
+Rule	US	1945	only	-	Sep	30	2:00	0	S
+Rule	US	1967	2006	-	Oct	lastSun	2:00	0	S
+Rule	US	1967	1973	-	Apr	lastSun	2:00	1:00	D
+Rule	US	1974	only	-	Jan	6	2:00	1:00	D
+Rule	US	1975	only	-	Feb	23	2:00	1:00	D
+Rule	US	1976	1986	-	Apr	lastSun	2:00	1:00	D
+Rule	US	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
+Rule	US	2007	max	-	Mar	Sun>=8	2:00	1:00	D
+Rule	US	2007	max	-	Nov	Sun>=1	2:00	0	S
+
+# From Arthur David Olson, 2005-12-19
+# We generate the files specified below to guard against old files with
+# obsolete information being left in the time zone binary directory.
+# We limit the list to names that have appeared in previous versions of
+# this time zone package.
+# We do these as separate Zones rather than as Links to avoid problems if
+# a particular place changes whether it observes DST.
+# We put these specifications here in the northamerica file both to
+# increase the chances that they'll actually get compiled and to
+# avoid the need to duplicate the US rules in another file.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	EST		 -5:00	-	EST
+Zone	MST		 -7:00	-	MST
+Zone	HST		-10:00	-	HST
+Zone	EST5EDT		 -5:00	US	E%sT
+Zone	CST6CDT		 -6:00	US	C%sT
+Zone	MST7MDT		 -7:00	US	M%sT
+Zone	PST8PDT		 -8:00	US	P%sT
+
+# From Bob Devine (1988-01-28):
+# ...Alaska (and Hawaii) had the timezone names changed in 1967.
+#    old			 new
+#    Pacific Standard Time(PST)  -same-
+#    Yukon Standard Time(YST)    -same-
+#    Central Alaska S.T. (CAT)   Alaska-Hawaii St[an]dard Time (AHST)
+#    Nome Standard Time (NT)     Bering Standard Time (BST)
+#
+# ...Alaska's timezone lines were redrawn in 1983 to give only 2 tz.
+#    The YST zone now covers nearly all of the state, AHST just part
+#    of the Aleutian islands.   No DST.
+
+# From Paul Eggert (1995-12-19):
+# The tables below use `NST', not `NT', for Nome Standard Time.
+# I invented `CAWT' for Central Alaska War Time.
+
+# From U. S. Naval Observatory (1989-01-19):
+# USA  EASTERN       5 H  BEHIND UTC    NEW YORK, WASHINGTON
+# USA  EASTERN       4 H  BEHIND UTC    APR 3 - OCT 30
+# USA  CENTRAL       6 H  BEHIND UTC    CHICAGO, HOUSTON
+# USA  CENTRAL       5 H  BEHIND UTC    APR 3 - OCT 30
+# USA  MOUNTAIN      7 H  BEHIND UTC    DENVER
+# USA  MOUNTAIN      6 H  BEHIND UTC    APR 3 - OCT 30
+# USA  PACIFIC       8 H  BEHIND UTC    L.A., SAN FRANCISCO
+# USA  PACIFIC       7 H  BEHIND UTC    APR 3 - OCT 30
+# USA  ALASKA STD    9 H  BEHIND UTC    MOST OF ALASKA     (AKST)
+# USA  ALASKA STD    8 H  BEHIND UTC    APR 3 - OCT 30 (AKDT)
+# USA  ALEUTIAN     10 H  BEHIND UTC    ISLANDS WEST OF 170W
+# USA  - " -         9 H  BEHIND UTC    APR 3 - OCT 30
+# USA  HAWAII       10 H  BEHIND UTC
+# USA  BERING       11 H  BEHIND UTC    SAMOA, MIDWAY
+
+# From Arthur David Olson (1989-01-21):
+# The above dates are for 1988.
+# Note the "AKST" and "AKDT" abbreviations, the claim that there's
+# no DST in Samoa, and the claim that there is DST in Alaska and the
+# Aleutians.
+
+# From Arthur David Olson (1988-02-13):
+# Legal standard time zone names, from United States Code (1982 Edition and
+# Supplement III), Title 15, Chapter 6, Section 260 and forward.  First, names
+# up to 1967-04-01 (when most provisions of the Uniform Time Act of 1966
+# took effect), as explained in sections 263 and 261:
+#	(none)
+#	United States standard eastern time
+#	United States standard mountain time
+#	United States standard central time
+#	United States standard Pacific time
+#	(none)
+#	United States standard Alaska time
+#	(none)
+# Next, names from 1967-04-01 until 1983-11-30 (the date for
+# public law 98-181):
+#	Atlantic standard time
+#	eastern standard time
+#	central standard time
+#	mountain standard time
+#	Pacific standard time
+#	Yukon standard time
+#	Alaska-Hawaii standard time
+#	Bering standard time
+# And after 1983-11-30:
+#	Atlantic standard time
+#	eastern standard time
+#	central standard time
+#	mountain standard time
+#	Pacific standard time
+#	Alaska standard time
+#	Hawaii-Aleutian standard time
+#	Samoa standard time
+# The law doesn't give abbreviations.
+#
+# From Paul Eggert (2000-01-08), following a heads-up from Rives McDow:
+# Public law 106-564 (2000-12-23) introduced the abbreviation
+# "Chamorro Standard Time" for time in Guam and the Northern Marianas.
+# See the file "australasia".
+
+# From Arthur David Olson, 2005-08-09
+# The following was signed into law on 2005-08-08.
+#
+# H.R. 6, Energy Policy Act of 2005, SEC. 110. DAYLIGHT SAVINGS.
+#   (a) Amendment- Section 3(a) of the Uniform Time Act of 1966 (15
+#   U.S.C. 260a(a)) is amended--
+#     (1) by striking `first Sunday of April' and inserting `second
+#     Sunday of March'; and
+#     (2) by striking `last Sunday of October' and inserting `first
+#     Sunday of November'.
+#   (b) Effective Date- Subsection (a) shall take effect 1 year after the
+#   date of enactment of this Act or March 1, 2007, whichever is later.
+#   (c) Report to Congress- Not later than 9 months after the effective
+#   date stated in subsection (b), the Secretary shall report to Congress
+#   on the impact of this section on energy consumption in the United
+#   States.
+#   (d) Right to Revert- Congress retains the right to revert the
+#   Daylight Saving Time back to the 2005 time schedules once the
+#   Department study is complete.
+
+# US eastern time, represented by New York
+
+# Connecticut, Delaware, District of Columbia, most of Florida,
+# Georgia, southeast Indiana (Dearborn and Ohio counties), eastern Kentucky
+# (except America/Kentucky/Louisville below), Maine, Maryland, Massachusetts,
+# New Hampshire, New Jersey, New York, North Carolina, Ohio,
+# Pennsylvania, Rhode Island, South Carolina, eastern Tennessee,
+# Vermont, Virginia, West Virginia
+
+# From Dave Cantor (2004-11-02):
+# Early this summer I had the occasion to visit the Mount Washington
+# Observatory weather station atop (of course!) Mount Washington [, NH]....
+# One of the staff members said that the station was on Eastern Standard Time
+# and didn't change their clocks for Daylight Saving ... so that their
+# reports will always have times which are 5 hours behind UTC.
+
+# From Paul Eggert (2005-08-26):
+# According to today's Huntsville Times
+# 
+# a few towns on Alabama's "eastern border with Georgia, such as Phenix City
+# in Russell County, Lanett in Chambers County and some towns in Lee County,
+# set their watches and clocks on Eastern time."  It quotes H.H. "Bubba"
+# Roberts, city administrator in Phenix City. as saying "We are in the Central
+# time zone, but we do go by the Eastern time zone because so many people work
+# in Columbus."
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule	NYC	1920	only	-	Mar	lastSun	2:00	1:00	D
+Rule	NYC	1920	only	-	Oct	lastSun	2:00	0	S
+Rule	NYC	1921	1966	-	Apr	lastSun	2:00	1:00	D
+Rule	NYC	1921	1954	-	Sep	lastSun	2:00	0	S
+Rule	NYC	1955	1966	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/New_York	-4:56:02 -	LMT	1883 Nov 18 12:03:58
+			-5:00	US	E%sT	1920
+			-5:00	NYC	E%sT	1942
+			-5:00	US	E%sT	1946
+			-5:00	NYC	E%sT	1967
+			-5:00	US	E%sT
+
+# US central time, represented by Chicago
+
+# Alabama, Arkansas, Florida panhandle (Bay, Calhoun, Escambia,
+# Gulf, Holmes, Jackson, Okaloosa, Santa Rosa, Walton, and
+# Washington counties), Illinois, western Indiana
+# (Gibson, Jasper, Lake, LaPorte, Newton, Porter, Posey, Spencer,
+# Vanderburgh, and Warrick counties), Iowa, most of Kansas, western
+# Kentucky, Louisiana, Minnesota, Mississippi, Missouri, eastern
+# Nebraska, eastern North Dakota, Oklahoma, eastern South Dakota,
+# western Tennessee, most of Texas, Wisconsin
+
+# From Larry M. Smith (2006-04-26) re Wisconsin:
+# http://www.legis.state.wi.us/statutes/Stat0175.pdf ...
+# is currently enforced at the 01:00 time of change.  Because the local
+# "bar time" in the state corresponds to 02:00, a number of citations
+# are issued for the "sale of class 'B' alcohol after prohibited
+# hours" within the deviated hour of this change every year....
+#
+# From Douglas R. Bomberg (2007-03-12):
+# Wisconsin has enacted (nearly eleventh-hour) legislation to get WI
+# Statue 175 closer in synch with the US Congress' intent....
+# http://www.legis.state.wi.us/2007/data/acts/07Act3.pdf
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule	Chicago	1920	only	-	Jun	13	2:00	1:00	D
+Rule	Chicago	1920	1921	-	Oct	lastSun	2:00	0	S
+Rule	Chicago	1921	only	-	Mar	lastSun	2:00	1:00	D
+Rule	Chicago	1922	1966	-	Apr	lastSun	2:00	1:00	D
+Rule	Chicago	1922	1954	-	Sep	lastSun	2:00	0	S
+Rule	Chicago	1955	1966	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Chicago	-5:50:36 -	LMT	1883 Nov 18 12:09:24
+			-6:00	US	C%sT	1920
+			-6:00	Chicago	C%sT	1936 Mar  1 2:00
+			-5:00	-	EST	1936 Nov 15 2:00
+			-6:00	Chicago	C%sT	1942
+			-6:00	US	C%sT	1946
+			-6:00	Chicago	C%sT	1967
+			-6:00	US	C%sT
+# Oliver County, ND switched from mountain to central time on 1992-10-25.
+Zone America/North_Dakota/Center -6:45:12 - LMT	1883 Nov 18 12:14:48
+			-7:00	US	M%sT	1992 Oct 25 02:00
+			-6:00	US	C%sT
+# Morton County, ND, switched from mountain to central time on
+# 2003-10-26, except for the area around Mandan which was already central time.
+# See .
+# Officially this switch also included part of Sioux County, and
+# Jones, Mellette, and Todd Counties in South Dakota;
+# but in practice these other counties were already observing central time.
+# See .
+Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21
+			-7:00	US	M%sT	2003 Oct 26 02:00
+			-6:00	US	C%sT
+
+# US mountain time, represented by Denver
+#
+# Colorado, far western Kansas, Montana, western
+# Nebraska, Nevada border (Jackpot, Owyhee, and Mountain City),
+# New Mexico, southwestern North Dakota,
+# western South Dakota, far western Texas (El Paso County, Hudspeth County,
+# and Pine Springs and Nickel Creek in Culberson County), Utah, Wyoming
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule	Denver	1920	1921	-	Mar	lastSun	2:00	1:00	D
+Rule	Denver	1920	only	-	Oct	lastSun	2:00	0	S
+Rule	Denver	1921	only	-	May	22	2:00	0	S
+Rule	Denver	1965	1966	-	Apr	lastSun	2:00	1:00	D
+Rule	Denver	1965	1966	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Denver	-6:59:56 -	LMT	1883 Nov 18 12:00:04
+			-7:00	US	M%sT	1920
+			-7:00	Denver	M%sT	1942
+			-7:00	US	M%sT	1946
+			-7:00	Denver	M%sT	1967
+			-7:00	US	M%sT
+
+# US Pacific time, represented by Los Angeles
+#
+# California, northern Idaho (Benewah, Bonner, Boundary, Clearwater,
+# Idaho, Kootenai, Latah, Lewis, Nez Perce, and Shoshone counties,
+# and the northern three-quarters of Idaho county),
+# most of Nevada, most of Oregon, and Washington
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule	CA	1948	only	-	Mar	14	2:00	1:00	D
+Rule	CA	1949	only	-	Jan	 1	2:00	0	S
+Rule	CA	1950	1966	-	Apr	lastSun	2:00	1:00	D
+Rule	CA	1950	1961	-	Sep	lastSun	2:00	0	S
+Rule	CA	1962	1966	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Los_Angeles -7:52:58 -	LMT	1883 Nov 18 12:07:02
+			-8:00	US	P%sT	1946
+			-8:00	CA	P%sT	1967
+			-8:00	US	P%sT
+
+# Alaska
+# AK%sT is the modern abbreviation for -9:00 per USNO.
+#
+# From Paul Eggert (2001-05-30):
+# Howse writes that Alaska switched from the Julian to the Gregorian calendar,
+# and from east-of-GMT to west-of-GMT days, when the US bought it from Russia.
+# This was on 1867-10-18, a Friday; the previous day was 1867-10-06 Julian,
+# also a Friday.  Include only the time zone part of this transition,
+# ignoring the switch from Julian to Gregorian, since we can't represent
+# the Julian calendar.
+#
+# As far as we know, none of the exact locations mentioned below were
+# permanently inhabited in 1867 by anyone using either calendar.
+# (Yakutat was colonized by the Russians in 1799, but the settlement
+# was destroyed in 1805 by a Yakutat-kon war party.)  However, there
+# were nearby inhabitants in some cases and for our purposes perhaps
+# it's best to simply use the official transition.
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Juneau	 15:02:19 -	LMT	1867 Oct 18
+			 -8:57:41 -	LMT	1900 Aug 20 12:00
+			 -8:00	-	PST	1942
+			 -8:00	US	P%sT	1946
+			 -8:00	-	PST	1969
+			 -8:00	US	P%sT	1983 Oct 30 2:00
+			 -9:00	US	Y%sT	1983 Nov 30
+			 -9:00	US	AK%sT
+Zone America/Yakutat	 14:41:05 -	LMT	1867 Oct 18
+			 -9:18:55 -	LMT	1900 Aug 20 12:00
+			 -9:00	-	YST	1942
+			 -9:00	US	Y%sT	1946
+			 -9:00	-	YST	1969
+			 -9:00	US	Y%sT	1983 Nov 30
+			 -9:00	US	AK%sT
+Zone America/Anchorage	 14:00:24 -	LMT	1867 Oct 18
+			 -9:59:36 -	LMT	1900 Aug 20 12:00
+			-10:00	-	CAT	1942
+			-10:00	US	CAT/CAWT 1945 Aug 14 23:00u
+			-10:00	US	CAT/CAPT 1946 # Peace
+			-10:00	-	CAT	1967 Apr
+			-10:00	-	AHST	1969
+			-10:00	US	AH%sT	1983 Oct 30 2:00
+			 -9:00	US	Y%sT	1983 Nov 30
+			 -9:00	US	AK%sT
+Zone America/Nome	 12:58:21 -	LMT	1867 Oct 18
+			-11:01:38 -	LMT	1900 Aug 20 12:00
+			-11:00	-	NST	1942
+			-11:00	US	N%sT	1946
+			-11:00	-	NST	1967 Apr
+			-11:00	-	BST	1969
+			-11:00	US	B%sT	1983 Oct 30 2:00
+			 -9:00	US	Y%sT	1983 Nov 30
+			 -9:00	US	AK%sT
+Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
+			-11:46:38 -	LMT	1900 Aug 20 12:00
+			-11:00	-	NST	1942
+			-11:00	US	N%sT	1946
+			-11:00	-	NST	1967 Apr
+			-11:00	-	BST	1969
+			-11:00	US	B%sT	1983 Oct 30 2:00
+			-10:00	US	AH%sT	1983 Nov 30
+			-10:00	US	HA%sT
+# The following switches don't quite make our 1970 cutoff.
+#
+# Shanks writes that part of southwest Alaska (e.g. Aniak)
+# switched from -11:00 to -10:00 on 1968-09-22 at 02:00,
+# and another part (e.g. Akiak) made the same switch five weeks later.
+#
+# From David Flater (2004-11-09):
+# In e-mail, 2004-11-02, Ray Hudson, historian/liaison to the Unalaska
+# Historic Preservation Commission, provided this information, which
+# suggests that Unalaska deviated from statutory time from early 1967
+# possibly until 1983:
+#
+#  Minutes of the Unalaska City Council Meeting, January 10, 1967:
+#  "Except for St. Paul and Akutan, Unalaska is the only important
+#  location not on Alaska Standard Time.  The following resolution was
+#  made by William Robinson and seconded by Henry Swanson:  Be it
+#  resolved that the City of Unalaska hereby goes to Alaska Standard
+#  Time as of midnight Friday, January 13, 1967 (1 A.M. Saturday,
+#  January 14, Alaska Standard Time.)  This resolution was passed with
+#  three votes for and one against."
+
+# Hawaii
+#
+# From Arthur David Olson:
+# And then there's Hawaii.
+# DST was observed for one day in 1933;
+# standard time was changed by half an hour in 1947;
+# it's always standard as of 1986.
+#
+# From Paul Eggert:
+# Shanks says the 1933 experiment lasted for three weeks.  Go with Shanks.
+#
+Zone Pacific/Honolulu	-10:31:26 -	LMT	1900 Jan  1 12:00
+			-10:30	-	HST	1933 Apr 30 2:00
+			-10:30	1:00	HDT	1933 May 21 2:00
+			-10:30	US	H%sT	1947 Jun  8 2:00
+			-10:00	-	HST
+
+# Now we turn to US areas that have diverged from the consensus since 1970.
+
+# Arizona mostly uses MST.
+
+# From Paul Eggert (2002-10-20):
+#
+# The information in the rest of this paragraph is derived from the
+# 
+# Daylight Saving Time web page (2002-01-23) maintained by the
+# Arizona State Library, Archives and Public Records.
+# Between 1944-01-01 and 1944-04-01 the State of Arizona used standard
+# time, but by federal law railroads, airlines, bus lines, military
+# personnel, and some engaged in interstate commerce continued to
+# observe war (i.e., daylight saving) time.  The 1944-03-17 Phoenix
+# Gazette says that was the date the law changed, and that 04-01 was
+# the date the state's clocks would change.  In 1945 the State of
+# Arizona used standard time all year, again with exceptions only as
+# mandated by federal law.  Arizona observed DST in 1967, but Arizona
+# Laws 1968, ch. 183 (effective 1968-03-21) repealed DST.
+#
+# Shanks says the 1944 experiment came to an end on 1944-03-17.
+# Go with the Arizona State Library instead.
+
+Zone America/Phoenix	-7:28:18 -	LMT	1883 Nov 18 11:31:42
+			-7:00	US	M%sT	1944 Jan  1 00:01
+			-7:00	-	MST	1944 Apr  1 00:01
+			-7:00	US	M%sT	1944 Oct  1 00:01
+			-7:00	-	MST	1967
+			-7:00	US	M%sT	1968 Mar 21
+			-7:00	-	MST
+# From Arthur David Olson (1988-02-13):
+# A writer from the Inter Tribal Council of Arizona, Inc.,
+# notes in private correspondence dated 1987-12-28 that "Presently, only the
+# Navajo Nation participates in the Daylight Saving Time policy, due to its
+# large size and location in three states."  (The "only" means that other
+# tribal nations don't use DST.)
+
+Link America/Denver America/Shiprock
+
+# Southern Idaho (Ada, Adams, Bannock, Bear Lake, Bingham, Blaine,
+# Boise, Bonneville, Butte, Camas, Canyon, Caribou, Cassia, Clark,
+# Custer, Elmore, Franklin, Fremont, Gem, Gooding, Jefferson, Jerome,
+# Lemhi, Lincoln, Madison, Minidoka, Oneida, Owyhee, Payette, Power,
+# Teton, Twin Falls, Valley, Washington counties, and the southern
+# quarter of Idaho county) and eastern Oregon (most of Malheur County)
+# switched four weeks late in 1974.
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Boise	-7:44:49 -	LMT	1883 Nov 18 12:15:11
+			-8:00	US	P%sT	1923 May 13 2:00
+			-7:00	US	M%sT	1974
+			-7:00	-	MST	1974 Feb  3 2:00
+			-7:00	US	M%sT
+
+# Indiana
+#
+# For a map of Indiana's time zone regions, see:
+# 
+# What time is it in Indiana?
+#  (2006-03-01)
+#
+# From Paul Eggert (2007-08-17):
+# Since 1970, most of Indiana has been like America/Indiana/Indianapolis,
+# with the following exceptions:
+#
+# - Gibson, Jasper, Lake, LaPorte, Newton, Porter, Posey, Spencer,
+#   Vandenburgh, and Warrick counties have been like America/Chicago.
+#
+# - Dearborn and Ohio counties have been like America/New_York.
+#
+# - Clark, Floyd, and Harrison counties have been like
+#   America/Kentucky/Louisville.
+#
+# - Crawford, Daviess, Dubois, Knox, Martin, Perry, Pike, Pulaski, Starke,
+#   and Switzerland counties have their own time zone histories as noted below.
+#
+# Shanks partitioned Indiana into 345 regions, each with its own time history,
+# and wrote ``Even newspaper reports present contradictory information.''
+# Those Hoosiers!  Such a flighty and changeable people!
+# Fortunately, most of the complexity occurred before our cutoff date of 1970.
+#
+# Other than Indianapolis, the Indiana place names are so nondescript
+# that they would be ambiguous if we left them at the `America' level.
+# So we reluctantly put them all in a subdirectory `America/Indiana'.
+
+# From Paul Eggert (2005-08-16):
+# http://www.mccsc.edu/time.html says that Indiana will use DST starting 2006.
+
+# From Nathan Stratton Treadway (2006-03-30):
+# http://www.dot.gov/affairs/dot0406.htm [3705 B]
+# From Deborah Goldsmith (2006-01-18):
+# http://dmses.dot.gov/docimages/pdf95/382329_web.pdf [2.9 MB]
+# From Paul Eggert (2006-01-20):
+# It says "DOT is relocating the time zone boundary in Indiana to move Starke,
+# Pulaski, Knox, Daviess, Martin, Pike, Dubois, and Perry Counties from the
+# Eastern Time Zone to the Central Time Zone.... The effective date of
+# this rule is 2:OO a.m. EST Sunday, April 2, 2006, which is the
+# changeover date from standard time to Daylight Saving Time."
+# Strictly speaking, this means the affected counties will change their
+# clocks twice that night, but this obviously is in error.  The intent
+# is that 01:59:59 EST be followed by 02:00:00 CDT.
+
+# From Gwillim Law (2007-02-10):
+# The Associated Press has been reporting that Pulaski County, Indiana is
+# going to switch from Central to Eastern Time on March 11, 2007....
+# http://www.indystar.com/apps/pbcs.dll/article?AID=/20070207/LOCAL190108/702070524/0/LOCAL
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule Indianapolis 1941	only	-	Jun	22	2:00	1:00	D
+Rule Indianapolis 1941	1954	-	Sep	lastSun	2:00	0	S
+Rule Indianapolis 1946	1954	-	Apr	lastSun	2:00	1:00	D
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Indiana/Indianapolis -5:44:38 - LMT 1883 Nov 18 12:15:22
+			-6:00	US	C%sT	1920
+			-6:00 Indianapolis C%sT	1942
+			-6:00	US	C%sT	1946
+			-6:00 Indianapolis C%sT	1955 Apr 24 2:00
+			-5:00	-	EST	1957 Sep 29 2:00
+			-6:00	-	CST	1958 Apr 27 2:00
+			-5:00	-	EST	1969
+			-5:00	US	E%sT	1971
+			-5:00	-	EST	2006
+			-5:00	US	E%sT
+#
+# Eastern Crawford County, Indiana, left its clocks alone in 1974,
+# as well as from 1976 through 2005.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule	Marengo	1951	only	-	Apr	lastSun	2:00	1:00	D
+Rule	Marengo	1951	only	-	Sep	lastSun	2:00	0	S
+Rule	Marengo	1954	1960	-	Apr	lastSun	2:00	1:00	D
+Rule	Marengo	1954	1960	-	Sep	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Indiana/Marengo -5:45:23 -	LMT	1883 Nov 18 12:14:37
+			-6:00	US	C%sT	1951
+			-6:00	Marengo	C%sT	1961 Apr 30 2:00
+			-5:00	-	EST	1969
+			-5:00	US	E%sT	1974 Jan  6 2:00
+			-6:00	1:00	CDT	1974 Oct 27 2:00
+			-5:00	US	E%sT	1976
+			-5:00	-	EST	2006
+			-5:00	US	E%sT
+#
+# Daviess, Dubois, Knox, and Martin Counties, Indiana,
+# switched from eastern to central time in April 2006, then switched back
+# in November 2007.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule Vincennes	1946	only	-	Apr	lastSun	2:00	1:00	D
+Rule Vincennes	1946	only	-	Sep	lastSun	2:00	0	S
+Rule Vincennes	1953	1954	-	Apr	lastSun	2:00	1:00	D
+Rule Vincennes	1953	1959	-	Sep	lastSun	2:00	0	S
+Rule Vincennes	1955	only	-	May	 1	0:00	1:00	D
+Rule Vincennes	1956	1963	-	Apr	lastSun	2:00	1:00	D
+Rule Vincennes	1960	only	-	Oct	lastSun	2:00	0	S
+Rule Vincennes	1961	only	-	Sep	lastSun	2:00	0	S
+Rule Vincennes	1962	1963	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Indiana/Vincennes -5:50:07 - LMT	1883 Nov 18 12:09:53
+			-6:00	US	C%sT	1946
+			-6:00 Vincennes	C%sT	1964 Apr 26 2:00
+			-5:00	-	EST	1969
+			-5:00	US	E%sT	1971
+			-5:00	-	EST	2006 Apr  2 2:00
+			-6:00	US	C%sT	2007 Nov  4 2:00
+			-5:00	US	E%sT
+#
+# Perry County, Indiana, switched from eastern to central time in April 2006.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule Perry	1946	only	-	Apr	lastSun	2:00	1:00	D
+Rule Perry	1946	only	-	Sep	lastSun	2:00	0	S
+Rule Perry	1953	1954	-	Apr	lastSun	2:00	1:00	D
+Rule Perry	1953	1959	-	Sep	lastSun	2:00	0	S
+Rule Perry	1955	only	-	May	 1	0:00	1:00	D
+Rule Perry	1956	1963	-	Apr	lastSun	2:00	1:00	D
+Rule Perry	1960	only	-	Oct	lastSun	2:00	0	S
+Rule Perry	1961	only	-	Sep	lastSun	2:00	0	S
+Rule Perry	1962	1963	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Indiana/Tell_City -5:47:03 - LMT	1883 Nov 18 12:12:57
+			-6:00	US	C%sT	1946
+			-6:00 Perry	C%sT	1964 Apr 26 2:00
+			-5:00	-	EST	1969
+			-5:00	US	E%sT	1971
+			-5:00	-	EST	2006 Apr  2 2:00
+			-6:00	US	C%sT
+#
+# Pike County, Indiana moved from central to eastern time in 1977,
+# then switched back in 2006, then switched back again in 2007.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule	Pike	1955	only	-	May	 1	0:00	1:00	D
+Rule	Pike	1955	1960	-	Sep	lastSun	2:00	0	S
+Rule	Pike	1956	1964	-	Apr	lastSun	2:00	1:00	D
+Rule	Pike	1961	1964	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Indiana/Petersburg -5:49:07 - LMT	1883 Nov 18 12:10:53
+			-6:00	US	C%sT	1955
+			-6:00	Pike	C%sT	1965 Apr 25 2:00
+			-5:00	-	EST	1966 Oct 30 2:00
+			-6:00	US	C%sT	1977 Oct 30 2:00
+			-5:00	-	EST	2006 Apr  2 2:00
+			-6:00	US	C%sT	2007 Nov  4 2:00
+			-5:00	US	E%sT
+#
+# Starke County, Indiana moved from central to eastern time in 1991,
+# then switched back in 2006.
+# From Arthur David Olson (1991-10-28):
+# An article on page A3 of the Sunday, 1991-10-27 Washington Post
+# notes that Starke County switched from Central time to Eastern time as of
+# 1991-10-27.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule	Starke	1947	1961	-	Apr	lastSun	2:00	1:00	D
+Rule	Starke	1947	1954	-	Sep	lastSun	2:00	0	S
+Rule	Starke	1955	1956	-	Oct	lastSun	2:00	0	S
+Rule	Starke	1957	1958	-	Sep	lastSun	2:00	0	S
+Rule	Starke	1959	1961	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Indiana/Knox -5:46:30 -	LMT	1883 Nov 18 12:13:30
+			-6:00	US	C%sT	1947
+			-6:00	Starke	C%sT	1962 Apr 29 2:00
+			-5:00	-	EST	1963 Oct 27 2:00
+			-6:00	US	C%sT	1991 Oct 27 2:00
+			-5:00	-	EST	2006 Apr  2 2:00
+			-6:00	US	C%sT
+#
+# Pulaski County, Indiana, switched from eastern to central time in
+# April 2006 and then switched back in March 2007.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule	Pulaski	1946	1960	-	Apr	lastSun	2:00	1:00	D
+Rule	Pulaski	1946	1954	-	Sep	lastSun	2:00	0	S
+Rule	Pulaski	1955	1956	-	Oct	lastSun	2:00	0	S
+Rule	Pulaski	1957	1960	-	Sep	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Indiana/Winamac -5:46:25 - LMT	1883 Nov 18 12:13:35
+			-6:00	US	C%sT	1946
+			-6:00	Pulaski	C%sT	1961 Apr 30 2:00
+			-5:00	-	EST	1969
+			-5:00	US	E%sT	1971
+			-5:00	-	EST	2006 Apr  2 2:00
+			-6:00	US	C%sT	2007 Mar 11 2:00
+			-5:00	US	E%sT
+#
+# Switzerland County, Indiana, did not observe DST from 1973 through 2005.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Indiana/Vevay -5:40:16 -	LMT	1883 Nov 18 12:19:44
+			-6:00	US	C%sT	1954 Apr 25 2:00
+			-5:00	-	EST	1969
+			-5:00	US	E%sT	1973
+			-5:00	-	EST	2006
+			-5:00	US	E%sT
+
+# Part of Kentucky left its clocks alone in 1974.
+# This also includes Clark, Floyd, and Harrison counties in Indiana.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule Louisville	1921	only	-	May	1	2:00	1:00	D
+Rule Louisville	1921	only	-	Sep	1	2:00	0	S
+Rule Louisville	1941	1961	-	Apr	lastSun	2:00	1:00	D
+Rule Louisville	1941	only	-	Sep	lastSun	2:00	0	S
+Rule Louisville	1946	only	-	Jun	2	2:00	0	S
+Rule Louisville	1950	1955	-	Sep	lastSun	2:00	0	S
+Rule Louisville	1956	1960	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Kentucky/Louisville -5:43:02 -	LMT	1883 Nov 18 12:16:58
+			-6:00	US	C%sT	1921
+			-6:00 Louisville C%sT	1942
+			-6:00	US	C%sT	1946
+			-6:00 Louisville C%sT	1961 Jul 23 2:00
+			-5:00	-	EST	1968
+			-5:00	US	E%sT	1974 Jan  6 2:00
+			-6:00	1:00	CDT	1974 Oct 27 2:00
+			-5:00	US	E%sT
+#
+# Wayne County, Kentucky
+#
+# From
+# 
+# Lake Cumberland LIFE
+#  (1999-01-29) via WKYM-101.7:
+# Clinton County has joined Wayne County in asking the DoT to change from
+# the Central to the Eastern time zone....  The Wayne County government made
+# the same request in December.  And while Russell County officials have not
+# taken action, the majority of respondents to a poll conducted there in
+# August indicated they would like to change to "fast time" also.
+# The three Lake Cumberland counties are the farthest east of any U.S.
+# location in the Central time zone.
+#
+# From Rich Wales (2000-08-29):
+# After prolonged debate, and despite continuing deep differences of opinion,
+# Wayne County (central Kentucky) is switching from Central (-0600) to Eastern
+# (-0500) time.  They won't "fall back" this year.  See Sara Shipley,
+# The difference an hour makes, Nando Times (2000-08-29 15:33 -0400).
+#
+# From Paul Eggert (2001-07-16):
+# The final rule was published in the
+# 
+# Federal Register 65, 160 (2000-08-17), page 50154-50158.
+# 
+#
+Zone America/Kentucky/Monticello -5:39:24 - LMT	1883 Nov 18 12:20:36
+			-6:00	US	C%sT	1946
+			-6:00	-	CST	1968
+			-6:00	US	C%sT	2000 Oct 29  2:00
+			-5:00	US	E%sT
+
+
+# From Rives McDow (2000-08-30):
+# Here ... are all the changes in the US since 1985.
+# Kearny County, KS (put all of county on central;
+#	previously split between MST and CST) ... 1990-10
+# Starke County, IN (from CST to EST) ... 1991-10
+# Oliver County, ND (from MST to CST) ... 1992-10
+# West Wendover, NV (from PST TO MST) ... 1999-10
+# Wayne County, KY (from CST to EST) ... 2000-10
+#
+# From Paul Eggert (2001-07-17):
+# We don't know where the line used to be within Kearny County, KS,
+# so omit that change for now.
+# See America/Indiana/Knox for the Starke County, IN change.
+# See America/North_Dakota/Center for the Oliver County, ND change.
+# West Wendover, NV officially switched from Pacific to mountain time on
+# 1999-10-31.  See the
+# 
+# Federal Register 64, 203 (1999-10-21), page 56705-56707.
+# 
+# However, the Federal Register says that West Wendover already operated
+# on mountain time, and the rule merely made this official;
+# hence a separate tz entry is not needed.
+
+# Michigan
+#
+# From Bob Devine (1988-01-28):
+# Michigan didn't observe DST from 1968 to 1973.
+#
+# From Paul Eggert (1999-03-31):
+# Shanks writes that Michigan started using standard time on 1885-09-18,
+# but Howse writes (pp 124-125, referring to Popular Astronomy, 1901-01)
+# that Detroit kept
+#
+#	local time until 1900 when the City Council decreed that clocks should
+#	be put back twenty-eight minutes to Central Standard Time.  Half the
+#	city obeyed, half refused.  After considerable debate, the decision
+#	was rescinded and the city reverted to Sun time.  A derisive offer to
+#	erect a sundial in front of the city hall was referred to the
+#	Committee on Sewers.  Then, in 1905, Central time was adopted
+#	by city vote.
+#
+# This story is too entertaining to be false, so go with Howse over Shanks.
+#
+# From Paul Eggert (2001-03-06):
+# Garland (1927) writes ``Cleveland and Detroit advanced their clocks
+# one hour in 1914.''  This change is not in Shanks.  We have no more
+# info, so omit this for now.
+#
+# Most of Michigan observed DST from 1973 on, but was a bit late in 1975.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule	Detroit	1948	only	-	Apr	lastSun	2:00	1:00	D
+Rule	Detroit	1948	only	-	Sep	lastSun	2:00	0	S
+Rule	Detroit	1967	only	-	Jun	14	2:00	1:00	D
+Rule	Detroit	1967	only	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Detroit	-5:32:11 -	LMT	1905
+			-6:00	-	CST	1915 May 15 2:00
+			-5:00	-	EST	1942
+			-5:00	US	E%sT	1946
+			-5:00	Detroit	E%sT	1973
+			-5:00	US	E%sT	1975
+			-5:00	-	EST	1975 Apr 27 2:00
+			-5:00	US	E%sT
+#
+# Dickinson, Gogebic, Iron, and Menominee Counties, Michigan,
+# switched from EST to CST/CDT in 1973.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
+Rule Menominee	1946	only	-	Apr	lastSun	2:00	1:00	D
+Rule Menominee	1946	only	-	Sep	lastSun	2:00	0	S
+Rule Menominee	1966	only	-	Apr	lastSun	2:00	1:00	D
+Rule Menominee	1966	only	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
+			-6:00	US	C%sT	1946
+			-6:00 Menominee	C%sT	1969 Apr 27 2:00
+			-5:00	-	EST	1973 Apr 29 2:00
+			-6:00	US	C%sT
+
+# Navassa
+# administered by the US Fish and Wildlife Service
+# claimed by US under the provisions of the 1856 Guano Islands Act
+# also claimed by Haiti
+# occupied 1857/1900 by the Navassa Phosphate Co
+# US lighthouse 1917/1996-09
+# currently uninhabited
+# see Mark Fineman, ``An Isle Rich in Guano and Discord'',
+# _Los Angeles Times_ (1998-11-10), A1, A10; it cites
+# Jimmy Skaggs, _The Great Guano Rush_ (1994).
+
+################################################################################
+
+
+# From Paul Eggert (2006-03-22):
+# A good source for time zone historical data outside the U.S. is
+# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
+# San Diego: ACS Publications, Inc. (2003).
+#
+# Gwillim Law writes that a good source
+# for recent time zone data is the International Air Transport
+# Association's Standard Schedules Information Manual (IATA SSIM),
+# published semiannually.  Law sent in several helpful summaries
+# of the IATA's data after 1990.
+#
+# Except where otherwise noted, Shanks & Pottenger is the source for
+# entries through 1990, and IATA SSIM is the source for entries afterwards.
+#
+# Other sources occasionally used include:
+#
+#	Edward W. Whitman, World Time Differences,
+#	Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
+#	which I found in the UCLA library.
+#
+#	
+#	William Willett, The Waste of Daylight, 19th edition
+#	 (1914-03)
+#
+# See the `europe' file for Greenland.
+
+# Canada
+
+# From Alain LaBont (1994-11-14):
+# I post here the time zone abbreviations standardized in Canada
+# for both English and French in the CAN/CSA-Z234.4-89 standard....
+#
+#	UTC	Standard time	Daylight savings time
+#	offset	French	English	French	English
+#	-2:30	-	-	HAT	NDT
+#	-3	-	-	HAA	ADT
+#	-3:30	HNT	NST	-	-
+#	-4	HNA	AST	HAE	EDT
+#	-5	HNE	EST	HAC	CDT
+#	-6	HNC	CST	HAR	MDT
+#	-7	HNR	MST	HAP	PDT
+#	-8	HNP	PST	HAY	YDT
+#	-9	HNY	YST	-	-
+#
+#	HN: Heure Normale	ST: Standard Time
+#	HA: Heure Avance	DT: Daylight saving Time
+#
+#	A: de l'Atlantique	Atlantic
+#	C: du Centre		Central
+#	E: de l'Est		Eastern
+#	M:			Mountain
+#	N:			Newfoundland
+#	P: du Pacifique		Pacific
+#	R: des Rocheuses
+#	T: de Terre-Neuve
+#	Y: du Yukon		Yukon
+#
+# From Paul Eggert (1994-11-22):
+# Alas, this sort of thing must be handled by localization software.
+
+# Unless otherwise specified, the data for Canada are all from Shanks
+# & Pottenger.
+
+# From Chris Walton (2006-04-01, 2006-04-25, 2006-06-26, 2007-01-31,
+# 2007-03-01):
+# The British Columbia government announced yesterday that it will
+# adjust daylight savings next year to align with changes in the
+# U.S. and the rest of Canada....
+# http://www2.news.gov.bc.ca/news_releases_2005-2009/2006AG0014-000330.htm
+# ...
+# Nova Scotia
+# Daylight saving time will be extended by four weeks starting in 2007....
+# http://www.gov.ns.ca/just/regulations/rg2/2006/ma1206.pdf
+#
+# [For New Brunswick] the new legislation dictates that the time change is to
+# be done at 02:00 instead of 00:01.
+# http://www.gnb.ca/0062/acts/BBA-2006/Chap-19.pdf
+# ...
+# Manitoba has traditionally changed the clock every fall at 03:00.
+# As of 2006, the transition is to take place one hour earlier at 02:00.
+# http://web2.gov.mb.ca/laws/statutes/ccsm/o030e.php
+# ...
+# [Alberta, Ontario, Quebec] will follow US rules.
+# http://www.qp.gov.ab.ca/documents/spring/CH03_06.CFM
+# http://www.e-laws.gov.on.ca/DBLaws/Source/Regs/English/2006/R06111_e.htm
+# http://www2.publicationsduquebec.gouv.qc.ca/dynamicSearch/telecharge.php?type=5&file=2006C39A.PDF
+# ...
+# P.E.I. will follow US rules....
+# http://www.assembly.pe.ca/bills/pdf_chapter/62/3/chapter-41.pdf
+# ...
+# Province of Newfoundland and Labrador....
+# http://www.hoa.gov.nl.ca/hoa/bills/Bill0634.htm
+# ...
+# Yukon
+# http://www.gov.yk.ca/legislation/regs/oic2006_127.pdf
+# ...
+# N.W.T. will follow US rules.  Whoever maintains the government web site
+# does not seem to believe in bookmarks.  To see the news release, click the
+# following link and search for "Daylight Savings Time Change".  Press the
+# "Daylight Savings Time Change" link; it will fire off a popup using
+# JavaScript.
+# http://www.exec.gov.nt.ca/currentnews/currentPR.asp?mode=archive
+# ...
+# Nunavut
+# An amendment to the Interpretation Act was registered on February 19/2007....
+# http://action.attavik.ca/home/justice-gn/attach/2007/gaz02part2.pdf
+
+# From Paul Eggert (2006-04-25):
+# H. David Matthews and Mary Vincent's map
+# 
+# "It's about TIME", _Canadian Geographic_ (September-October 1998)
+#  contains detailed boundaries for regions observing nonstandard
+# time and daylight saving time arrangements in Canada circa 1998.
+#
+# INMS, the Institute for National Measurement Standards in Ottawa, has 
+# information about standard and daylight saving time zones in Canada.
+#  (updated periodically).
+# Its unofficial information is often taken from Matthews and Vincent.
+
+# From Paul Eggert (2006-06-27):
+# For now, assume all of DST-observing Canada will fall into line with the
+# new US DST rules,
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Canada	1918	only	-	Apr	14	2:00	1:00	D
+Rule	Canada	1918	only	-	Oct	31	2:00	0	S
+Rule	Canada	1942	only	-	Feb	 9	2:00	1:00	W # War
+Rule	Canada	1945	only	-	Aug	14	23:00u	1:00	P # Peace
+Rule	Canada	1945	only	-	Sep	30	2:00	0	S
+Rule	Canada	1974	1986	-	Apr	lastSun	2:00	1:00	D
+Rule	Canada	1974	2006	-	Oct	lastSun	2:00	0	S
+Rule	Canada	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
+Rule	Canada	2007	max	-	Mar	Sun>=8	2:00	1:00	D
+Rule	Canada	2007	max	-	Nov	Sun>=1	2:00	0	S
+
+
+# Newfoundland and Labrador
+
+# From Paul Eggert (2000-10-02):
+# Matthews and Vincent (1998) write that Labrador should use NST/NDT,
+# but the only part of Labrador that follows the rules is the
+# southeast corner, including Port Hope Simpson and Mary's Harbour,
+# but excluding, say, Black Tickle.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	StJohns	1917	only	-	Apr	 8	2:00	1:00	D
+Rule	StJohns	1917	only	-	Sep	17	2:00	0	S
+# Whitman gives 1919 Apr 5 and 1920 Apr 5; go with Shanks & Pottenger.
+Rule	StJohns	1919	only	-	May	 5	23:00	1:00	D
+Rule	StJohns	1919	only	-	Aug	12	23:00	0	S
+# For 1931-1935 Whitman gives Apr same date; go with Shanks & Pottenger.
+Rule	StJohns	1920	1935	-	May	Sun>=1	23:00	1:00	D
+Rule	StJohns	1920	1935	-	Oct	lastSun	23:00	0	S
+# For 1936-1941 Whitman gives May Sun>=8 and Oct Sun>=1; go with Shanks &
+# Pottenger.
+Rule	StJohns	1936	1941	-	May	Mon>=9	0:00	1:00	D
+Rule	StJohns	1936	1941	-	Oct	Mon>=2	0:00	0	S
+# Whitman gives the following transitions:
+# 1942 03-01/12-31, 1943 05-30/09-05, 1944 07-10/09-02, 1945 01-01/10-07
+# but go with Shanks & Pottenger and assume they used Canadian rules.
+# For 1946-9 Whitman gives May 5,4,9,1 - Oct 1,5,3,2, and for 1950 he gives
+# Apr 30 - Sep 24; go with Shanks & Pottenger.
+Rule	StJohns	1946	1950	-	May	Sun>=8	2:00	1:00	D
+Rule	StJohns	1946	1950	-	Oct	Sun>=2	2:00	0	S
+Rule	StJohns	1951	1986	-	Apr	lastSun	2:00	1:00	D
+Rule	StJohns	1951	1959	-	Sep	lastSun	2:00	0	S
+Rule	StJohns	1960	1986	-	Oct	lastSun	2:00	0	S
+# From Paul Eggert (2000-10-02):
+# INMS (2000-09-12) says that, since 1988 at least, Newfoundland switches
+# at 00:01 local time.  For now, assume it started in 1987.
+Rule	StJohns	1987	only	-	Apr	Sun>=1	0:01	1:00	D
+Rule	StJohns	1987	2006	-	Oct	lastSun	0:01	0	S
+Rule	StJohns	1988	only	-	Apr	Sun>=1	0:01	2:00	DD
+Rule	StJohns	1989	2006	-	Apr	Sun>=1	0:01	1:00	D
+Rule	StJohns	2007	max	-	Mar	Sun>=8	0:01	1:00	D
+Rule	StJohns	2007	max	-	Nov	Sun>=1	0:01	0	S
+#
+# St John's has an apostrophe, but Posix file names can't have apostrophes.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/St_Johns	-3:30:52 -	LMT	1884
+			-3:30:52 StJohns N%sT	1918
+			-3:30:52 Canada	N%sT	1919
+			-3:30:52 StJohns N%sT	1935 Mar 30
+			-3:30	StJohns	N%sT	1942 May 11
+			-3:30	Canada	N%sT	1946
+			-3:30	StJohns	N%sT
+
+# most of east Labrador
+
+# The name `Happy Valley-Goose Bay' is too long; use `Goose Bay'.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Goose_Bay	-4:01:40 -	LMT	1884 # Happy Valley-Goose Bay
+			-3:30:52 -	NST	1918
+			-3:30:52 Canada N%sT	1919
+			-3:30:52 -	NST	1935 Mar 30
+			-3:30	-	NST	1936
+			-3:30	StJohns	N%sT	1942 May 11
+			-3:30	Canada	N%sT	1946
+			-3:30	StJohns	N%sT	1966 Mar 15 2:00
+			-4:00	StJohns	A%sT
+
+
+# west Labrador, Nova Scotia, Prince Edward I
+
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger write that since 1970 most of this region has been like
+# Halifax.  Many locales did not observe peacetime DST until 1972;
+# Glace Bay, NS is the largest that we know of.
+# Shanks & Pottenger also write that Liverpool, NS was the only town
+# in Canada to observe DST in 1971 but not 1970; for now we'll assume
+# this is a typo.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Halifax	1916	only	-	Apr	 1	0:00	1:00	D
+Rule	Halifax	1916	only	-	Oct	 1	0:00	0	S
+Rule	Halifax	1920	only	-	May	 9	0:00	1:00	D
+Rule	Halifax	1920	only	-	Aug	29	0:00	0	S
+Rule	Halifax	1921	only	-	May	 6	0:00	1:00	D
+Rule	Halifax	1921	1922	-	Sep	 5	0:00	0	S
+Rule	Halifax	1922	only	-	Apr	30	0:00	1:00	D
+Rule	Halifax	1923	1925	-	May	Sun>=1	0:00	1:00	D
+Rule	Halifax	1923	only	-	Sep	 4	0:00	0	S
+Rule	Halifax	1924	only	-	Sep	15	0:00	0	S
+Rule	Halifax	1925	only	-	Sep	28	0:00	0	S
+Rule	Halifax	1926	only	-	May	16	0:00	1:00	D
+Rule	Halifax	1926	only	-	Sep	13	0:00	0	S
+Rule	Halifax	1927	only	-	May	 1	0:00	1:00	D
+Rule	Halifax	1927	only	-	Sep	26	0:00	0	S
+Rule	Halifax	1928	1931	-	May	Sun>=8	0:00	1:00	D
+Rule	Halifax	1928	only	-	Sep	 9	0:00	0	S
+Rule	Halifax	1929	only	-	Sep	 3	0:00	0	S
+Rule	Halifax	1930	only	-	Sep	15	0:00	0	S
+Rule	Halifax	1931	1932	-	Sep	Mon>=24	0:00	0	S
+Rule	Halifax	1932	only	-	May	 1	0:00	1:00	D
+Rule	Halifax	1933	only	-	Apr	30	0:00	1:00	D
+Rule	Halifax	1933	only	-	Oct	 2	0:00	0	S
+Rule	Halifax	1934	only	-	May	20	0:00	1:00	D
+Rule	Halifax	1934	only	-	Sep	16	0:00	0	S
+Rule	Halifax	1935	only	-	Jun	 2	0:00	1:00	D
+Rule	Halifax	1935	only	-	Sep	30	0:00	0	S
+Rule	Halifax	1936	only	-	Jun	 1	0:00	1:00	D
+Rule	Halifax	1936	only	-	Sep	14	0:00	0	S
+Rule	Halifax	1937	1938	-	May	Sun>=1	0:00	1:00	D
+Rule	Halifax	1937	1941	-	Sep	Mon>=24	0:00	0	S
+Rule	Halifax	1939	only	-	May	28	0:00	1:00	D
+Rule	Halifax	1940	1941	-	May	Sun>=1	0:00	1:00	D
+Rule	Halifax	1946	1949	-	Apr	lastSun	2:00	1:00	D
+Rule	Halifax	1946	1949	-	Sep	lastSun	2:00	0	S
+Rule	Halifax	1951	1954	-	Apr	lastSun	2:00	1:00	D
+Rule	Halifax	1951	1954	-	Sep	lastSun	2:00	0	S
+Rule	Halifax	1956	1959	-	Apr	lastSun	2:00	1:00	D
+Rule	Halifax	1956	1959	-	Sep	lastSun	2:00	0	S
+Rule	Halifax	1962	1973	-	Apr	lastSun	2:00	1:00	D
+Rule	Halifax	1962	1973	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Halifax	-4:14:24 -	LMT	1902 Jun 15
+			-4:00	Halifax	A%sT	1918
+			-4:00	Canada	A%sT	1919
+			-4:00	Halifax	A%sT	1942 Feb  9 2:00s
+			-4:00	Canada	A%sT	1946
+			-4:00	Halifax	A%sT	1974
+			-4:00	Canada	A%sT
+Zone America/Glace_Bay	-3:59:48 -	LMT	1902 Jun 15
+			-4:00	Canada	A%sT	1953
+			-4:00	Halifax	A%sT	1954
+			-4:00	-	AST	1972
+			-4:00	Halifax	A%sT	1974
+			-4:00	Canada	A%sT
+
+# New Brunswick
+
+# From Paul Eggert (2007-01-31):
+# The Time Definition Act 
+# says they changed at 00:01 through 2006, and
+#  makes it
+# clear that this was the case since at least 1993.
+# For now, assume it started in 1993.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Moncton	1933	1935	-	Jun	Sun>=8	1:00	1:00	D
+Rule	Moncton	1933	1935	-	Sep	Sun>=8	1:00	0	S
+Rule	Moncton	1936	1938	-	Jun	Sun>=1	1:00	1:00	D
+Rule	Moncton	1936	1938	-	Sep	Sun>=1	1:00	0	S
+Rule	Moncton	1939	only	-	May	27	1:00	1:00	D
+Rule	Moncton	1939	1941	-	Sep	Sat>=21	1:00	0	S
+Rule	Moncton	1940	only	-	May	19	1:00	1:00	D
+Rule	Moncton	1941	only	-	May	 4	1:00	1:00	D
+Rule	Moncton	1946	1972	-	Apr	lastSun	2:00	1:00	D
+Rule	Moncton	1946	1956	-	Sep	lastSun	2:00	0	S
+Rule	Moncton	1957	1972	-	Oct	lastSun	2:00	0	S
+Rule	Moncton	1993	2006	-	Apr	Sun>=1	0:01	1:00	D
+Rule	Moncton	1993	2006	-	Oct	lastSun	0:01	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Moncton	-4:19:08 -	LMT	1883 Dec  9
+			-5:00	-	EST	1902 Jun 15
+			-4:00	Canada	A%sT	1933
+			-4:00	Moncton	A%sT	1942
+			-4:00	Canada	A%sT	1946
+			-4:00	Moncton	A%sT	1973
+			-4:00	Canada	A%sT	1993
+			-4:00	Moncton	A%sT	2007
+			-4:00	Canada	A%sT
+
+# Quebec
+
+# From Paul Eggert (2006-07-09):
+# Shanks & Pottenger write that since 1970 most of Quebec has been
+# like Montreal.
+
+# From Paul Eggert (2006-06-27):
+# Matthews and Vincent (1998) also write that Quebec east of the -63
+# meridian is supposed to observe AST, but residents as far east as
+# Natashquan use EST/EDT, and residents east of Natashquan use AST.
+# In "Official time in Quebec" the Quebec department of justice writes in
+# http://www.justice.gouv.qc.ca/english/publications/generale/temps-regl-1-a.htm
+# that "The residents of the Municipality of the
+# Cote-Nord-du-Golfe-Saint-Laurent and the municipalities of Saint-Augustin,
+# Bonne-Esperance and Blanc-Sablon apply the Official Time Act as it is
+# written and use Atlantic standard time all year round. The same applies to
+# the residents of the Native facilities along the lower North Shore."
+# 
+# says this common practice was codified into law as of 2007.
+# For lack of better info, guess this practice began around 1970, contra to
+# Shanks & Pottenger who have this region observing AST/ADT.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Mont	1917	only	-	Mar	25	2:00	1:00	D
+Rule	Mont	1917	only	-	Apr	24	0:00	0	S
+Rule	Mont	1919	only	-	Mar	31	2:30	1:00	D
+Rule	Mont	1919	only	-	Oct	25	2:30	0	S
+Rule	Mont	1920	only	-	May	 2	2:30	1:00	D
+Rule	Mont	1920	1922	-	Oct	Sun>=1	2:30	0	S
+Rule	Mont	1921	only	-	May	 1	2:00	1:00	D
+Rule	Mont	1922	only	-	Apr	30	2:00	1:00	D
+Rule	Mont	1924	only	-	May	17	2:00	1:00	D
+Rule	Mont	1924	1926	-	Sep	lastSun	2:30	0	S
+Rule	Mont	1925	1926	-	May	Sun>=1	2:00	1:00	D
+# The 1927-to-1937 rules can be expressed more simply as
+# Rule	Mont	1927	1937	-	Apr	lastSat	24:00	1:00	D
+# Rule	Mont	1927	1937	-	Sep	lastSat	24:00	0	S
+# The rules below avoid use of 24:00
+# (which pre-1998 versions of zic cannot handle).
+Rule	Mont	1927	only	-	May	1	0:00	1:00	D
+Rule	Mont	1927	1932	-	Sep	lastSun	0:00	0	S
+Rule	Mont	1928	1931	-	Apr	lastSun	0:00	1:00	D
+Rule	Mont	1932	only	-	May	1	0:00	1:00	D
+Rule	Mont	1933	1940	-	Apr	lastSun	0:00	1:00	D
+Rule	Mont	1933	only	-	Oct	1	0:00	0	S
+Rule	Mont	1934	1939	-	Sep	lastSun	0:00	0	S
+Rule	Mont	1946	1973	-	Apr	lastSun	2:00	1:00	D
+Rule	Mont	1945	1948	-	Sep	lastSun	2:00	0	S
+Rule	Mont	1949	1950	-	Oct	lastSun	2:00	0	S
+Rule	Mont	1951	1956	-	Sep	lastSun	2:00	0	S
+Rule	Mont	1957	1973	-	Oct	lastSun	2:00	0	S
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Blanc-Sablon -3:48:28 -	LMT	1884
+			-4:00	Canada	A%sT	1970
+			-4:00	-	AST
+Zone America/Montreal	-4:54:16 -	LMT	1884
+			-5:00	Mont	E%sT	1918
+			-5:00	Canada	E%sT	1919
+			-5:00	Mont	E%sT	1942 Feb  9 2:00s
+			-5:00	Canada	E%sT	1946
+			-5:00	Mont	E%sT	1974
+			-5:00	Canada	E%sT
+
+
+# Ontario
+
+# From Paul Eggert (2006-07-09):
+# Shanks & Pottenger write that since 1970 most of Ontario has been like
+# Toronto.
+# Thunder Bay skipped DST in 1973.
+# Many smaller locales did not observe peacetime DST until 1974;
+# Nipigon (EST) and Rainy River (CST) are the largest that we know of.
+# Far west Ontario is like Winnipeg; far east Quebec is like Halifax.
+
+# From Mark Brader (2003-07-26):
+# [According to the Toronto Star] Orillia, Ontario, adopted DST
+# effective Saturday, 1912-06-22, 22:00; the article mentions that
+# Port Arthur (now part of Thunder Bay, Ontario) as well as Moose Jaw
+# have already done so.  In Orillia DST was to run until Saturday,
+# 1912-08-31 (no time mentioned), but it was met with considerable
+# hostility from certain segments of the public, and was revoked after
+# only two weeks -- I copied it as Saturday, 1912-07-07, 22:00, but
+# presumably that should be -07-06.  (1912-06-19, -07-12; also letters
+# earlier in June).
+#
+# Kenora, Ontario, was to abandon DST on 1914-06-01 (-05-21).
+
+# From Paul Eggert (1997-10-17):
+# Mark Brader writes that an article in the 1997-10-14 Toronto Star
+# says that Atikokan, Ontario currently does not observe DST,
+# but will vote on 11-10 whether to use EST/EDT.
+# He also writes that the
+# 
+# Ontario Time Act (1990, Chapter T.9)
+# 
+# says that Ontario east of 90W uses EST/EDT, and west of 90W uses CST/CDT.
+# Officially Atikokan is therefore on CST/CDT, and most likely this report
+# concerns a non-official time observed as a matter of local practice.
+#
+# From Paul Eggert (2000-10-02):
+# Matthews and Vincent (1998) write that Atikokan, Pickle Lake, and
+# New Osnaburgh observe CST all year, that Big Trout Lake observes
+# CST/CDT, and that Upsala and Shebandowan observe EST/EDT, all in
+# violation of the official Ontario rules.
+#
+# From Paul Eggert (2006-07-09):
+# Chris Walton (2006-07-06) mentioned an article by Stephanie MacLellan in the
+# 2005-07-21 Chronicle-Journal, which said:
+#
+#	The clocks in Atikokan stay set on standard time year-round.
+#	This means they spend about half the time on central time and
+#	the other half on eastern time.
+#
+#	For the most part, the system works, Mayor Dennis Brown said.
+#
+#	"The majority of businesses in Atikokan deal more with Eastern
+#	Canada, but there are some that deal with Western Canada," he
+#	said.  "I don't see any changes happening here."
+#
+# Walton also writes "Supposedly Pickle Lake and Mishkeegogamang
+# [New Osnaburgh] follow the same practice."
+
+# From Garry McKinnon (2006-07-14) via Chris Walton:
+# I chatted with a member of my board who has an outstanding memory
+# and a long history in Atikokan (and in the telecom industry) and he
+# can say for certain that Atikokan has been practicing the current
+# time keeping since 1952, at least.
+
+# From Paul Eggert (2006-07-17):
+# Shanks & Pottenger say that Atikokan has agreed with Rainy River
+# ever since standard time was introduced, but the information from
+# McKinnon sounds more authoritative.  For now, assume that Atikokan
+# switched to EST immediately after WWII era daylight saving time
+# ended.  This matches the old (less-populous) America/Coral_Harbour
+# entry since our cutoff date of 1970, so we can move
+# America/Coral_Harbour to the 'backward' file.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Toronto	1919	only	-	Mar	30	23:30	1:00	D
+Rule	Toronto	1919	only	-	Oct	26	0:00	0	S
+Rule	Toronto	1920	only	-	May	 2	2:00	1:00	D
+Rule	Toronto	1920	only	-	Sep	26	0:00	0	S
+Rule	Toronto	1921	only	-	May	15	2:00	1:00	D
+Rule	Toronto	1921	only	-	Sep	15	2:00	0	S
+Rule	Toronto	1922	1923	-	May	Sun>=8	2:00	1:00	D
+# Shanks & Pottenger say 1923-09-19; assume it's a typo and that "-16"
+# was meant.
+Rule	Toronto	1922	1926	-	Sep	Sun>=15	2:00	0	S
+Rule	Toronto	1924	1927	-	May	Sun>=1	2:00	1:00	D
+# The 1927-to-1939 rules can be expressed more simply as
+# Rule	Toronto	1927	1937	-	Sep	Sun>=25	2:00	0	S
+# Rule	Toronto	1928	1937	-	Apr	Sun>=25	2:00	1:00	D
+# Rule	Toronto	1938	1940	-	Apr	lastSun	2:00	1:00	D
+# Rule	Toronto	1938	1939	-	Sep	lastSun	2:00	0	S
+# The rules below avoid use of Sun>=25
+# (which pre-2004 versions of zic cannot handle).
+Rule	Toronto	1927	1932	-	Sep	lastSun	2:00	0	S
+Rule	Toronto	1928	1931	-	Apr	lastSun	2:00	1:00	D
+Rule	Toronto	1932	only	-	May	1	2:00	1:00	D
+Rule	Toronto	1933	1940	-	Apr	lastSun	2:00	1:00	D
+Rule	Toronto	1933	only	-	Oct	1	2:00	0	S
+Rule	Toronto	1934	1939	-	Sep	lastSun	2:00	0	S
+Rule	Toronto	1945	1946	-	Sep	lastSun	2:00	0	S
+Rule	Toronto	1946	only	-	Apr	lastSun	2:00	1:00	D
+Rule	Toronto	1947	1949	-	Apr	lastSun	0:00	1:00	D
+Rule	Toronto	1947	1948	-	Sep	lastSun	0:00	0	S
+Rule	Toronto	1949	only	-	Nov	lastSun	0:00	0	S
+Rule	Toronto	1950	1973	-	Apr	lastSun	2:00	1:00	D
+Rule	Toronto	1950	only	-	Nov	lastSun	2:00	0	S
+Rule	Toronto	1951	1956	-	Sep	lastSun	2:00	0	S
+# Shanks & Pottenger say Toronto ended DST a week early in 1971,
+# namely on 1971-10-24, but Mark Brader wrote (2003-05-31) that this
+# is wrong, and that he had confirmed it by checking the 1971-10-30
+# Toronto Star, which said that DST was ending 1971-10-31 as usual.
+Rule	Toronto	1957	1973	-	Oct	lastSun	2:00	0	S
+
+# From Paul Eggert (2003-07-27):
+# Willett (1914-03) writes (p. 17) "In the Cities of Fort William, and
+# Port Arthur, Ontario, the principle of the Bill has been in
+# operation for the past three years, and in the City of Moose Jaw,
+# Saskatchewan, for one year."
+
+# From David Bryan via Tory Tronrud, Director/Curator,
+# Thunder Bay Museum (2003-11-12):
+# There is some suggestion, however, that, by-law or not, daylight
+# savings time was being practiced in Fort William and Port Arthur
+# before 1909.... [I]n 1910, the line between the Eastern and Central
+# Time Zones was permanently moved about two hundred miles west to
+# include the Thunder Bay area....  When Canada adopted daylight
+# savings time in 1916, Fort William and Port Arthur, having done so
+# already, did not change their clocks....  During the Second World
+# War,... [t]he cities agreed to implement DST during the summer
+# months for the remainder of the war years.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Toronto	-5:17:32 -	LMT	1895
+			-5:00	Canada	E%sT	1919
+			-5:00	Toronto	E%sT	1942 Feb  9 2:00s
+			-5:00	Canada	E%sT	1946
+			-5:00	Toronto	E%sT	1974
+			-5:00	Canada	E%sT
+Zone America/Thunder_Bay -5:57:00 -	LMT	1895
+			-6:00	-	CST	1910
+			-5:00	-	EST	1942
+			-5:00	Canada	E%sT	1970
+			-5:00	Mont	E%sT	1973
+			-5:00	-	EST	1974
+			-5:00	Canada	E%sT
+Zone America/Nipigon	-5:53:04 -	LMT	1895
+			-5:00	Canada	E%sT	1940 Sep 29
+			-5:00	1:00	EDT	1942 Feb  9 2:00s
+			-5:00	Canada	E%sT
+Zone America/Rainy_River -6:18:16 -	LMT	1895
+			-6:00	Canada	C%sT	1940 Sep 29
+			-6:00	1:00	CDT	1942 Feb  9 2:00s
+			-6:00	Canada	C%sT
+Zone America/Atikokan	-6:06:28 -	LMT	1895
+			-6:00	Canada	C%sT	1940 Sep 29
+			-6:00	1:00	CDT	1942 Feb  9 2:00s
+			-6:00	Canada	C%sT	1945 Sep 30 2:00
+			-5:00	-	EST
+
+
+# Manitoba
+
+# From Rob Douglas (2006-04-06):
+# the old Manitoba Time Act - as amended by Bill 2, assented to
+# March 27, 1987 ... said ...
+# "between two o'clock Central Standard Time in the morning of
+# the first Sunday of April of each year and two o'clock Central
+# Standard Time in the morning of the last Sunday of October next
+# following, one hour in advance of Central Standard Time."...
+# I believe that the English legislation [of the old time act] had =
+# been assented to (March 22, 1967)....
+# Also, as far as I can tell, there was no order-in-council varying
+# the time of Daylight Saving Time for 2005 and so the provisions of
+# the 1987 version would apply - the changeover was at 2:00 Central
+# Standard Time (i.e. not until 3:00 Central Daylight Time).
+
+# From Paul Eggert (2006-04-10):
+# Shanks & Pottenger say Manitoba switched at 02:00 (not 02:00s)
+# starting 1966.  Since 02:00s is clearly correct for 1967 on, assume
+# it was also 02:00s in 1966.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Winn	1916	only	-	Apr	23	0:00	1:00	D
+Rule	Winn	1916	only	-	Sep	17	0:00	0	S
+Rule	Winn	1918	only	-	Apr	14	2:00	1:00	D
+Rule	Winn	1918	only	-	Oct	31	2:00	0	S
+Rule	Winn	1937	only	-	May	16	2:00	1:00	D
+Rule	Winn	1937	only	-	Sep	26	2:00	0	S
+Rule	Winn	1942	only	-	Feb	 9	2:00	1:00	W # War
+Rule	Winn	1945	only	-	Aug	14	23:00u	1:00	P # Peace
+Rule	Winn	1945	only	-	Sep	lastSun	2:00	0	S
+Rule	Winn	1946	only	-	May	12	2:00	1:00	D
+Rule	Winn	1946	only	-	Oct	13	2:00	0	S
+Rule	Winn	1947	1949	-	Apr	lastSun	2:00	1:00	D
+Rule	Winn	1947	1949	-	Sep	lastSun	2:00	0	S
+Rule	Winn	1950	only	-	May	 1	2:00	1:00	D
+Rule	Winn	1950	only	-	Sep	30	2:00	0	S
+Rule	Winn	1951	1960	-	Apr	lastSun	2:00	1:00	D
+Rule	Winn	1951	1958	-	Sep	lastSun	2:00	0	S
+Rule	Winn	1959	only	-	Oct	lastSun	2:00	0	S
+Rule	Winn	1960	only	-	Sep	lastSun	2:00	0	S
+Rule	Winn	1963	only	-	Apr	lastSun	2:00	1:00	D
+Rule	Winn	1963	only	-	Sep	22	2:00	0	S
+Rule	Winn	1966	1986	-	Apr	lastSun	2:00s	1:00	D
+Rule	Winn	1966	2005	-	Oct	lastSun	2:00s	0	S
+Rule	Winn	1987	2005	-	Apr	Sun>=1	2:00s	1:00	D
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Winnipeg	-6:28:36 -	LMT	1887 Jul 16
+			-6:00	Winn	C%sT	2006
+			-6:00	Canada	C%sT
+
+
+# Saskatchewan
+
+# From Mark Brader (2003-07-26):
+# The first actual adoption of DST in Canada was at the municipal
+# level.  As the [Toronto] Star put it (1912-06-07), "While people
+# elsewhere have long been talking of legislation to save daylight,
+# the city of Moose Jaw [Saskatchewan] has acted on its own hook."
+# DST in Moose Jaw began on Saturday, 1912-06-01 (no time mentioned:
+# presumably late evening, as below), and would run until "the end of
+# the summer".  The discrepancy between municipal time and railroad
+# time was noted.
+
+# From Paul Eggert (2003-07-27):
+# Willett (1914-03) notes that DST "has been in operation ... in the
+# City of Moose Jaw, Saskatchewan, for one year."
+
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger say that since 1970 this region has mostly been as Regina.
+# Some western towns (e.g. Swift Current) switched from MST/MDT to CST in 1972.
+# Other western towns (e.g. Lloydminster) are like Edmonton.
+# Matthews and Vincent (1998) write that Denare Beach and Creighton
+# are like Winnipeg, in violation of Saskatchewan law.
+
+# From W. Jones (1992-11-06):
+# The. . .below is based on information I got from our law library, the
+# provincial archives, and the provincial Community Services department.
+# A precise history would require digging through newspaper archives, and
+# since you didn't say what you wanted, I didn't bother.
+#
+# Saskatchewan is split by a time zone meridian (105W) and over the years
+# the boundary became pretty ragged as communities near it reevaluated
+# their affiliations in one direction or the other.  In 1965 a provincial
+# referendum favoured legislating common time practices.
+#
+# On 15 April 1966 the Time Act (c. T-14, Revised Statutes of
+# Saskatchewan 1978) was proclaimed, and established that the eastern
+# part of Saskatchewan would use CST year round, that districts in
+# northwest Saskatchewan would by default follow CST but could opt to
+# follow Mountain Time rules (thus 1 hour difference in the winter and
+# zero in the summer), and that districts in southwest Saskatchewan would
+# by default follow MT but could opt to follow CST.
+#
+# It took a few years for the dust to settle (I know one story of a town
+# on one time zone having its school in another, such that a mom had to
+# serve her family lunch in two shifts), but presently it seems that only
+# a few towns on the border with Alberta (e.g. Lloydminster) follow MT
+# rules any more; all other districts appear to have used CST year round
+# since sometime in the 1960s.
+
+# From Chris Walton (2006-06-26):
+# The Saskatchewan time act which was last updated in 1996 is about 30 pages
+# long and rather painful to read.
+# http://www.qp.gov.sk.ca/documents/English/Statutes/Statutes/T14.pdf
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Regina	1918	only	-	Apr	14	2:00	1:00	D
+Rule	Regina	1918	only	-	Oct	31	2:00	0	S
+Rule	Regina	1930	1934	-	May	Sun>=1	0:00	1:00	D
+Rule	Regina	1930	1934	-	Oct	Sun>=1	0:00	0	S
+Rule	Regina	1937	1941	-	Apr	Sun>=8	0:00	1:00	D
+Rule	Regina	1937	only	-	Oct	Sun>=8	0:00	0	S
+Rule	Regina	1938	only	-	Oct	Sun>=1	0:00	0	S
+Rule	Regina	1939	1941	-	Oct	Sun>=8	0:00	0	S
+Rule	Regina	1942	only	-	Feb	 9	2:00	1:00	W # War
+Rule	Regina	1945	only	-	Aug	14	23:00u	1:00	P # Peace
+Rule	Regina	1945	only	-	Sep	lastSun	2:00	0	S
+Rule	Regina	1946	only	-	Apr	Sun>=8	2:00	1:00	D
+Rule	Regina	1946	only	-	Oct	Sun>=8	2:00	0	S
+Rule	Regina	1947	1957	-	Apr	lastSun	2:00	1:00	D
+Rule	Regina	1947	1957	-	Sep	lastSun	2:00	0	S
+Rule	Regina	1959	only	-	Apr	lastSun	2:00	1:00	D
+Rule	Regina	1959	only	-	Oct	lastSun	2:00	0	S
+#
+Rule	Swift	1957	only	-	Apr	lastSun	2:00	1:00	D
+Rule	Swift	1957	only	-	Oct	lastSun	2:00	0	S
+Rule	Swift	1959	1961	-	Apr	lastSun	2:00	1:00	D
+Rule	Swift	1959	only	-	Oct	lastSun	2:00	0	S
+Rule	Swift	1960	1961	-	Sep	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Regina	-6:58:36 -	LMT	1905 Sep
+			-7:00	Regina	M%sT	1960 Apr lastSun 2:00
+			-6:00	-	CST
+Zone America/Swift_Current -7:11:20 -	LMT	1905 Sep
+			-7:00	Canada	M%sT	1946 Apr lastSun 2:00
+			-7:00	Regina	M%sT	1950
+			-7:00	Swift	M%sT	1972 Apr lastSun 2:00
+			-6:00	-	CST
+
+
+# Alberta
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Edm	1918	1919	-	Apr	Sun>=8	2:00	1:00	D
+Rule	Edm	1918	only	-	Oct	31	2:00	0	S
+Rule	Edm	1919	only	-	May	27	2:00	0	S
+Rule	Edm	1920	1923	-	Apr	lastSun	2:00	1:00	D
+Rule	Edm	1920	only	-	Oct	lastSun	2:00	0	S
+Rule	Edm	1921	1923	-	Sep	lastSun	2:00	0	S
+Rule	Edm	1942	only	-	Feb	 9	2:00	1:00	W # War
+Rule	Edm	1945	only	-	Aug	14	23:00u	1:00	P # Peace
+Rule	Edm	1945	only	-	Sep	lastSun	2:00	0	S
+Rule	Edm	1947	only	-	Apr	lastSun	2:00	1:00	D
+Rule	Edm	1947	only	-	Sep	lastSun	2:00	0	S
+Rule	Edm	1967	only	-	Apr	lastSun	2:00	1:00	D
+Rule	Edm	1967	only	-	Oct	lastSun	2:00	0	S
+Rule	Edm	1969	only	-	Apr	lastSun	2:00	1:00	D
+Rule	Edm	1969	only	-	Oct	lastSun	2:00	0	S
+Rule	Edm	1972	1986	-	Apr	lastSun	2:00	1:00	D
+Rule	Edm	1972	2006	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Edmonton	-7:33:52 -	LMT	1906 Sep
+			-7:00	Edm	M%sT	1987
+			-7:00	Canada	M%sT
+
+
+# British Columbia
+
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger write that since 1970 most of this region has
+# been like Vancouver.
+# Dawson Creek uses MST.  Much of east BC is like Edmonton.
+# Matthews and Vincent (1998) write that Creston is like Dawson Creek.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Vanc	1918	only	-	Apr	14	2:00	1:00	D
+Rule	Vanc	1918	only	-	Oct	31	2:00	0	S
+Rule	Vanc	1942	only	-	Feb	 9	2:00	1:00	W # War
+Rule	Vanc	1945	only	-	Aug	14	23:00u	1:00	P # Peace
+Rule	Vanc	1945	only	-	Sep	30	2:00	0	S
+Rule	Vanc	1946	1986	-	Apr	lastSun	2:00	1:00	D
+Rule	Vanc	1946	only	-	Oct	13	2:00	0	S
+Rule	Vanc	1947	1961	-	Sep	lastSun	2:00	0	S
+Rule	Vanc	1962	2006	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Vancouver	-8:12:28 -	LMT	1884
+			-8:00	Vanc	P%sT	1987
+			-8:00	Canada	P%sT
+Zone America/Dawson_Creek -8:00:56 -	LMT	1884
+			-8:00	Canada	P%sT	1947
+			-8:00	Vanc	P%sT	1972 Aug 30 2:00
+			-7:00	-	MST
+
+
+# Northwest Territories, Nunavut, Yukon
+
+# From Paul Eggert (2006-03-22):
+# Dawson switched to PST in 1973.  Inuvik switched to MST in 1979.
+# Mathew Englander (1996-10-07) gives the following refs:
+#	* 1967. Paragraph 28(34)(g) of the Interpretation Act, S.C. 1967-68,
+#	c. 7 defines Yukon standard time as UTC-9.  This is still valid;
+#	see Interpretation Act, R.S.C. 1985, c. I-21, s. 35(1).
+#	* C.O. 1973/214 switched Yukon to PST on 1973-10-28 00:00.
+#	* O.I.C. 1980/02 established DST.
+#	* O.I.C. 1987/056 changed DST to Apr firstSun 2:00 to Oct lastSun 2:00.
+# Shanks & Pottenger say Yukon's 1973-10-28 switch was at 2:00; go
+# with Englander.
+# From Chris Walton (2006-06-26):
+# Here is a link to the old daylight saving portion of the interpretation
+# act which was last updated in 1987:
+# http://www.gov.yk.ca/legislation/regs/oic1987_056.pdf
+
+# From Rives McDow (1999-09-04):
+# Nunavut ... moved ... to incorporate the whole territory into one time zone.
+# 
+# Nunavut moves to single time zone Oct. 31
+# 
+#
+# From Antoine Leca (1999-09-06):
+# We then need to create a new timezone for the Kitikmeot region of Nunavut
+# to differentiate it from the Yellowknife region.
+
+# From Paul Eggert (1999-09-20):
+# 
+# Basic Facts: The New Territory
+#  (1999) reports that Pangnirtung operates on eastern time,
+# and that Coral Harbour does not observe DST.  We don't know when
+# Pangnirtung switched to eastern time; we'll guess 1995.
+
+# From Rives McDow (1999-11-08):
+# On October 31, when the rest of Nunavut went to Central time,
+# Pangnirtung wobbled.  Here is the result of their wobble:
+#
+# The following businesses and organizations in Pangnirtung use Central Time:
+#
+#	First Air, Power Corp, Nunavut Construction, Health Center, RCMP,
+#	Eastern Arctic National Parks, A & D Specialist
+#
+# The following businesses and organizations in Pangnirtung use Eastern Time:
+#
+#	Hamlet office, All other businesses, Both schools, Airport operator
+#
+# This has made for an interesting situation there, which warranted the news.
+# No one there that I spoke with seems concerned, or has plans to
+# change the local methods of keeping time, as it evidently does not
+# really interfere with any activities or make things difficult locally.
+# They plan to celebrate New Year's turn-over twice, one hour apart,
+# so it appears that the situation will last at least that long.
+# The Nunavut Intergovernmental Affairs hopes that they will "come to
+# their senses", but the locals evidently don't see any problem with
+# the current state of affairs.
+
+# From Michaela Rodrigue, writing in the
+# 
+# Nunatsiaq News (1999-11-19):
+# Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones,
+# central - or Nunavut time - for government offices, and eastern time
+# for municipal offices and schools....  Igloolik [was similar but then]
+# made the switch to central time on Saturday, Nov. 6.
+
+# From Paul Eggert (2000-10-02):
+# Matthews and Vincent (1998) say the following, but we lack histories
+# for these potential new Zones.
+#
+# The Canadian Forces station at Alert uses Eastern Time while the
+# handful of residents at the Eureka weather station [in the Central
+# zone] skip daylight savings.  Baffin Island, which is crossed by the
+# Central, Eastern and Atlantic Time zones only uses Eastern Time.
+# Gjoa Haven, Taloyoak and Pelly Bay all use Mountain instead of
+# Central Time and Southampton Island [in the Central zone] is not
+# required to use daylight savings.
+
+# From
+# 
+# Nunavut now has two time zones
+#  (2000-11-10):
+# The Nunavut government would allow its employees in Kugluktuk and
+# Cambridge Bay to operate on central time year-round, putting them
+# one hour behind the rest of Nunavut for six months during the winter.
+# At the end of October the two communities had rebelled against
+# Nunavut's unified time zone, refusing to shift to eastern time with
+# the rest of the territory for the winter.  Cambridge Bay remained on
+# central time, while Kugluktuk, even farther west, reverted to
+# mountain time, which they had used before the advent of Nunavut's
+# unified time zone in 1999.
+#
+# From Rives McDow (2001-01-20), quoting the Nunavut government:
+# The preceding decision came into effect at midnight, Saturday Nov 4, 2000.
+
+# From Paul Eggert (2000-12-04):
+# Let's just keep track of the official times for now.
+
+# From Rives McDow (2001-03-07):
+# The premier of Nunavut has issued a ministerial statement advising
+# that effective 2001-04-01, the territory of Nunavut will revert
+# back to three time zones (mountain, central, and eastern).  Of the
+# cities in Nunavut, Coral Harbor is the only one that I know of that
+# has said it will not observe dst, staying on EST year round.  I'm
+# checking for more info, and will get back to you if I come up with
+# more.
+# [Also see  (2001-03-09).]
+
+# From Gwillim Law (2005-05-21):
+# According to maps at
+# http://inms-ienm.nrc-cnrc.gc.ca/images/time_services/TZ01SWE.jpg
+# http://inms-ienm.nrc-cnrc.gc.ca/images/time_services/TZ01SSE.jpg
+# (both dated 2003), and
+# http://www.canadiangeographic.ca/Magazine/SO98/geomap.asp
+# (from a 1998 Canadian Geographic article), the de facto and de jure time
+# for Southampton Island (at the north end of Hudson Bay) is UTC-5 all year
+# round.  Using Google, it's easy to find other websites that confirm this.
+# I wasn't able to find how far back this time regimen goes, but since it
+# predates the creation of Nunavut, it probably goes back many years....
+# The Inuktitut name of Coral Harbour is Sallit, but it's rarely used.
+#
+# From Paul Eggert (2005-07-26):
+# For lack of better information, assume that Southampton Island observed
+# daylight saving only during wartime.
+
+# From Chris Walton (2007-03-01):
+# ... the community of Resolute (located on Cornwallis Island in
+# Nunavut) moved from Central Time to Eastern Time last November.
+# Basically the community did not change its clocks at the end of
+# daylight saving....
+# http://www.nnsl.com/frames/newspapers/2006-11/nov13_06none.html
+
+# From Chris Walton (2007-03-14):
+# Today I phoned the "hamlet office" to find out what Resolute was doing with
+# its clocks.
+#
+# The individual that answered the phone confirmed that the clocks did not
+# move at the end of daylight saving on October 29/2006.  He also told me that
+# the clocks did not move this past weekend (March 11/2007)....
+
+# From Chris Walton (2008-11-13):
+# ...the residents of Resolute believe that they are changing "time zones"
+# twice a year.  In winter months, local time is qualified with "Eastern
+# Time" which is really "Eastern Standard Time (UTC-5)".  In summer
+# months, local time is qualified with "Central Time" which is really
+# "Central Daylight Time (UTC-5)"...
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	NT_YK	1918	only	-	Apr	14	2:00	1:00	D
+Rule	NT_YK	1918	only	-	Oct	27	2:00	0	S
+Rule	NT_YK	1919	only	-	May	25	2:00	1:00	D
+Rule	NT_YK	1919	only	-	Nov	 1	0:00	0	S
+Rule	NT_YK	1942	only	-	Feb	 9	2:00	1:00	W # War
+Rule	NT_YK	1945	only	-	Aug	14	23:00u	1:00	P # Peace
+Rule	NT_YK	1945	only	-	Sep	30	2:00	0	S
+Rule	NT_YK	1965	only	-	Apr	lastSun	0:00	2:00	DD
+Rule	NT_YK	1965	only	-	Oct	lastSun	2:00	0	S
+Rule	NT_YK	1980	1986	-	Apr	lastSun	2:00	1:00	D
+Rule	NT_YK	1980	2006	-	Oct	lastSun	2:00	0	S
+Rule	NT_YK	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+# aka Panniqtuuq
+Zone America/Pangnirtung 0	-	zzz	1921 # trading post est.
+			-4:00	NT_YK	A%sT	1995 Apr Sun>=1 2:00
+			-5:00	Canada	E%sT	1999 Oct 31 2:00
+			-6:00	Canada	C%sT	2000 Oct 29 2:00
+			-5:00	Canada	E%sT
+# formerly Frobisher Bay
+Zone America/Iqaluit	0	-	zzz	1942 Aug # Frobisher Bay est.
+			-5:00	NT_YK	E%sT	1999 Oct 31 2:00
+			-6:00	Canada	C%sT	2000 Oct 29 2:00
+			-5:00	Canada	E%sT
+# aka Qausuittuq
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Resolute 2006	max	-	Nov	Sun>=1	2:00	0	ES
+Rule	Resolute 2007	max	-	Mar	Sun>=8	2:00	0	CD
+Zone America/Resolute	0	-	zzz	1947 Aug 31 # Resolute founded
+			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
+			-5:00	-	EST	2001 Apr  1 3:00
+			-6:00	Canada	C%sT	2006 Oct 29 2:00
+			-5:00	Resolute	%sT
+# aka Kangiqiniq
+Zone America/Rankin_Inlet 0	-	zzz	1957 # Rankin Inlet founded
+			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
+			-5:00	-	EST	2001 Apr  1 3:00
+			-6:00	Canada	C%sT
+# aka Iqaluktuuttiaq
+Zone America/Cambridge_Bay 0	-	zzz	1920 # trading post est.?
+			-7:00	NT_YK	M%sT	1999 Oct 31 2:00
+			-6:00	Canada	C%sT	2000 Oct 29 2:00
+			-5:00	-	EST	2000 Nov  5 0:00
+			-6:00	-	CST	2001 Apr  1 3:00
+			-7:00	Canada	M%sT
+Zone America/Yellowknife 0	-	zzz	1935 # Yellowknife founded?
+			-7:00	NT_YK	M%sT	1980
+			-7:00	Canada	M%sT
+Zone America/Inuvik	0	-	zzz	1953 # Inuvik founded
+			-8:00	NT_YK	P%sT	1979 Apr lastSun 2:00
+			-7:00	NT_YK	M%sT	1980
+			-7:00	Canada	M%sT
+Zone America/Whitehorse	-9:00:12 -	LMT	1900 Aug 20
+			-9:00	NT_YK	Y%sT	1966 Jul 1 2:00
+			-8:00	NT_YK	P%sT	1980
+			-8:00	Canada	P%sT
+Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
+			-9:00	NT_YK	Y%sT	1973 Oct 28 0:00
+			-8:00	NT_YK	P%sT	1980
+			-8:00	Canada	P%sT
+
+
+###############################################################################
+
+# Mexico
+
+# From Paul Eggert (2001-03-05):
+# The Investigation and Analysis Service of the
+# Mexican Library of Congress (MLoC) has published a
+# 
+# history of Mexican local time (in Spanish)
+# .
+#
+# Here are the discrepancies between Shanks & Pottenger (S&P) and the MLoC.
+# (In all cases we go with the MLoC.)
+# S&P report that Baja was at -8:00 in 1922/1923.
+# S&P say the 1930 transition in Baja was 1930-11-16.
+# S&P report no DST during summer 1931.
+# S&P report a transition at 1932-03-30 23:00, not 1932-04-01.
+
+# From Gwillim Law (2001-02-20):
+# There are some other discrepancies between the Decrees page and the
+# tz database.  I think they can best be explained by supposing that
+# the researchers who prepared the Decrees page failed to find some of
+# the relevant documents.
+
+# From Alan Perry (1996-02-15):
+# A guy from our Mexico subsidiary finally found the Presidential Decree
+# outlining the timezone changes in Mexico.
+#
+# ------------- Begin Forwarded Message -------------
+#
+# I finally got my hands on the Official Presidential Decree that sets up the
+# rules for the DST changes. The rules are:
+#
+# 1. The country is divided in 3 timezones:
+#    - Baja California Norte (the Mexico/BajaNorte TZ)
+#    - Baja California Sur, Nayarit, Sinaloa and Sonora (the Mexico/BajaSur TZ)
+#    - The rest of the country (the Mexico/General TZ)
+#
+# 2. From the first Sunday in April at 2:00 AM to the last Sunday in October
+#    at 2:00 AM, the times in each zone are as follows:
+#    BajaNorte: GMT+7
+#    BajaSur:   GMT+6
+#    General:   GMT+5
+#
+# 3. The rest of the year, the times are as follows:
+#    BajaNorte: GMT+8
+#    BajaSur:   GMT+7
+#    General:   GMT+6
+#
+# The Decree was published in Mexico's Official Newspaper on January 4th.
+#
+# -------------- End Forwarded Message --------------
+# From Paul Eggert (1996-06-12):
+# For an English translation of the decree, see
+# 
+# ``Diario Oficial: Time Zone Changeover'' (1996-01-04).
+# 
+
+# From Rives McDow (1998-10-08):
+# The State of Quintana Roo has reverted back to central STD and DST times
+# (i.e. UTC -0600 and -0500 as of 1998-08-02).
+
+# From Rives McDow (2000-01-10):
+# Effective April 4, 1999 at 2:00 AM local time, Sonora changed to the time
+# zone 5 hours from the International Date Line, and will not observe daylight
+# savings time so as to stay on the same time zone as the southern part of
+# Arizona year round.
+
+# From Jesper Norgaard, translating
+#  (2001-01-17):
+# In Oaxaca, the 55.000 teachers from the Section 22 of the National
+# Syndicate of Education Workers, refuse to apply daylight saving each
+# year, so that the more than 10,000 schools work at normal hour the
+# whole year.
+
+# From Gwillim Law (2001-01-19):
+#  ... says
+# (translated):...
+# January 17, 2000 - The Energy Secretary, Ernesto Martens, announced
+# that Summer Time will be reduced from seven to five months, starting
+# this year....
+# 
+# [translated], says "summer time will ... take effect on the first Sunday
+# in May, and end on the last Sunday of September.
+
+# From Arthur David Olson (2001-01-25):
+# The 2001-01-24 traditional Washington Post contained the page one
+# story "Timely Issue Divides Mexicans."...
+# http://www.washingtonpost.com/wp-dyn/articles/A37383-2001Jan23.html
+# ... Mexico City Mayor Lopez Obrador "...is threatening to keep
+# Mexico City and its 20 million residents on a different time than
+# the rest of the country..." In particular, Lopez Obrador would abolish
+# observation of Daylight Saving Time.
+
+# 
+# Official statute published by the Energy Department
+#  (2001-02-01) shows Baja and Chihauhua as still using US DST rules,
+# and Sonora with no DST.  This was reported by Jesper Norgaard (2001-02-03).
+
+# From Paul Eggert (2001-03-03):
+#
+# 
+# James F. Smith writes in today's LA Times
+# 
+# * Sonora will continue to observe standard time.
+# * Last week Mexico City's mayor Andres Manuel Lopez Obrador decreed that
+#   the Federal District will not adopt DST.
+# * 4 of 16 district leaders announced they'll ignore the decree.
+# * The decree does not affect federal-controlled facilities including
+#   the airport, banks, hospitals, and schools.
+#
+# For now we'll assume that the Federal District will bow to federal rules.
+
+# From Jesper Norgaard (2001-04-01):
+# I found some references to the Mexican application of daylight
+# saving, which modifies what I had already sent you, stating earlier
+# that a number of northern Mexican states would go on daylight
+# saving. The modification reverts this to only cover Baja California
+# (Norte), while all other states (except Sonora, who has no daylight
+# saving all year) will follow the original decree of president
+# Vicente Fox, starting daylight saving May 6, 2001 and ending
+# September 30, 2001.
+# References: "Diario de Monterrey" 
+# Palabra  (2001-03-31)
+
+# From Reuters (2001-09-04):
+# Mexico's Supreme Court on Tuesday declared that daylight savings was
+# unconstitutional in Mexico City, creating the possibility the
+# capital will be in a different time zone from the rest of the nation
+# next year....  The Supreme Court's ruling takes effect at 2:00
+# a.m. (0800 GMT) on Sept. 30, when Mexico is scheduled to revert to
+# standard time. "This is so residents of the Federal District are not
+# subject to unexpected time changes," a statement from the court said.
+
+# From Jesper Norgaard Welen (2002-03-12):
+# ... consulting my local grocery store(!) and my coworkers, they all insisted
+# that a new decision had been made to reinstate US style DST in Mexico....
+# http://www.conae.gob.mx/ahorro/horaver2001_m1_2002.html (2002-02-20)
+# confirms this.  Sonora as usual is the only state where DST is not applied.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Mexico	1939	only	-	Feb	5	0:00	1:00	D
+Rule	Mexico	1939	only	-	Jun	25	0:00	0	S
+Rule	Mexico	1940	only	-	Dec	9	0:00	1:00	D
+Rule	Mexico	1941	only	-	Apr	1	0:00	0	S
+Rule	Mexico	1943	only	-	Dec	16	0:00	1:00	W # War
+Rule	Mexico	1944	only	-	May	1	0:00	0	S
+Rule	Mexico	1950	only	-	Feb	12	0:00	1:00	D
+Rule	Mexico	1950	only	-	Jul	30	0:00	0	S
+Rule	Mexico	1996	2000	-	Apr	Sun>=1	2:00	1:00	D
+Rule	Mexico	1996	2000	-	Oct	lastSun	2:00	0	S
+Rule	Mexico	2001	only	-	May	Sun>=1	2:00	1:00	D
+Rule	Mexico	2001	only	-	Sep	lastSun	2:00	0	S
+Rule	Mexico	2002	max	-	Apr	Sun>=1	2:00	1:00	D
+Rule	Mexico	2002	max	-	Oct	lastSun	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+# Quintana Roo
+Zone America/Cancun	-5:47:04 -	LMT	1922 Jan  1  0:12:56
+			-6:00	-	CST	1981 Dec 23
+			-5:00	Mexico	E%sT	1998 Aug  2  2:00
+			-6:00	Mexico	C%sT
+# Campeche, Yucatan
+Zone America/Merida	-5:58:28 -	LMT	1922 Jan  1  0:01:32
+			-6:00	-	CST	1981 Dec 23
+			-5:00	-	EST	1982 Dec  2
+			-6:00	Mexico	C%sT
+# Coahuila, Durango, Nuevo Leon, Tamaulipas
+Zone America/Monterrey	-6:41:16 -	LMT	1921 Dec 31 23:18:44
+			-6:00	-	CST	1988
+			-6:00	US	C%sT	1989
+			-6:00	Mexico	C%sT
+# Central Mexico
+Zone America/Mexico_City -6:36:36 -	LMT	1922 Jan  1  0:23:24
+			-7:00	-	MST	1927 Jun 10 23:00
+			-6:00	-	CST	1930 Nov 15
+			-7:00	-	MST	1931 May  1 23:00
+			-6:00	-	CST	1931 Oct
+			-7:00	-	MST	1932 Apr  1
+			-6:00	Mexico	C%sT	2001 Sep 30 02:00
+			-6:00	-	CST	2002 Feb 20
+			-6:00	Mexico	C%sT
+# Chihuahua
+Zone America/Chihuahua	-7:04:20 -	LMT	1921 Dec 31 23:55:40
+			-7:00	-	MST	1927 Jun 10 23:00
+			-6:00	-	CST	1930 Nov 15
+			-7:00	-	MST	1931 May  1 23:00
+			-6:00	-	CST	1931 Oct
+			-7:00	-	MST	1932 Apr  1
+			-6:00	-	CST	1996
+			-6:00	Mexico	C%sT	1998
+			-6:00	-	CST	1998 Apr Sun>=1 3:00
+			-7:00	Mexico	M%sT
+# Sonora
+Zone America/Hermosillo	-7:23:52 -	LMT	1921 Dec 31 23:36:08
+			-7:00	-	MST	1927 Jun 10 23:00
+			-6:00	-	CST	1930 Nov 15
+			-7:00	-	MST	1931 May  1 23:00
+			-6:00	-	CST	1931 Oct
+			-7:00	-	MST	1932 Apr  1
+			-6:00	-	CST	1942 Apr 24
+			-7:00	-	MST	1949 Jan 14
+			-8:00	-	PST	1970
+			-7:00	Mexico	M%sT	1999
+			-7:00	-	MST
+# Baja California Sur, Nayarit, Sinaloa
+Zone America/Mazatlan	-7:05:40 -	LMT	1921 Dec 31 23:54:20
+			-7:00	-	MST	1927 Jun 10 23:00
+			-6:00	-	CST	1930 Nov 15
+			-7:00	-	MST	1931 May  1 23:00
+			-6:00	-	CST	1931 Oct
+			-7:00	-	MST	1932 Apr  1
+			-6:00	-	CST	1942 Apr 24
+			-7:00	-	MST	1949 Jan 14
+			-8:00	-	PST	1970
+			-7:00	Mexico	M%sT
+# Baja California
+Zone America/Tijuana	-7:48:04 -	LMT	1922 Jan  1  0:11:56
+			-7:00	-	MST	1924
+			-8:00	-	PST	1927 Jun 10 23:00
+			-7:00	-	MST	1930 Nov 15
+			-8:00	-	PST	1931 Apr  1
+			-8:00	1:00	PDT	1931 Sep 30
+			-8:00	-	PST	1942 Apr 24
+			-8:00	1:00	PWT	1945 Aug 14 23:00u
+			-8:00	1:00	PPT	1945 Nov 12 # Peace
+			-8:00	-	PST	1948 Apr  5
+			-8:00	1:00	PDT	1949 Jan 14
+			-8:00	-	PST	1954
+			-8:00	CA	P%sT	1961
+			-8:00	-	PST	1976
+			-8:00	US	P%sT	1996
+			-8:00	Mexico	P%sT	2001
+			-8:00	US	P%sT	2002 Feb 20
+			-8:00	Mexico	P%sT
+# From Paul Eggert (2006-03-22):
+# Formerly there was an America/Ensenada zone, which differed from
+# America/Tijuana only in that it did not observe DST from 1976
+# through 1995.  This was as per Shanks (1999).  But Shanks & Pottenger say
+# Ensenada did not observe DST from 1948 through 1975.  Guy Harris reports
+# that the 1987 OAG says "Only Ensenada, Mexicale, San Felipe and
+# Tijuana observe DST," which agrees with Shanks & Pottenger but implies that
+# DST-observance was a town-by-town matter back then.  This concerns
+# data after 1970 so most likely there should be at least one Zone
+# other than America/Tijuana for Baja, but it's not clear yet what its
+# name or contents should be.
+#
+# Revillagigedo Is
+# no information
+
+###############################################################################
+
+# Anguilla
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Anguilla	-4:12:16 -	LMT	1912 Mar 2
+			-4:00	-	AST
+
+# Antigua and Barbuda
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Antigua	-4:07:12 -	LMT	1912 Mar 2
+			-5:00	-	EST	1951
+			-4:00	-	AST
+
+# Bahamas
+#
+# From Sue Williams (2006-12-07):
+# The Bahamas announced about a month ago that they plan to change their DST
+# rules to sync with the U.S. starting in 2007....
+# http://www.jonesbahamas.com/?c=45&a=10412
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Bahamas	1964	1975	-	Oct	lastSun	2:00	0	S
+Rule	Bahamas	1964	1975	-	Apr	lastSun	2:00	1:00	D
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Nassau	-5:09:24 -	LMT	1912 Mar 2
+			-5:00	Bahamas	E%sT	1976
+			-5:00	US	E%sT
+
+# Barbados
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Barb	1977	only	-	Jun	12	2:00	1:00	D
+Rule	Barb	1977	1978	-	Oct	Sun>=1	2:00	0	S
+Rule	Barb	1978	1980	-	Apr	Sun>=15	2:00	1:00	D
+Rule	Barb	1979	only	-	Sep	30	2:00	0	S
+Rule	Barb	1980	only	-	Sep	25	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Barbados	-3:58:28 -	LMT	1924		# Bridgetown
+			-3:58:28 -	BMT	1932	  # Bridgetown Mean Time
+			-4:00	Barb	A%sT
+
+# Belize
+# Whitman entirely disagrees with Shanks; go with Shanks & Pottenger.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Belize	1918	1942	-	Oct	Sun>=2	0:00	0:30	HD
+Rule	Belize	1919	1943	-	Feb	Sun>=9	0:00	0	S
+Rule	Belize	1973	only	-	Dec	 5	0:00	1:00	D
+Rule	Belize	1974	only	-	Feb	 9	0:00	0	S
+Rule	Belize	1982	only	-	Dec	18	0:00	1:00	D
+Rule	Belize	1983	only	-	Feb	12	0:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Belize	-5:52:48 -	LMT	1912 Apr
+			-6:00	Belize	C%sT
+
+# Bermuda
+
+# From Dan Jones, reporting in The Royal Gazette (2006-06-26):
+
+# Next year, however, clocks in the US will go forward on the second Sunday
+# in March, until the first Sunday in November.  And, after the Time Zone
+# (Seasonal Variation) Bill 2006 was passed in the House of Assembly on
+# Friday, the same thing will happen in Bermuda.
+# http://www.theroyalgazette.com/apps/pbcs.dll/article?AID=/20060529/NEWS/105290135
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Atlantic/Bermuda	-4:19:04 -	LMT	1930 Jan  1 2:00    # Hamilton
+			-4:00	-	AST	1974 Apr 28 2:00
+			-4:00	Bahamas	A%sT	1976
+			-4:00	US	A%sT
+
+# Cayman Is
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Cayman	-5:25:32 -	LMT	1890		# Georgetown
+			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
+			-5:00	-	EST
+
+# Costa Rica
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	CR	1979	1980	-	Feb	lastSun	0:00	1:00	D
+Rule	CR	1979	1980	-	Jun	Sun>=1	0:00	0	S
+Rule	CR	1991	1992	-	Jan	Sat>=15	0:00	1:00	D
+# IATA SSIM (1991-09) says the following was at 1:00;
+# go with Shanks & Pottenger.
+Rule	CR	1991	only	-	Jul	 1	0:00	0	S
+Rule	CR	1992	only	-	Mar	15	0:00	0	S
+# There are too many San Joses elsewhere, so we'll use `Costa Rica'.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Costa_Rica	-5:36:20 -	LMT	1890		# San Jose
+			-5:36:20 -	SJMT	1921 Jan 15 # San Jose Mean Time
+			-6:00	CR	C%sT
+# Coco
+# no information; probably like America/Costa_Rica
+
+# Cuba
+
+# From Arthur David Olson (1999-03-29):
+# The 1999-03-28 exhibition baseball game held in Havana, Cuba, between
+# the Cuban National Team and the Baltimore Orioles was carried live on
+# the Orioles Radio Network, including affiliate WTOP in Washington, DC.
+# During the game, play-by-play announcer Jim Hunter noted that
+# "We'll be losing two hours of sleep...Cuba switched to Daylight Saving
+# Time today."  (The "two hour" remark referred to losing one hour of
+# sleep on 1999-03-28--when the announcers were in Cuba as it switched
+# to DST--and one more hour on 1999-04-04--when the announcers will have
+# returned to Baltimore, which switches on that date.)
+
+# From Evert van der Veer via Steffen Thorsen (2004-10-28):
+# Cuba is not going back to standard time this year.
+# From Paul Eggert (2006-03-22):
+# http://www.granma.cu/ingles/2004/septiembre/juev30/41medid-i.html
+# says that it's due to a problem at the Antonio Guiteras
+# thermoelectric plant, and says "This October there will be no return
+# to normal hours (after daylight saving time)".
+# For now, let's assume that it's a temporary measure.
+
+# From Carlos A. Carnero Delgado (2005-11-12):
+# This year (just like in 2004-2005) there's no change in time zone
+# adjustment in Cuba.  We will stay in daylight saving time:
+# http://www.granma.cu/espanol/2005/noviembre/mier9/horario.html
+
+# From Jesper Norgaard Welen (2006-10-21):
+# An article in GRANMA INTERNACIONAL claims that Cuba will end
+# the 3 years of permanent DST next weekend, see
+# http://www.granma.cu/ingles/2006/octubre/lun16/43horario.html
+# "On Saturday night, October 28 going into Sunday, October 29, at 01:00,
+# watches should be set back one hour -- going back to 00:00 hours -- returning
+# to the normal schedule....
+
+# From Paul Eggert (2007-03-02):
+# http://www.granma.cubaweb.cu/english/news/art89.html, dated yesterday,
+# says Cuban clocks will advance at midnight on March 10.
+# For lack of better information, assume Cuba will use US rules,
+# except that it switches at midnight standard time as usual.
+#
+# From Steffen Thorsen (2007-10-25):
+# Carlos Alberto Fonseca Arauz informed me that Cuba will end DST one week 
+# earlier - on the last Sunday of October, just like in 2006.
+# 
+# He supplied these references:
+# 
+# http://www.prensalatina.com.mx/article.asp?ID=%7B4CC32C1B-A9F7-42FB-8A07-8631AFC923AF%7D&language=ES
+# http://actualidad.terra.es/sociedad/articulo/cuba_llama_ahorrar_energia_cambio_1957044.htm
+# 
+# From Alex Kryvenishev (2007-10-25):
+# Here is also article from Granma (Cuba):
+# 
+# [Regira] el Horario Normal desde el [proximo] domingo 28 de octubre
+# http://www.granma.cubaweb.cu/2007/10/24/nacional/artic07.html
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_cuba03.html
+
+# From Arthur David Olson (2008-03-09):
+# I'm in Maryland which is now observing United States Eastern Daylight
+# Time. At 9:44 local time I used RealPlayer to listen to
+# 
+# http://media.enet.cu/radioreloj
+# , a Cuban information station, and heard
+# the time announced as "ocho cuarenta y cuatro" ("eight forty-four"),
+# indicating that Cuba is still on standard time.
+
+# From Steffen Thorsen (2008-03-12):
+# It seems that Cuba will start DST on Sunday, 2007-03-16...
+# It was announced yesterday, according to this source (in Spanish):
+# 
+# http://www.nnc.cubaweb.cu/marzo-2008/cien-1-11-3-08.htm
+# 
+#
+# Some more background information is posted here:
+# 
+# http://www.timeanddate.com/news/time/cuba-starts-dst-march-16.html
+# 
+#
+# The article also says that Cuba has been observing DST since 1963,
+# while Shanks (and tzdata) has 1965 as the first date (except in the
+# 1940's). Many other web pages in Cuba also claim that it has been
+# observed since 1963, but with the exception of 1970 - an exception
+# which is not present in tzdata/Shanks. So there is a chance we need to
+# change some historic records as well.
+#
+# One example:
+# 
+# http://www.radiohc.cu/espanol/noticias/mar07/11mar/hor.htm
+# 
+
+# From Jesper Norgaard Welen (2008-03-13):
+# The Cuban time change has just been confirmed on the most authoritative
+# web site, the Granma.  Please check out
+# 
+# http://www.granma.cubaweb.cu/2008/03/13/nacional/artic10.html
+# 
+#
+# Basically as expected after Steffen Thorsens information, the change
+# will take place midnight between Saturday and Sunday.
+
+# From Arthur David Olson (2008-03-12):
+# Assume Sun>=15 (third Sunday) going forward.
+
+# From Alexander Krivenyshev (2009-03-04)
+# According to the Radio Reloj - Cuba will start Daylight Saving Time on
+# midnight between Saturday, March 07, 2009 and Sunday, March 08, 2009-
+# not on midnight March 14 / March 15 as previously thought.
+#
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_cuba05.html
+# (in Spanish)
+# 
+
+# From Arthur David Olson (2009-03-09)
+# I listened over the Internet to
+# 
+# http://media.enet.cu/readioreloj
+# 
+# this morning; when it was 10:05 a. m. here in Bethesda, Maryland the
+# the time was announced as "diez cinco"--the same time as here, indicating
+# that has indeed switched to DST. Assume second Sunday from 2009 forward.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Cuba	1928	only	-	Jun	10	0:00	1:00	D
+Rule	Cuba	1928	only	-	Oct	10	0:00	0	S
+Rule	Cuba	1940	1942	-	Jun	Sun>=1	0:00	1:00	D
+Rule	Cuba	1940	1942	-	Sep	Sun>=1	0:00	0	S
+Rule	Cuba	1945	1946	-	Jun	Sun>=1	0:00	1:00	D
+Rule	Cuba	1945	1946	-	Sep	Sun>=1	0:00	0	S
+Rule	Cuba	1965	only	-	Jun	1	0:00	1:00	D
+Rule	Cuba	1965	only	-	Sep	30	0:00	0	S
+Rule	Cuba	1966	only	-	May	29	0:00	1:00	D
+Rule	Cuba	1966	only	-	Oct	2	0:00	0	S
+Rule	Cuba	1967	only	-	Apr	8	0:00	1:00	D
+Rule	Cuba	1967	1968	-	Sep	Sun>=8	0:00	0	S
+Rule	Cuba	1968	only	-	Apr	14	0:00	1:00	D
+Rule	Cuba	1969	1977	-	Apr	lastSun	0:00	1:00	D
+Rule	Cuba	1969	1971	-	Oct	lastSun	0:00	0	S
+Rule	Cuba	1972	1974	-	Oct	8	0:00	0	S
+Rule	Cuba	1975	1977	-	Oct	lastSun	0:00	0	S
+Rule	Cuba	1978	only	-	May	7	0:00	1:00	D
+Rule	Cuba	1978	1990	-	Oct	Sun>=8	0:00	0	S
+Rule	Cuba	1979	1980	-	Mar	Sun>=15	0:00	1:00	D
+Rule	Cuba	1981	1985	-	May	Sun>=5	0:00	1:00	D
+Rule	Cuba	1986	1989	-	Mar	Sun>=14	0:00	1:00	D
+Rule	Cuba	1990	1997	-	Apr	Sun>=1	0:00	1:00	D
+Rule	Cuba	1991	1995	-	Oct	Sun>=8	0:00s	0	S
+Rule	Cuba	1996	only	-	Oct	 6	0:00s	0	S
+Rule	Cuba	1997	only	-	Oct	12	0:00s	0	S
+Rule	Cuba	1998	1999	-	Mar	lastSun	0:00s	1:00	D
+Rule	Cuba	1998	2003	-	Oct	lastSun	0:00s	0	S
+Rule	Cuba	2000	2004	-	Apr	Sun>=1	0:00s	1:00	D
+Rule	Cuba	2006	max	-	Oct	lastSun	0:00s	0	S
+Rule	Cuba	2007	only	-	Mar	Sun>=8	0:00s	1:00	D
+Rule	Cuba	2008	only	-	Mar	Sun>=15	0:00s	1:00	D
+Rule	Cuba	2009	max	-	Mar	Sun>=8	0:00s	1:00	D
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Havana	-5:29:28 -	LMT	1890
+			-5:29:36 -	HMT	1925 Jul 19 12:00 # Havana MT
+			-5:00	Cuba	C%sT
+
+# Dominica
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Dominica	-4:05:36 -	LMT	1911 Jul 1 0:01		# Roseau
+			-4:00	-	AST
+
+# Dominican Republic
+
+# From Steffen Thorsen (2000-10-30):
+# Enrique Morales reported to me that the Dominican Republic has changed the
+# time zone to Eastern Standard Time as of Sunday 29 at 2 am....
+# http://www.listin.com.do/antes/261000/republica/princi.html
+
+# From Paul Eggert (2000-12-04):
+# That URL (2000-10-26, in Spanish) says they planned to use US-style DST.
+
+# From Rives McDow (2000-12-01):
+# Dominican Republic changed its mind and presidential decree on Tuesday,
+# November 28, 2000, with a new decree.  On Sunday, December 3 at 1:00 AM the
+# Dominican Republic will be reverting to 8 hours from the International Date
+# Line, and will not be using DST in the foreseeable future.  The reason they
+# decided to use DST was to be in synch with Puerto Rico, who was also going
+# to implement DST.  When Puerto Rico didn't implement DST, the president
+# decided to revert.
+
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	DR	1966	only	-	Oct	30	0:00	1:00	D
+Rule	DR	1967	only	-	Feb	28	0:00	0	S
+Rule	DR	1969	1973	-	Oct	lastSun	0:00	0:30	HD
+Rule	DR	1970	only	-	Feb	21	0:00	0	S
+Rule	DR	1971	only	-	Jan	20	0:00	0	S
+Rule	DR	1972	1974	-	Jan	21	0:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Santo_Domingo -4:39:36 -	LMT	1890
+			-4:40	-	SDMT	1933 Apr  1 12:00 # S. Dom. MT
+			-5:00	DR	E%sT	1974 Oct 27
+			-4:00	-	AST	2000 Oct 29 02:00
+			-5:00	US	E%sT	2000 Dec  3 01:00
+			-4:00	-	AST
+
+# El Salvador
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Salv	1987	1988	-	May	Sun>=1	0:00	1:00	D
+Rule	Salv	1987	1988	-	Sep	lastSun	0:00	0	S
+# There are too many San Salvadors elsewhere, so use America/El_Salvador
+# instead of America/San_Salvador.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/El_Salvador -5:56:48 -	LMT	1921		# San Salvador
+			-6:00	Salv	C%sT
+
+# Grenada
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Grenada	-4:07:00 -	LMT	1911 Jul	# St George's
+			-4:00	-	AST
+
+# Guadeloupe
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Guadeloupe	-4:06:08 -	LMT	1911 Jun 8	# Pointe a Pitre
+			-4:00	-	AST
+# St Barthelemy
+Link America/Guadeloupe	America/St_Barthelemy
+# St Martin (French part)
+Link America/Guadeloupe	America/Marigot
+
+# Guatemala
+#
+# From Gwillim Law (2006-04-22), after a heads-up from Oscar van Vlijmen:
+# Diario Co Latino, at
+# http://www.diariocolatino.com/internacionales/detalles.asp?NewsID=8079,
+# says in an article dated 2006-04-19 that the Guatemalan government had
+# decided on that date to advance official time by 60 minutes, to lessen the
+# impact of the elevated cost of oil....  Daylight saving time will last from
+# 2006-04-29 24:00 (Guatemalan standard time) to 2006-09-30 (time unspecified).
+# From Paul Eggert (2006-06-22):
+# The Ministry of Energy and Mines, press release CP-15/2006
+# (2006-04-19), says DST ends at 24:00.  See
+# .
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Guat	1973	only	-	Nov	25	0:00	1:00	D
+Rule	Guat	1974	only	-	Feb	24	0:00	0	S
+Rule	Guat	1983	only	-	May	21	0:00	1:00	D
+Rule	Guat	1983	only	-	Sep	22	0:00	0	S
+Rule	Guat	1991	only	-	Mar	23	0:00	1:00	D
+Rule	Guat	1991	only	-	Sep	 7	0:00	0	S
+Rule	Guat	2006	only	-	Apr	30	0:00	1:00	D
+Rule	Guat	2006	only	-	Oct	 1	0:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Guatemala	-6:02:04 -	LMT	1918 Oct 5
+			-6:00	Guat	C%sT
+
+# Haiti
+# From Gwillim Law (2005-04-15):
+# Risto O. Nykanen wrote me that Haiti is now on DST.
+# I searched for confirmation, and I found a
+#  press release
+# on the Web page of the Haitian Consulate in Chicago (2005-03-31),
+# .  Translated from French, it says:
+#
+#  "The Prime Minister's Communication Office notifies the public in general
+#   and the press in particular that, following a decision of the Interior
+#   Ministry and the Territorial Collectivities [I suppose that means the
+#   provinces], Haiti will move to Eastern Daylight Time in the night from next
+#   Saturday the 2nd to Sunday the 3rd.
+#
+#  "Consequently, the Prime Minister's Communication Office wishes to inform
+#   the population that the country's clocks will be set forward one hour
+#   starting at midnight.  This provision will hold until the last Saturday in
+#   October 2005.
+#
+#  "Port-au-Prince, March 31, 2005"
+#
+# From Steffen Thorsen (2006-04-04):
+# I have been informed by users that Haiti observes DST this year like
+# last year, so the current "only" rule for 2005 might be changed to a
+# "max" rule or to last until 2006. (Who knows if they will observe DST
+# next year or if they will extend their DST like US/Canada next year).
+#
+# I have found this article about it (in French):
+# http://www.haitipressnetwork.com/news.cfm?articleID=7612
+#
+# The reason seems to be an energy crisis.
+
+# From Stephen Colebourne (2007-02-22):
+# Some IATA info: Haiti won't be having DST in 2007.
+
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Haiti	1983	only	-	May	8	0:00	1:00	D
+Rule	Haiti	1984	1987	-	Apr	lastSun	0:00	1:00	D
+Rule	Haiti	1983	1987	-	Oct	lastSun	0:00	0	S
+# Shanks & Pottenger say AT is 2:00, but IATA SSIM (1991/1997) says 1:00s.
+# Go with IATA.
+Rule	Haiti	1988	1997	-	Apr	Sun>=1	1:00s	1:00	D
+Rule	Haiti	1988	1997	-	Oct	lastSun	1:00s	0	S
+Rule	Haiti	2005	2006	-	Apr	Sun>=1	0:00	1:00	D
+Rule	Haiti	2005	2006	-	Oct	lastSun	0:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Port-au-Prince -4:49:20 -	LMT	1890
+			-4:49	-	PPMT	1917 Jan 24 12:00 # P-a-P MT
+			-5:00	Haiti	E%sT
+
+# Honduras
+# Shanks & Pottenger say 1921 Jan 1; go with Whitman's more precise Apr 1.
+
+# From Paul Eggert (2006-05-05):
+# worldtimezone.com reports a 2006-05-02 Spanish-language AP article
+# saying Honduras will start using DST midnight Saturday, effective 4
+# months until September.  La Tribuna reported today
+#  that Manuel Zelaya, the president
+# of Honduras, refused to back down on this.
+
+# From Jesper Norgaard Welen (2006-08-08):
+# It seems that Honduras has returned from DST to standard time this Monday at
+# 00:00 hours (prolonging Sunday to 25 hours duration).
+# http://www.worldtimezone.com/dst_news/dst_news_honduras04.html
+
+# From Paul Eggert (2006-08-08):
+# Also see Diario El Heraldo, The country returns to standard time (2006-08-08)
+# .
+# It mentions executive decree 18-2006.
+
+# From Steffen Thorsen (2006-08-17):
+# Honduras will observe DST from 2007 to 2009, exact dates are not
+# published, I have located this authoritative source:
+# http://www.presidencia.gob.hn/noticia.aspx?nId=47
+
+# From Steffen Thorsen (2007-03-30):
+# http://www.laprensahn.com/pais_nota.php?id04962=7386
+# So it seems that Honduras will not enter DST this year....
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Hond	1987	1988	-	May	Sun>=1	0:00	1:00	D
+Rule	Hond	1987	1988	-	Sep	lastSun	0:00	0	S
+Rule	Hond	2006	only	-	May	Sun>=1	0:00	1:00	D
+Rule	Hond	2006	only	-	Aug	Mon>=1	0:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Tegucigalpa -5:48:52 -	LMT	1921 Apr
+			-6:00	Hond	C%sT
+#
+# Great Swan I ceded by US to Honduras in 1972
+
+# Jamaica
+
+# From Bob Devine (1988-01-28):
+# Follows US rules.
+
+# From U. S. Naval Observatory (1989-01-19):
+# JAMAICA             5 H  BEHIND UTC
+
+# From Shanks & Pottenger:
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Jamaica	-5:07:12 -	LMT	1890		# Kingston
+			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
+			-5:00	-	EST	1974 Apr 28 2:00
+			-5:00	US	E%sT	1984
+			-5:00	-	EST
+
+# Martinique
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Martinique	-4:04:20 -      LMT	1890		# Fort-de-France
+			-4:04:20 -	FFMT	1911 May     # Fort-de-France MT
+			-4:00	-	AST	1980 Apr  6
+			-4:00	1:00	ADT	1980 Sep 28
+			-4:00	-	AST
+
+# Montserrat
+# From Paul Eggert (2006-03-22):
+# In 1995 volcanic eruptions forced evacuation of Plymouth, the capital.
+# world.gazetteer.com says Cork Hill is the most populous location now.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Montserrat	-4:08:52 -	LMT	1911 Jul 1 0:01   # Cork Hill
+			-4:00	-	AST
+
+# Nicaragua
+#
+# This uses Shanks & Pottenger for times before 2005.
+#
+# From Steffen Thorsen (2005-04-12):
+# I've got reports from 8 different people that Nicaragua just started
+# DST on Sunday 2005-04-10, in order to save energy because of
+# expensive petroleum.  The exact end date for DST is not yet
+# announced, only "September" but some sites also say "mid-September".
+# Some background information is available on the President's official site:
+# http://www.presidencia.gob.ni/Presidencia/Files_index/Secretaria/Notas%20de%20Prensa/Presidente/2005/ABRIL/Gobierno-de-nicaragua-adelanta-hora-oficial-06abril.htm
+# The Decree, no 23-2005 is available here:
+# http://www.presidencia.gob.ni/buscador_gaceta/BD/DECRETOS/2005/Decreto%2023-2005%20Se%20adelanta%20en%20una%20hora%20en%20todo%20el%20territorio%20nacional%20apartir%20de%20las%2024horas%20del%2009%20de%20Abril.pdf
+#
+# From Paul Eggert (2005-05-01):
+# The decree doesn't say anything about daylight saving, but for now let's
+# assume that it is daylight saving....
+#
+# From Gwillim Law (2005-04-21):
+# The Associated Press story on the time change, which can be found at
+# http://www.lapalmainteractivo.com/guias/content/gen/ap/America_Latina/AMC_GEN_NICARAGUA_HORA.html
+# and elsewhere, says (fifth paragraph, translated from Spanish):  "The last
+# time that a change of clocks was applied to save energy was in the year 2000
+# during the Arnoldo Aleman administration."...
+# The northamerica file says that Nicaragua has been on UTC-6 continuously
+# since December 1998.  I wasn't able to find any details of Nicaraguan time
+# changes in 2000.  Perhaps a note could be added to the northamerica file, to
+# the effect that we have indirect evidence that DST was observed in 2000.
+#
+# From Jesper Norgaard Welen (2005-11-02):
+# Nicaragua left DST the 2005-10-02 at 00:00 (local time).
+# http://www.presidencia.gob.ni/presidencia/files_index/secretaria/comunicados/2005/septiembre/26septiembre-cambio-hora.htm
+# (2005-09-26)
+#
+# From Jesper Norgaard Welen (2006-05-05):
+# http://www.elnuevodiario.com.ni/2006/05/01/nacionales/18410
+# (my informal translation)
+# By order of the president of the republic, Enrique Bolanos, Nicaragua
+# advanced by sixty minutes their official time, yesterday at 2 in the
+# morning, and will stay that way until 30.th. of september.
+#
+# From Jesper Norgaard Welen (2006-09-30):
+# http://www.presidencia.gob.ni/buscador_gaceta/BD/DECRETOS/2006/D-063-2006P-PRN-Cambio-Hora.pdf
+# My informal translation runs:
+# The natural sun time is restored in all the national territory, in that the
+# time is returned one hour at 01:00 am of October 1 of 2006.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Nic	1979	1980	-	Mar	Sun>=16	0:00	1:00	D
+Rule	Nic	1979	1980	-	Jun	Mon>=23	0:00	0	S
+Rule	Nic	2005	only	-	Apr	10	0:00	1:00	D
+Rule	Nic	2005	only	-	Oct	Sun>=1	0:00	0	S
+Rule	Nic	2006	only	-	Apr	30	2:00	1:00	D
+Rule	Nic	2006	only	-	Oct	Sun>=1	1:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Managua	-5:45:08 -	LMT	1890
+			-5:45:12 -	MMT	1934 Jun 23 # Managua Mean Time?
+			-6:00	-	CST	1973 May
+			-5:00	-	EST	1975 Feb 16
+			-6:00	Nic	C%sT	1992 Jan  1 4:00
+			-5:00	-	EST	1992 Sep 24
+			-6:00	-	CST	1993
+			-5:00	-	EST	1997
+			-6:00	Nic	C%sT
+
+# Panama
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Panama	-5:18:08 -	LMT	1890
+			-5:19:36 -	CMT	1908 Apr 22   # Colon Mean Time
+			-5:00	-	EST
+
+# Puerto Rico
+# There are too many San Juans elsewhere, so we'll use `Puerto_Rico'.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Puerto_Rico -4:24:25 -	LMT	1899 Mar 28 12:00    # San Juan
+			-4:00	-	AST	1942 May  3
+			-4:00	US	A%sT	1946
+			-4:00	-	AST
+
+# St Kitts-Nevis
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/St_Kitts	-4:10:52 -	LMT	1912 Mar 2	# Basseterre
+			-4:00	-	AST
+
+# St Lucia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/St_Lucia	-4:04:00 -	LMT	1890		# Castries
+			-4:04:00 -	CMT	1912	    # Castries Mean Time
+			-4:00	-	AST
+
+# St Pierre and Miquelon
+# There are too many St Pierres elsewhere, so we'll use `Miquelon'.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Miquelon	-3:44:40 -	LMT	1911 May 15	# St Pierre
+			-4:00	-	AST	1980 May
+			-3:00	-	PMST	1987 # Pierre & Miquelon Time
+			-3:00	Canada	PM%sT
+
+# St Vincent and the Grenadines
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/St_Vincent	-4:04:56 -	LMT	1890		# Kingstown
+			-4:04:56 -	KMT	1912	   # Kingstown Mean Time
+			-4:00	-	AST
+
+# Turks and Caicos
+#
+# From Chris Dunn in
+# 
+# (2007-03-15): In the Turks & Caicos Islands (America/Grand_Turk) the
+# daylight saving dates for time changes have been adjusted to match
+# the recent U.S. change of dates.
+#
+# From Brian Inglis (2007-04-28):
+# http://www.turksandcaicos.tc/calendar/index.htm [2007-04-26]
+# there is an entry for Nov 4 "Daylight Savings Time Ends 2007" and three
+# rows before that there is an out of date entry for Oct:
+# "Eastern Standard Times Begins 2007
+# Clocks are set back one hour at 2:00 a.m. local Daylight Saving Time"
+# indicating that the normal ET rules are followed.
+#
+# From Paul Eggert (2006-05-01):
+# Shanks & Pottenger say they use US DST rules, but IATA SSIM (1991/1998)
+# says they switch at midnight.  Go with Shanks & Pottenger.
+#
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	TC	1979	1986	-	Apr	lastSun	2:00	1:00	D
+Rule	TC	1979	2006	-	Oct	lastSun	2:00	0	S
+Rule	TC	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
+Rule	TC	2007	max	-	Mar	Sun>=8	2:00	1:00	D
+Rule	TC	2007	max	-	Nov	Sun>=1	2:00	0	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Grand_Turk	-4:44:32 -	LMT	1890
+			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
+			-5:00	TC	E%sT
+
+# British Virgin Is
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Tortola	-4:18:28 -	LMT	1911 Jul    # Road Town
+			-4:00	-	AST
+
+# Virgin Is
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/St_Thomas	-4:19:44 -	LMT	1911 Jul    # Charlotte Amalie
+			-4:00	-	AST
diff --git a/extra/zoneinfo/pacificnew b/extra/zoneinfo/pacificnew
new file mode 100644
index 0000000000..667940bf53
--- /dev/null
+++ b/extra/zoneinfo/pacificnew
@@ -0,0 +1,26 @@
+# @(#)pacificnew	8.1
+
+# From Arthur David Olson (1989-04-05):
+# On 1989-04-05, the U. S. House of Representatives passed (238-154) a bill
+# establishing "Pacific Presidential Election Time"; it was not acted on
+# by the Senate or signed into law by the President.
+# You might want to change the "PE" (Presidential Election) below to
+# "Q" (Quadrennial) to maintain three-character zone abbreviations.
+# If you're really conservative, you might want to change it to "D".
+# Avoid "L" (Leap Year), which won't be true in 2100.
+
+# If Presidential Election Time is ever established, replace "XXXX" below
+# with the year the law takes effect and uncomment the "##" lines.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+## Rule	Twilite	XXXX	max	-	Apr	Sun>=1	2:00	1:00	D
+## Rule	Twilite	XXXX	max	uspres	Oct	lastSun	2:00	1:00	PE
+## Rule	Twilite	XXXX	max	uspres	Nov	Sun>=7	2:00	0	S
+## Rule	Twilite	XXXX	max	nonpres	Oct	lastSun	2:00	0	S
+
+# Zone	NAME			GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
+## Zone	America/Los_Angeles-PET	-8:00	US		P%sT	XXXX
+##				-8:00	Twilite		P%sT
+
+# For now...
+Link	America/Los_Angeles	US/Pacific-New	##
diff --git a/extra/zoneinfo/solar87 b/extra/zoneinfo/solar87
new file mode 100644
index 0000000000..71839320ad
--- /dev/null
+++ b/extra/zoneinfo/solar87
@@ -0,0 +1,388 @@
+# @(#)solar87	8.1
+
+# So much for footnotes about Saudi Arabia.
+# Apparent noon times below are for Riyadh; your mileage will vary.
+# Times were computed using formulas in the U.S. Naval Observatory's
+# Almanac for Computers 1987; the formulas "will give EqT to an accuracy of
+# [plus or minus two] seconds during the current year."
+#
+# Rounding to the nearest five seconds results in fewer than
+# 256 different "time types"--a limit that's faced because time types are
+# stored on disk as unsigned chars.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	sol87	1987	only	-	Jan	1	12:03:20s -0:03:20 -
+Rule	sol87	1987	only	-	Jan	2	12:03:50s -0:03:50 -
+Rule	sol87	1987	only	-	Jan	3	12:04:15s -0:04:15 -
+Rule	sol87	1987	only	-	Jan	4	12:04:45s -0:04:45 -
+Rule	sol87	1987	only	-	Jan	5	12:05:10s -0:05:10 -
+Rule	sol87	1987	only	-	Jan	6	12:05:40s -0:05:40 -
+Rule	sol87	1987	only	-	Jan	7	12:06:05s -0:06:05 -
+Rule	sol87	1987	only	-	Jan	8	12:06:30s -0:06:30 -
+Rule	sol87	1987	only	-	Jan	9	12:06:55s -0:06:55 -
+Rule	sol87	1987	only	-	Jan	10	12:07:20s -0:07:20 -
+Rule	sol87	1987	only	-	Jan	11	12:07:45s -0:07:45 -
+Rule	sol87	1987	only	-	Jan	12	12:08:10s -0:08:10 -
+Rule	sol87	1987	only	-	Jan	13	12:08:30s -0:08:30 -
+Rule	sol87	1987	only	-	Jan	14	12:08:55s -0:08:55 -
+Rule	sol87	1987	only	-	Jan	15	12:09:15s -0:09:15 -
+Rule	sol87	1987	only	-	Jan	16	12:09:35s -0:09:35 -
+Rule	sol87	1987	only	-	Jan	17	12:09:55s -0:09:55 -
+Rule	sol87	1987	only	-	Jan	18	12:10:15s -0:10:15 -
+Rule	sol87	1987	only	-	Jan	19	12:10:35s -0:10:35 -
+Rule	sol87	1987	only	-	Jan	20	12:10:55s -0:10:55 -
+Rule	sol87	1987	only	-	Jan	21	12:11:10s -0:11:10 -
+Rule	sol87	1987	only	-	Jan	22	12:11:30s -0:11:30 -
+Rule	sol87	1987	only	-	Jan	23	12:11:45s -0:11:45 -
+Rule	sol87	1987	only	-	Jan	24	12:12:00s -0:12:00 -
+Rule	sol87	1987	only	-	Jan	25	12:12:15s -0:12:15 -
+Rule	sol87	1987	only	-	Jan	26	12:12:30s -0:12:30 -
+Rule	sol87	1987	only	-	Jan	27	12:12:40s -0:12:40 -
+Rule	sol87	1987	only	-	Jan	28	12:12:55s -0:12:55 -
+Rule	sol87	1987	only	-	Jan	29	12:13:05s -0:13:05 -
+Rule	sol87	1987	only	-	Jan	30	12:13:15s -0:13:15 -
+Rule	sol87	1987	only	-	Jan	31	12:13:25s -0:13:25 -
+Rule	sol87	1987	only	-	Feb	1	12:13:35s -0:13:35 -
+Rule	sol87	1987	only	-	Feb	2	12:13:40s -0:13:40 -
+Rule	sol87	1987	only	-	Feb	3	12:13:50s -0:13:50 -
+Rule	sol87	1987	only	-	Feb	4	12:13:55s -0:13:55 -
+Rule	sol87	1987	only	-	Feb	5	12:14:00s -0:14:00 -
+Rule	sol87	1987	only	-	Feb	6	12:14:05s -0:14:05 -
+Rule	sol87	1987	only	-	Feb	7	12:14:10s -0:14:10 -
+Rule	sol87	1987	only	-	Feb	8	12:14:10s -0:14:10 -
+Rule	sol87	1987	only	-	Feb	9	12:14:15s -0:14:15 -
+Rule	sol87	1987	only	-	Feb	10	12:14:15s -0:14:15 -
+Rule	sol87	1987	only	-	Feb	11	12:14:15s -0:14:15 -
+Rule	sol87	1987	only	-	Feb	12	12:14:15s -0:14:15 -
+Rule	sol87	1987	only	-	Feb	13	12:14:15s -0:14:15 -
+Rule	sol87	1987	only	-	Feb	14	12:14:15s -0:14:15 -
+Rule	sol87	1987	only	-	Feb	15	12:14:10s -0:14:10 -
+Rule	sol87	1987	only	-	Feb	16	12:14:10s -0:14:10 -
+Rule	sol87	1987	only	-	Feb	17	12:14:05s -0:14:05 -
+Rule	sol87	1987	only	-	Feb	18	12:14:00s -0:14:00 -
+Rule	sol87	1987	only	-	Feb	19	12:13:55s -0:13:55 -
+Rule	sol87	1987	only	-	Feb	20	12:13:50s -0:13:50 -
+Rule	sol87	1987	only	-	Feb	21	12:13:45s -0:13:45 -
+Rule	sol87	1987	only	-	Feb	22	12:13:35s -0:13:35 -
+Rule	sol87	1987	only	-	Feb	23	12:13:30s -0:13:30 -
+Rule	sol87	1987	only	-	Feb	24	12:13:20s -0:13:20 -
+Rule	sol87	1987	only	-	Feb	25	12:13:10s -0:13:10 -
+Rule	sol87	1987	only	-	Feb	26	12:13:00s -0:13:00 -
+Rule	sol87	1987	only	-	Feb	27	12:12:50s -0:12:50 -
+Rule	sol87	1987	only	-	Feb	28	12:12:40s -0:12:40 -
+Rule	sol87	1987	only	-	Mar	1	12:12:30s -0:12:30 -
+Rule	sol87	1987	only	-	Mar	2	12:12:20s -0:12:20 -
+Rule	sol87	1987	only	-	Mar	3	12:12:05s -0:12:05 -
+Rule	sol87	1987	only	-	Mar	4	12:11:55s -0:11:55 -
+Rule	sol87	1987	only	-	Mar	5	12:11:40s -0:11:40 -
+Rule	sol87	1987	only	-	Mar	6	12:11:25s -0:11:25 -
+Rule	sol87	1987	only	-	Mar	7	12:11:15s -0:11:15 -
+Rule	sol87	1987	only	-	Mar	8	12:11:00s -0:11:00 -
+Rule	sol87	1987	only	-	Mar	9	12:10:45s -0:10:45 -
+Rule	sol87	1987	only	-	Mar	10	12:10:30s -0:10:30 -
+Rule	sol87	1987	only	-	Mar	11	12:10:15s -0:10:15 -
+Rule	sol87	1987	only	-	Mar	12	12:09:55s -0:09:55 -
+Rule	sol87	1987	only	-	Mar	13	12:09:40s -0:09:40 -
+Rule	sol87	1987	only	-	Mar	14	12:09:25s -0:09:25 -
+Rule	sol87	1987	only	-	Mar	15	12:09:10s -0:09:10 -
+Rule	sol87	1987	only	-	Mar	16	12:08:50s -0:08:50 -
+Rule	sol87	1987	only	-	Mar	17	12:08:35s -0:08:35 -
+Rule	sol87	1987	only	-	Mar	18	12:08:15s -0:08:15 -
+Rule	sol87	1987	only	-	Mar	19	12:08:00s -0:08:00 -
+Rule	sol87	1987	only	-	Mar	20	12:07:40s -0:07:40 -
+Rule	sol87	1987	only	-	Mar	21	12:07:25s -0:07:25 -
+Rule	sol87	1987	only	-	Mar	22	12:07:05s -0:07:05 -
+Rule	sol87	1987	only	-	Mar	23	12:06:50s -0:06:50 -
+Rule	sol87	1987	only	-	Mar	24	12:06:30s -0:06:30 -
+Rule	sol87	1987	only	-	Mar	25	12:06:10s -0:06:10 -
+Rule	sol87	1987	only	-	Mar	26	12:05:55s -0:05:55 -
+Rule	sol87	1987	only	-	Mar	27	12:05:35s -0:05:35 -
+Rule	sol87	1987	only	-	Mar	28	12:05:15s -0:05:15 -
+Rule	sol87	1987	only	-	Mar	29	12:05:00s -0:05:00 -
+Rule	sol87	1987	only	-	Mar	30	12:04:40s -0:04:40 -
+Rule	sol87	1987	only	-	Mar	31	12:04:25s -0:04:25 -
+Rule	sol87	1987	only	-	Apr	1	12:04:05s -0:04:05 -
+Rule	sol87	1987	only	-	Apr	2	12:03:45s -0:03:45 -
+Rule	sol87	1987	only	-	Apr	3	12:03:30s -0:03:30 -
+Rule	sol87	1987	only	-	Apr	4	12:03:10s -0:03:10 -
+Rule	sol87	1987	only	-	Apr	5	12:02:55s -0:02:55 -
+Rule	sol87	1987	only	-	Apr	6	12:02:35s -0:02:35 -
+Rule	sol87	1987	only	-	Apr	7	12:02:20s -0:02:20 -
+Rule	sol87	1987	only	-	Apr	8	12:02:05s -0:02:05 -
+Rule	sol87	1987	only	-	Apr	9	12:01:45s -0:01:45 -
+Rule	sol87	1987	only	-	Apr	10	12:01:30s -0:01:30 -
+Rule	sol87	1987	only	-	Apr	11	12:01:15s -0:01:15 -
+Rule	sol87	1987	only	-	Apr	12	12:00:55s -0:00:55 -
+Rule	sol87	1987	only	-	Apr	13	12:00:40s -0:00:40 -
+Rule	sol87	1987	only	-	Apr	14	12:00:25s -0:00:25 -
+Rule	sol87	1987	only	-	Apr	15	12:00:10s -0:00:10 -
+Rule	sol87	1987	only	-	Apr	16	11:59:55s 0:00:05 -
+Rule	sol87	1987	only	-	Apr	17	11:59:45s 0:00:15 -
+Rule	sol87	1987	only	-	Apr	18	11:59:30s 0:00:30 -
+Rule	sol87	1987	only	-	Apr	19	11:59:15s 0:00:45 -
+Rule	sol87	1987	only	-	Apr	20	11:59:05s 0:00:55 -
+Rule	sol87	1987	only	-	Apr	21	11:58:50s 0:01:10 -
+Rule	sol87	1987	only	-	Apr	22	11:58:40s 0:01:20 -
+Rule	sol87	1987	only	-	Apr	23	11:58:25s 0:01:35 -
+Rule	sol87	1987	only	-	Apr	24	11:58:15s 0:01:45 -
+Rule	sol87	1987	only	-	Apr	25	11:58:05s 0:01:55 -
+Rule	sol87	1987	only	-	Apr	26	11:57:55s 0:02:05 -
+Rule	sol87	1987	only	-	Apr	27	11:57:45s 0:02:15 -
+Rule	sol87	1987	only	-	Apr	28	11:57:35s 0:02:25 -
+Rule	sol87	1987	only	-	Apr	29	11:57:25s 0:02:35 -
+Rule	sol87	1987	only	-	Apr	30	11:57:15s 0:02:45 -
+Rule	sol87	1987	only	-	May	1	11:57:10s 0:02:50 -
+Rule	sol87	1987	only	-	May	2	11:57:00s 0:03:00 -
+Rule	sol87	1987	only	-	May	3	11:56:55s 0:03:05 -
+Rule	sol87	1987	only	-	May	4	11:56:50s 0:03:10 -
+Rule	sol87	1987	only	-	May	5	11:56:45s 0:03:15 -
+Rule	sol87	1987	only	-	May	6	11:56:40s 0:03:20 -
+Rule	sol87	1987	only	-	May	7	11:56:35s 0:03:25 -
+Rule	sol87	1987	only	-	May	8	11:56:30s 0:03:30 -
+Rule	sol87	1987	only	-	May	9	11:56:25s 0:03:35 -
+Rule	sol87	1987	only	-	May	10	11:56:25s 0:03:35 -
+Rule	sol87	1987	only	-	May	11	11:56:20s 0:03:40 -
+Rule	sol87	1987	only	-	May	12	11:56:20s 0:03:40 -
+Rule	sol87	1987	only	-	May	13	11:56:20s 0:03:40 -
+Rule	sol87	1987	only	-	May	14	11:56:20s 0:03:40 -
+Rule	sol87	1987	only	-	May	15	11:56:20s 0:03:40 -
+Rule	sol87	1987	only	-	May	16	11:56:20s 0:03:40 -
+Rule	sol87	1987	only	-	May	17	11:56:20s 0:03:40 -
+Rule	sol87	1987	only	-	May	18	11:56:20s 0:03:40 -
+Rule	sol87	1987	only	-	May	19	11:56:25s 0:03:35 -
+Rule	sol87	1987	only	-	May	20	11:56:25s 0:03:35 -
+Rule	sol87	1987	only	-	May	21	11:56:30s 0:03:30 -
+Rule	sol87	1987	only	-	May	22	11:56:35s 0:03:25 -
+Rule	sol87	1987	only	-	May	23	11:56:40s 0:03:20 -
+Rule	sol87	1987	only	-	May	24	11:56:45s 0:03:15 -
+Rule	sol87	1987	only	-	May	25	11:56:50s 0:03:10 -
+Rule	sol87	1987	only	-	May	26	11:56:55s 0:03:05 -
+Rule	sol87	1987	only	-	May	27	11:57:00s 0:03:00 -
+Rule	sol87	1987	only	-	May	28	11:57:10s 0:02:50 -
+Rule	sol87	1987	only	-	May	29	11:57:15s 0:02:45 -
+Rule	sol87	1987	only	-	May	30	11:57:25s 0:02:35 -
+Rule	sol87	1987	only	-	May	31	11:57:30s 0:02:30 -
+Rule	sol87	1987	only	-	Jun	1	11:57:40s 0:02:20 -
+Rule	sol87	1987	only	-	Jun	2	11:57:50s 0:02:10 -
+Rule	sol87	1987	only	-	Jun	3	11:58:00s 0:02:00 -
+Rule	sol87	1987	only	-	Jun	4	11:58:10s 0:01:50 -
+Rule	sol87	1987	only	-	Jun	5	11:58:20s 0:01:40 -
+Rule	sol87	1987	only	-	Jun	6	11:58:30s 0:01:30 -
+Rule	sol87	1987	only	-	Jun	7	11:58:40s 0:01:20 -
+Rule	sol87	1987	only	-	Jun	8	11:58:50s 0:01:10 -
+Rule	sol87	1987	only	-	Jun	9	11:59:05s 0:00:55 -
+Rule	sol87	1987	only	-	Jun	10	11:59:15s 0:00:45 -
+Rule	sol87	1987	only	-	Jun	11	11:59:30s 0:00:30 -
+Rule	sol87	1987	only	-	Jun	12	11:59:40s 0:00:20 -
+Rule	sol87	1987	only	-	Jun	13	11:59:50s 0:00:10 -
+Rule	sol87	1987	only	-	Jun	14	12:00:05s -0:00:05 -
+Rule	sol87	1987	only	-	Jun	15	12:00:15s -0:00:15 -
+Rule	sol87	1987	only	-	Jun	16	12:00:30s -0:00:30 -
+Rule	sol87	1987	only	-	Jun	17	12:00:45s -0:00:45 -
+Rule	sol87	1987	only	-	Jun	18	12:00:55s -0:00:55 -
+Rule	sol87	1987	only	-	Jun	19	12:01:10s -0:01:10 -
+Rule	sol87	1987	only	-	Jun	20	12:01:20s -0:01:20 -
+Rule	sol87	1987	only	-	Jun	21	12:01:35s -0:01:35 -
+Rule	sol87	1987	only	-	Jun	22	12:01:50s -0:01:50 -
+Rule	sol87	1987	only	-	Jun	23	12:02:00s -0:02:00 -
+Rule	sol87	1987	only	-	Jun	24	12:02:15s -0:02:15 -
+Rule	sol87	1987	only	-	Jun	25	12:02:25s -0:02:25 -
+Rule	sol87	1987	only	-	Jun	26	12:02:40s -0:02:40 -
+Rule	sol87	1987	only	-	Jun	27	12:02:50s -0:02:50 -
+Rule	sol87	1987	only	-	Jun	28	12:03:05s -0:03:05 -
+Rule	sol87	1987	only	-	Jun	29	12:03:15s -0:03:15 -
+Rule	sol87	1987	only	-	Jun	30	12:03:30s -0:03:30 -
+Rule	sol87	1987	only	-	Jul	1	12:03:40s -0:03:40 -
+Rule	sol87	1987	only	-	Jul	2	12:03:50s -0:03:50 -
+Rule	sol87	1987	only	-	Jul	3	12:04:05s -0:04:05 -
+Rule	sol87	1987	only	-	Jul	4	12:04:15s -0:04:15 -
+Rule	sol87	1987	only	-	Jul	5	12:04:25s -0:04:25 -
+Rule	sol87	1987	only	-	Jul	6	12:04:35s -0:04:35 -
+Rule	sol87	1987	only	-	Jul	7	12:04:45s -0:04:45 -
+Rule	sol87	1987	only	-	Jul	8	12:04:55s -0:04:55 -
+Rule	sol87	1987	only	-	Jul	9	12:05:05s -0:05:05 -
+Rule	sol87	1987	only	-	Jul	10	12:05:15s -0:05:15 -
+Rule	sol87	1987	only	-	Jul	11	12:05:20s -0:05:20 -
+Rule	sol87	1987	only	-	Jul	12	12:05:30s -0:05:30 -
+Rule	sol87	1987	only	-	Jul	13	12:05:40s -0:05:40 -
+Rule	sol87	1987	only	-	Jul	14	12:05:45s -0:05:45 -
+Rule	sol87	1987	only	-	Jul	15	12:05:50s -0:05:50 -
+Rule	sol87	1987	only	-	Jul	16	12:06:00s -0:06:00 -
+Rule	sol87	1987	only	-	Jul	17	12:06:05s -0:06:05 -
+Rule	sol87	1987	only	-	Jul	18	12:06:10s -0:06:10 -
+Rule	sol87	1987	only	-	Jul	19	12:06:15s -0:06:15 -
+Rule	sol87	1987	only	-	Jul	20	12:06:15s -0:06:15 -
+Rule	sol87	1987	only	-	Jul	21	12:06:20s -0:06:20 -
+Rule	sol87	1987	only	-	Jul	22	12:06:25s -0:06:25 -
+Rule	sol87	1987	only	-	Jul	23	12:06:25s -0:06:25 -
+Rule	sol87	1987	only	-	Jul	24	12:06:25s -0:06:25 -
+Rule	sol87	1987	only	-	Jul	25	12:06:30s -0:06:30 -
+Rule	sol87	1987	only	-	Jul	26	12:06:30s -0:06:30 -
+Rule	sol87	1987	only	-	Jul	27	12:06:30s -0:06:30 -
+Rule	sol87	1987	only	-	Jul	28	12:06:30s -0:06:30 -
+Rule	sol87	1987	only	-	Jul	29	12:06:25s -0:06:25 -
+Rule	sol87	1987	only	-	Jul	30	12:06:25s -0:06:25 -
+Rule	sol87	1987	only	-	Jul	31	12:06:25s -0:06:25 -
+Rule	sol87	1987	only	-	Aug	1	12:06:20s -0:06:20 -
+Rule	sol87	1987	only	-	Aug	2	12:06:15s -0:06:15 -
+Rule	sol87	1987	only	-	Aug	3	12:06:10s -0:06:10 -
+Rule	sol87	1987	only	-	Aug	4	12:06:05s -0:06:05 -
+Rule	sol87	1987	only	-	Aug	5	12:06:00s -0:06:00 -
+Rule	sol87	1987	only	-	Aug	6	12:05:55s -0:05:55 -
+Rule	sol87	1987	only	-	Aug	7	12:05:50s -0:05:50 -
+Rule	sol87	1987	only	-	Aug	8	12:05:40s -0:05:40 -
+Rule	sol87	1987	only	-	Aug	9	12:05:35s -0:05:35 -
+Rule	sol87	1987	only	-	Aug	10	12:05:25s -0:05:25 -
+Rule	sol87	1987	only	-	Aug	11	12:05:15s -0:05:15 -
+Rule	sol87	1987	only	-	Aug	12	12:05:05s -0:05:05 -
+Rule	sol87	1987	only	-	Aug	13	12:04:55s -0:04:55 -
+Rule	sol87	1987	only	-	Aug	14	12:04:45s -0:04:45 -
+Rule	sol87	1987	only	-	Aug	15	12:04:35s -0:04:35 -
+Rule	sol87	1987	only	-	Aug	16	12:04:25s -0:04:25 -
+Rule	sol87	1987	only	-	Aug	17	12:04:10s -0:04:10 -
+Rule	sol87	1987	only	-	Aug	18	12:04:00s -0:04:00 -
+Rule	sol87	1987	only	-	Aug	19	12:03:45s -0:03:45 -
+Rule	sol87	1987	only	-	Aug	20	12:03:30s -0:03:30 -
+Rule	sol87	1987	only	-	Aug	21	12:03:15s -0:03:15 -
+Rule	sol87	1987	only	-	Aug	22	12:03:00s -0:03:00 -
+Rule	sol87	1987	only	-	Aug	23	12:02:45s -0:02:45 -
+Rule	sol87	1987	only	-	Aug	24	12:02:30s -0:02:30 -
+Rule	sol87	1987	only	-	Aug	25	12:02:15s -0:02:15 -
+Rule	sol87	1987	only	-	Aug	26	12:02:00s -0:02:00 -
+Rule	sol87	1987	only	-	Aug	27	12:01:40s -0:01:40 -
+Rule	sol87	1987	only	-	Aug	28	12:01:25s -0:01:25 -
+Rule	sol87	1987	only	-	Aug	29	12:01:05s -0:01:05 -
+Rule	sol87	1987	only	-	Aug	30	12:00:50s -0:00:50 -
+Rule	sol87	1987	only	-	Aug	31	12:00:30s -0:00:30 -
+Rule	sol87	1987	only	-	Sep	1	12:00:10s -0:00:10 -
+Rule	sol87	1987	only	-	Sep	2	11:59:50s 0:00:10 -
+Rule	sol87	1987	only	-	Sep	3	11:59:35s 0:00:25 -
+Rule	sol87	1987	only	-	Sep	4	11:59:15s 0:00:45 -
+Rule	sol87	1987	only	-	Sep	5	11:58:55s 0:01:05 -
+Rule	sol87	1987	only	-	Sep	6	11:58:35s 0:01:25 -
+Rule	sol87	1987	only	-	Sep	7	11:58:15s 0:01:45 -
+Rule	sol87	1987	only	-	Sep	8	11:57:55s 0:02:05 -
+Rule	sol87	1987	only	-	Sep	9	11:57:30s 0:02:30 -
+Rule	sol87	1987	only	-	Sep	10	11:57:10s 0:02:50 -
+Rule	sol87	1987	only	-	Sep	11	11:56:50s 0:03:10 -
+Rule	sol87	1987	only	-	Sep	12	11:56:30s 0:03:30 -
+Rule	sol87	1987	only	-	Sep	13	11:56:10s 0:03:50 -
+Rule	sol87	1987	only	-	Sep	14	11:55:45s 0:04:15 -
+Rule	sol87	1987	only	-	Sep	15	11:55:25s 0:04:35 -
+Rule	sol87	1987	only	-	Sep	16	11:55:05s 0:04:55 -
+Rule	sol87	1987	only	-	Sep	17	11:54:45s 0:05:15 -
+Rule	sol87	1987	only	-	Sep	18	11:54:20s 0:05:40 -
+Rule	sol87	1987	only	-	Sep	19	11:54:00s 0:06:00 -
+Rule	sol87	1987	only	-	Sep	20	11:53:40s 0:06:20 -
+Rule	sol87	1987	only	-	Sep	21	11:53:15s 0:06:45 -
+Rule	sol87	1987	only	-	Sep	22	11:52:55s 0:07:05 -
+Rule	sol87	1987	only	-	Sep	23	11:52:35s 0:07:25 -
+Rule	sol87	1987	only	-	Sep	24	11:52:15s 0:07:45 -
+Rule	sol87	1987	only	-	Sep	25	11:51:55s 0:08:05 -
+Rule	sol87	1987	only	-	Sep	26	11:51:35s 0:08:25 -
+Rule	sol87	1987	only	-	Sep	27	11:51:10s 0:08:50 -
+Rule	sol87	1987	only	-	Sep	28	11:50:50s 0:09:10 -
+Rule	sol87	1987	only	-	Sep	29	11:50:30s 0:09:30 -
+Rule	sol87	1987	only	-	Sep	30	11:50:10s 0:09:50 -
+Rule	sol87	1987	only	-	Oct	1	11:49:50s 0:10:10 -
+Rule	sol87	1987	only	-	Oct	2	11:49:35s 0:10:25 -
+Rule	sol87	1987	only	-	Oct	3	11:49:15s 0:10:45 -
+Rule	sol87	1987	only	-	Oct	4	11:48:55s 0:11:05 -
+Rule	sol87	1987	only	-	Oct	5	11:48:35s 0:11:25 -
+Rule	sol87	1987	only	-	Oct	6	11:48:20s 0:11:40 -
+Rule	sol87	1987	only	-	Oct	7	11:48:00s 0:12:00 -
+Rule	sol87	1987	only	-	Oct	8	11:47:45s 0:12:15 -
+Rule	sol87	1987	only	-	Oct	9	11:47:25s 0:12:35 -
+Rule	sol87	1987	only	-	Oct	10	11:47:10s 0:12:50 -
+Rule	sol87	1987	only	-	Oct	11	11:46:55s 0:13:05 -
+Rule	sol87	1987	only	-	Oct	12	11:46:40s 0:13:20 -
+Rule	sol87	1987	only	-	Oct	13	11:46:25s 0:13:35 -
+Rule	sol87	1987	only	-	Oct	14	11:46:10s 0:13:50 -
+Rule	sol87	1987	only	-	Oct	15	11:45:55s 0:14:05 -
+Rule	sol87	1987	only	-	Oct	16	11:45:45s 0:14:15 -
+Rule	sol87	1987	only	-	Oct	17	11:45:30s 0:14:30 -
+Rule	sol87	1987	only	-	Oct	18	11:45:20s 0:14:40 -
+Rule	sol87	1987	only	-	Oct	19	11:45:05s 0:14:55 -
+Rule	sol87	1987	only	-	Oct	20	11:44:55s 0:15:05 -
+Rule	sol87	1987	only	-	Oct	21	11:44:45s 0:15:15 -
+Rule	sol87	1987	only	-	Oct	22	11:44:35s 0:15:25 -
+Rule	sol87	1987	only	-	Oct	23	11:44:25s 0:15:35 -
+Rule	sol87	1987	only	-	Oct	24	11:44:20s 0:15:40 -
+Rule	sol87	1987	only	-	Oct	25	11:44:10s 0:15:50 -
+Rule	sol87	1987	only	-	Oct	26	11:44:05s 0:15:55 -
+Rule	sol87	1987	only	-	Oct	27	11:43:55s 0:16:05 -
+Rule	sol87	1987	only	-	Oct	28	11:43:50s 0:16:10 -
+Rule	sol87	1987	only	-	Oct	29	11:43:45s 0:16:15 -
+Rule	sol87	1987	only	-	Oct	30	11:43:45s 0:16:15 -
+Rule	sol87	1987	only	-	Oct	31	11:43:40s 0:16:20 -
+Rule	sol87	1987	only	-	Nov	1	11:43:40s 0:16:20 -
+Rule	sol87	1987	only	-	Nov	2	11:43:35s 0:16:25 -
+Rule	sol87	1987	only	-	Nov	3	11:43:35s 0:16:25 -
+Rule	sol87	1987	only	-	Nov	4	11:43:35s 0:16:25 -
+Rule	sol87	1987	only	-	Nov	5	11:43:35s 0:16:25 -
+Rule	sol87	1987	only	-	Nov	6	11:43:40s 0:16:20 -
+Rule	sol87	1987	only	-	Nov	7	11:43:40s 0:16:20 -
+Rule	sol87	1987	only	-	Nov	8	11:43:45s 0:16:15 -
+Rule	sol87	1987	only	-	Nov	9	11:43:50s 0:16:10 -
+Rule	sol87	1987	only	-	Nov	10	11:43:55s 0:16:05 -
+Rule	sol87	1987	only	-	Nov	11	11:44:00s 0:16:00 -
+Rule	sol87	1987	only	-	Nov	12	11:44:05s 0:15:55 -
+Rule	sol87	1987	only	-	Nov	13	11:44:15s 0:15:45 -
+Rule	sol87	1987	only	-	Nov	14	11:44:20s 0:15:40 -
+Rule	sol87	1987	only	-	Nov	15	11:44:30s 0:15:30 -
+Rule	sol87	1987	only	-	Nov	16	11:44:40s 0:15:20 -
+Rule	sol87	1987	only	-	Nov	17	11:44:50s 0:15:10 -
+Rule	sol87	1987	only	-	Nov	18	11:45:05s 0:14:55 -
+Rule	sol87	1987	only	-	Nov	19	11:45:15s 0:14:45 -
+Rule	sol87	1987	only	-	Nov	20	11:45:30s 0:14:30 -
+Rule	sol87	1987	only	-	Nov	21	11:45:45s 0:14:15 -
+Rule	sol87	1987	only	-	Nov	22	11:46:00s 0:14:00 -
+Rule	sol87	1987	only	-	Nov	23	11:46:15s 0:13:45 -
+Rule	sol87	1987	only	-	Nov	24	11:46:30s 0:13:30 -
+Rule	sol87	1987	only	-	Nov	25	11:46:50s 0:13:10 -
+Rule	sol87	1987	only	-	Nov	26	11:47:10s 0:12:50 -
+Rule	sol87	1987	only	-	Nov	27	11:47:25s 0:12:35 -
+Rule	sol87	1987	only	-	Nov	28	11:47:45s 0:12:15 -
+Rule	sol87	1987	only	-	Nov	29	11:48:05s 0:11:55 -
+Rule	sol87	1987	only	-	Nov	30	11:48:30s 0:11:30 -
+Rule	sol87	1987	only	-	Dec	1	11:48:50s 0:11:10 -
+Rule	sol87	1987	only	-	Dec	2	11:49:10s 0:10:50 -
+Rule	sol87	1987	only	-	Dec	3	11:49:35s 0:10:25 -
+Rule	sol87	1987	only	-	Dec	4	11:50:00s 0:10:00 -
+Rule	sol87	1987	only	-	Dec	5	11:50:25s 0:09:35 -
+Rule	sol87	1987	only	-	Dec	6	11:50:50s 0:09:10 -
+Rule	sol87	1987	only	-	Dec	7	11:51:15s 0:08:45 -
+Rule	sol87	1987	only	-	Dec	8	11:51:40s 0:08:20 -
+Rule	sol87	1987	only	-	Dec	9	11:52:05s 0:07:55 -
+Rule	sol87	1987	only	-	Dec	10	11:52:30s 0:07:30 -
+Rule	sol87	1987	only	-	Dec	11	11:53:00s 0:07:00 -
+Rule	sol87	1987	only	-	Dec	12	11:53:25s 0:06:35 -
+Rule	sol87	1987	only	-	Dec	13	11:53:55s 0:06:05 -
+Rule	sol87	1987	only	-	Dec	14	11:54:25s 0:05:35 -
+Rule	sol87	1987	only	-	Dec	15	11:54:50s 0:05:10 -
+Rule	sol87	1987	only	-	Dec	16	11:55:20s 0:04:40 -
+Rule	sol87	1987	only	-	Dec	17	11:55:50s 0:04:10 -
+Rule	sol87	1987	only	-	Dec	18	11:56:20s 0:03:40 -
+Rule	sol87	1987	only	-	Dec	19	11:56:50s 0:03:10 -
+Rule	sol87	1987	only	-	Dec	20	11:57:20s 0:02:40 -
+Rule	sol87	1987	only	-	Dec	21	11:57:50s 0:02:10 -
+Rule	sol87	1987	only	-	Dec	22	11:58:20s 0:01:40 -
+Rule	sol87	1987	only	-	Dec	23	11:58:50s 0:01:10 -
+Rule	sol87	1987	only	-	Dec	24	11:59:20s 0:00:40 -
+Rule	sol87	1987	only	-	Dec	25	11:59:50s 0:00:10 -
+Rule	sol87	1987	only	-	Dec	26	12:00:20s -0:00:20 -
+Rule	sol87	1987	only	-	Dec	27	12:00:45s -0:00:45 -
+Rule	sol87	1987	only	-	Dec	28	12:01:15s -0:01:15 -
+Rule	sol87	1987	only	-	Dec	29	12:01:45s -0:01:45 -
+Rule	sol87	1987	only	-	Dec	30	12:02:15s -0:02:15 -
+Rule	sol87	1987	only	-	Dec	31	12:02:45s -0:02:45 -
+
+# Riyadh is at about 46 degrees 46 minutes East:  3 hrs, 7 mins, 4 secs
+# Before and after 1987, we'll operate on local mean solar time.
+
+# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
+Zone	Asia/Riyadh87	3:07:04	-		zzz	1987
+			3:07:04	sol87		zzz	1988
+			3:07:04	-		zzz
+# For backward compatibility...
+Link	Asia/Riyadh87	Mideast/Riyadh87
diff --git a/extra/zoneinfo/solar88 b/extra/zoneinfo/solar88
new file mode 100644
index 0000000000..b4cfe8e37a
--- /dev/null
+++ b/extra/zoneinfo/solar88
@@ -0,0 +1,388 @@
+# @(#)solar88	8.1
+
+# Apparent noon times below are for Riyadh; they're a bit off for other places.
+# Times were computed using formulas in the U.S. Naval Observatory's
+# Almanac for Computers 1988; the formulas "will give EqT to an accuracy of
+# [plus or minus two] seconds during the current year."
+#
+# Rounding to the nearest five seconds results in fewer than
+# 256 different "time types"--a limit that's faced because time types are
+# stored on disk as unsigned chars.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	sol88	1988	only	-	Jan	1	12:03:15s -0:03:15 -
+Rule	sol88	1988	only	-	Jan	2	12:03:40s -0:03:40 -
+Rule	sol88	1988	only	-	Jan	3	12:04:10s -0:04:10 -
+Rule	sol88	1988	only	-	Jan	4	12:04:40s -0:04:40 -
+Rule	sol88	1988	only	-	Jan	5	12:05:05s -0:05:05 -
+Rule	sol88	1988	only	-	Jan	6	12:05:30s -0:05:30 -
+Rule	sol88	1988	only	-	Jan	7	12:06:00s -0:06:00 -
+Rule	sol88	1988	only	-	Jan	8	12:06:25s -0:06:25 -
+Rule	sol88	1988	only	-	Jan	9	12:06:50s -0:06:50 -
+Rule	sol88	1988	only	-	Jan	10	12:07:15s -0:07:15 -
+Rule	sol88	1988	only	-	Jan	11	12:07:40s -0:07:40 -
+Rule	sol88	1988	only	-	Jan	12	12:08:05s -0:08:05 -
+Rule	sol88	1988	only	-	Jan	13	12:08:25s -0:08:25 -
+Rule	sol88	1988	only	-	Jan	14	12:08:50s -0:08:50 -
+Rule	sol88	1988	only	-	Jan	15	12:09:10s -0:09:10 -
+Rule	sol88	1988	only	-	Jan	16	12:09:30s -0:09:30 -
+Rule	sol88	1988	only	-	Jan	17	12:09:50s -0:09:50 -
+Rule	sol88	1988	only	-	Jan	18	12:10:10s -0:10:10 -
+Rule	sol88	1988	only	-	Jan	19	12:10:30s -0:10:30 -
+Rule	sol88	1988	only	-	Jan	20	12:10:50s -0:10:50 -
+Rule	sol88	1988	only	-	Jan	21	12:11:05s -0:11:05 -
+Rule	sol88	1988	only	-	Jan	22	12:11:25s -0:11:25 -
+Rule	sol88	1988	only	-	Jan	23	12:11:40s -0:11:40 -
+Rule	sol88	1988	only	-	Jan	24	12:11:55s -0:11:55 -
+Rule	sol88	1988	only	-	Jan	25	12:12:10s -0:12:10 -
+Rule	sol88	1988	only	-	Jan	26	12:12:25s -0:12:25 -
+Rule	sol88	1988	only	-	Jan	27	12:12:40s -0:12:40 -
+Rule	sol88	1988	only	-	Jan	28	12:12:50s -0:12:50 -
+Rule	sol88	1988	only	-	Jan	29	12:13:00s -0:13:00 -
+Rule	sol88	1988	only	-	Jan	30	12:13:10s -0:13:10 -
+Rule	sol88	1988	only	-	Jan	31	12:13:20s -0:13:20 -
+Rule	sol88	1988	only	-	Feb	1	12:13:30s -0:13:30 -
+Rule	sol88	1988	only	-	Feb	2	12:13:40s -0:13:40 -
+Rule	sol88	1988	only	-	Feb	3	12:13:45s -0:13:45 -
+Rule	sol88	1988	only	-	Feb	4	12:13:55s -0:13:55 -
+Rule	sol88	1988	only	-	Feb	5	12:14:00s -0:14:00 -
+Rule	sol88	1988	only	-	Feb	6	12:14:05s -0:14:05 -
+Rule	sol88	1988	only	-	Feb	7	12:14:10s -0:14:10 -
+Rule	sol88	1988	only	-	Feb	8	12:14:10s -0:14:10 -
+Rule	sol88	1988	only	-	Feb	9	12:14:15s -0:14:15 -
+Rule	sol88	1988	only	-	Feb	10	12:14:15s -0:14:15 -
+Rule	sol88	1988	only	-	Feb	11	12:14:15s -0:14:15 -
+Rule	sol88	1988	only	-	Feb	12	12:14:15s -0:14:15 -
+Rule	sol88	1988	only	-	Feb	13	12:14:15s -0:14:15 -
+Rule	sol88	1988	only	-	Feb	14	12:14:15s -0:14:15 -
+Rule	sol88	1988	only	-	Feb	15	12:14:10s -0:14:10 -
+Rule	sol88	1988	only	-	Feb	16	12:14:10s -0:14:10 -
+Rule	sol88	1988	only	-	Feb	17	12:14:05s -0:14:05 -
+Rule	sol88	1988	only	-	Feb	18	12:14:00s -0:14:00 -
+Rule	sol88	1988	only	-	Feb	19	12:13:55s -0:13:55 -
+Rule	sol88	1988	only	-	Feb	20	12:13:50s -0:13:50 -
+Rule	sol88	1988	only	-	Feb	21	12:13:45s -0:13:45 -
+Rule	sol88	1988	only	-	Feb	22	12:13:40s -0:13:40 -
+Rule	sol88	1988	only	-	Feb	23	12:13:30s -0:13:30 -
+Rule	sol88	1988	only	-	Feb	24	12:13:20s -0:13:20 -
+Rule	sol88	1988	only	-	Feb	25	12:13:15s -0:13:15 -
+Rule	sol88	1988	only	-	Feb	26	12:13:05s -0:13:05 -
+Rule	sol88	1988	only	-	Feb	27	12:12:55s -0:12:55 -
+Rule	sol88	1988	only	-	Feb	28	12:12:45s -0:12:45 -
+Rule	sol88	1988	only	-	Feb	29	12:12:30s -0:12:30 -
+Rule	sol88	1988	only	-	Mar	1	12:12:20s -0:12:20 -
+Rule	sol88	1988	only	-	Mar	2	12:12:10s -0:12:10 -
+Rule	sol88	1988	only	-	Mar	3	12:11:55s -0:11:55 -
+Rule	sol88	1988	only	-	Mar	4	12:11:45s -0:11:45 -
+Rule	sol88	1988	only	-	Mar	5	12:11:30s -0:11:30 -
+Rule	sol88	1988	only	-	Mar	6	12:11:15s -0:11:15 -
+Rule	sol88	1988	only	-	Mar	7	12:11:00s -0:11:00 -
+Rule	sol88	1988	only	-	Mar	8	12:10:45s -0:10:45 -
+Rule	sol88	1988	only	-	Mar	9	12:10:30s -0:10:30 -
+Rule	sol88	1988	only	-	Mar	10	12:10:15s -0:10:15 -
+Rule	sol88	1988	only	-	Mar	11	12:10:00s -0:10:00 -
+Rule	sol88	1988	only	-	Mar	12	12:09:45s -0:09:45 -
+Rule	sol88	1988	only	-	Mar	13	12:09:30s -0:09:30 -
+Rule	sol88	1988	only	-	Mar	14	12:09:10s -0:09:10 -
+Rule	sol88	1988	only	-	Mar	15	12:08:55s -0:08:55 -
+Rule	sol88	1988	only	-	Mar	16	12:08:40s -0:08:40 -
+Rule	sol88	1988	only	-	Mar	17	12:08:20s -0:08:20 -
+Rule	sol88	1988	only	-	Mar	18	12:08:05s -0:08:05 -
+Rule	sol88	1988	only	-	Mar	19	12:07:45s -0:07:45 -
+Rule	sol88	1988	only	-	Mar	20	12:07:30s -0:07:30 -
+Rule	sol88	1988	only	-	Mar	21	12:07:10s -0:07:10 -
+Rule	sol88	1988	only	-	Mar	22	12:06:50s -0:06:50 -
+Rule	sol88	1988	only	-	Mar	23	12:06:35s -0:06:35 -
+Rule	sol88	1988	only	-	Mar	24	12:06:15s -0:06:15 -
+Rule	sol88	1988	only	-	Mar	25	12:06:00s -0:06:00 -
+Rule	sol88	1988	only	-	Mar	26	12:05:40s -0:05:40 -
+Rule	sol88	1988	only	-	Mar	27	12:05:20s -0:05:20 -
+Rule	sol88	1988	only	-	Mar	28	12:05:05s -0:05:05 -
+Rule	sol88	1988	only	-	Mar	29	12:04:45s -0:04:45 -
+Rule	sol88	1988	only	-	Mar	30	12:04:25s -0:04:25 -
+Rule	sol88	1988	only	-	Mar	31	12:04:10s -0:04:10 -
+Rule	sol88	1988	only	-	Apr	1	12:03:50s -0:03:50 -
+Rule	sol88	1988	only	-	Apr	2	12:03:35s -0:03:35 -
+Rule	sol88	1988	only	-	Apr	3	12:03:15s -0:03:15 -
+Rule	sol88	1988	only	-	Apr	4	12:03:00s -0:03:00 -
+Rule	sol88	1988	only	-	Apr	5	12:02:40s -0:02:40 -
+Rule	sol88	1988	only	-	Apr	6	12:02:25s -0:02:25 -
+Rule	sol88	1988	only	-	Apr	7	12:02:05s -0:02:05 -
+Rule	sol88	1988	only	-	Apr	8	12:01:50s -0:01:50 -
+Rule	sol88	1988	only	-	Apr	9	12:01:35s -0:01:35 -
+Rule	sol88	1988	only	-	Apr	10	12:01:15s -0:01:15 -
+Rule	sol88	1988	only	-	Apr	11	12:01:00s -0:01:00 -
+Rule	sol88	1988	only	-	Apr	12	12:00:45s -0:00:45 -
+Rule	sol88	1988	only	-	Apr	13	12:00:30s -0:00:30 -
+Rule	sol88	1988	only	-	Apr	14	12:00:15s -0:00:15 -
+Rule	sol88	1988	only	-	Apr	15	12:00:00s 0:00:00 -
+Rule	sol88	1988	only	-	Apr	16	11:59:45s 0:00:15 -
+Rule	sol88	1988	only	-	Apr	17	11:59:30s 0:00:30 -
+Rule	sol88	1988	only	-	Apr	18	11:59:20s 0:00:40 -
+Rule	sol88	1988	only	-	Apr	19	11:59:05s 0:00:55 -
+Rule	sol88	1988	only	-	Apr	20	11:58:55s 0:01:05 -
+Rule	sol88	1988	only	-	Apr	21	11:58:40s 0:01:20 -
+Rule	sol88	1988	only	-	Apr	22	11:58:30s 0:01:30 -
+Rule	sol88	1988	only	-	Apr	23	11:58:15s 0:01:45 -
+Rule	sol88	1988	only	-	Apr	24	11:58:05s 0:01:55 -
+Rule	sol88	1988	only	-	Apr	25	11:57:55s 0:02:05 -
+Rule	sol88	1988	only	-	Apr	26	11:57:45s 0:02:15 -
+Rule	sol88	1988	only	-	Apr	27	11:57:35s 0:02:25 -
+Rule	sol88	1988	only	-	Apr	28	11:57:30s 0:02:30 -
+Rule	sol88	1988	only	-	Apr	29	11:57:20s 0:02:40 -
+Rule	sol88	1988	only	-	Apr	30	11:57:10s 0:02:50 -
+Rule	sol88	1988	only	-	May	1	11:57:05s 0:02:55 -
+Rule	sol88	1988	only	-	May	2	11:56:55s 0:03:05 -
+Rule	sol88	1988	only	-	May	3	11:56:50s 0:03:10 -
+Rule	sol88	1988	only	-	May	4	11:56:45s 0:03:15 -
+Rule	sol88	1988	only	-	May	5	11:56:40s 0:03:20 -
+Rule	sol88	1988	only	-	May	6	11:56:35s 0:03:25 -
+Rule	sol88	1988	only	-	May	7	11:56:30s 0:03:30 -
+Rule	sol88	1988	only	-	May	8	11:56:25s 0:03:35 -
+Rule	sol88	1988	only	-	May	9	11:56:25s 0:03:35 -
+Rule	sol88	1988	only	-	May	10	11:56:20s 0:03:40 -
+Rule	sol88	1988	only	-	May	11	11:56:20s 0:03:40 -
+Rule	sol88	1988	only	-	May	12	11:56:20s 0:03:40 -
+Rule	sol88	1988	only	-	May	13	11:56:20s 0:03:40 -
+Rule	sol88	1988	only	-	May	14	11:56:20s 0:03:40 -
+Rule	sol88	1988	only	-	May	15	11:56:20s 0:03:40 -
+Rule	sol88	1988	only	-	May	16	11:56:20s 0:03:40 -
+Rule	sol88	1988	only	-	May	17	11:56:20s 0:03:40 -
+Rule	sol88	1988	only	-	May	18	11:56:25s 0:03:35 -
+Rule	sol88	1988	only	-	May	19	11:56:25s 0:03:35 -
+Rule	sol88	1988	only	-	May	20	11:56:30s 0:03:30 -
+Rule	sol88	1988	only	-	May	21	11:56:35s 0:03:25 -
+Rule	sol88	1988	only	-	May	22	11:56:40s 0:03:20 -
+Rule	sol88	1988	only	-	May	23	11:56:45s 0:03:15 -
+Rule	sol88	1988	only	-	May	24	11:56:50s 0:03:10 -
+Rule	sol88	1988	only	-	May	25	11:56:55s 0:03:05 -
+Rule	sol88	1988	only	-	May	26	11:57:00s 0:03:00 -
+Rule	sol88	1988	only	-	May	27	11:57:05s 0:02:55 -
+Rule	sol88	1988	only	-	May	28	11:57:15s 0:02:45 -
+Rule	sol88	1988	only	-	May	29	11:57:20s 0:02:40 -
+Rule	sol88	1988	only	-	May	30	11:57:30s 0:02:30 -
+Rule	sol88	1988	only	-	May	31	11:57:40s 0:02:20 -
+Rule	sol88	1988	only	-	Jun	1	11:57:50s 0:02:10 -
+Rule	sol88	1988	only	-	Jun	2	11:57:55s 0:02:05 -
+Rule	sol88	1988	only	-	Jun	3	11:58:05s 0:01:55 -
+Rule	sol88	1988	only	-	Jun	4	11:58:15s 0:01:45 -
+Rule	sol88	1988	only	-	Jun	5	11:58:30s 0:01:30 -
+Rule	sol88	1988	only	-	Jun	6	11:58:40s 0:01:20 -
+Rule	sol88	1988	only	-	Jun	7	11:58:50s 0:01:10 -
+Rule	sol88	1988	only	-	Jun	8	11:59:00s 0:01:00 -
+Rule	sol88	1988	only	-	Jun	9	11:59:15s 0:00:45 -
+Rule	sol88	1988	only	-	Jun	10	11:59:25s 0:00:35 -
+Rule	sol88	1988	only	-	Jun	11	11:59:35s 0:00:25 -
+Rule	sol88	1988	only	-	Jun	12	11:59:50s 0:00:10 -
+Rule	sol88	1988	only	-	Jun	13	12:00:00s 0:00:00 -
+Rule	sol88	1988	only	-	Jun	14	12:00:15s -0:00:15 -
+Rule	sol88	1988	only	-	Jun	15	12:00:25s -0:00:25 -
+Rule	sol88	1988	only	-	Jun	16	12:00:40s -0:00:40 -
+Rule	sol88	1988	only	-	Jun	17	12:00:55s -0:00:55 -
+Rule	sol88	1988	only	-	Jun	18	12:01:05s -0:01:05 -
+Rule	sol88	1988	only	-	Jun	19	12:01:20s -0:01:20 -
+Rule	sol88	1988	only	-	Jun	20	12:01:30s -0:01:30 -
+Rule	sol88	1988	only	-	Jun	21	12:01:45s -0:01:45 -
+Rule	sol88	1988	only	-	Jun	22	12:02:00s -0:02:00 -
+Rule	sol88	1988	only	-	Jun	23	12:02:10s -0:02:10 -
+Rule	sol88	1988	only	-	Jun	24	12:02:25s -0:02:25 -
+Rule	sol88	1988	only	-	Jun	25	12:02:35s -0:02:35 -
+Rule	sol88	1988	only	-	Jun	26	12:02:50s -0:02:50 -
+Rule	sol88	1988	only	-	Jun	27	12:03:00s -0:03:00 -
+Rule	sol88	1988	only	-	Jun	28	12:03:15s -0:03:15 -
+Rule	sol88	1988	only	-	Jun	29	12:03:25s -0:03:25 -
+Rule	sol88	1988	only	-	Jun	30	12:03:40s -0:03:40 -
+Rule	sol88	1988	only	-	Jul	1	12:03:50s -0:03:50 -
+Rule	sol88	1988	only	-	Jul	2	12:04:00s -0:04:00 -
+Rule	sol88	1988	only	-	Jul	3	12:04:10s -0:04:10 -
+Rule	sol88	1988	only	-	Jul	4	12:04:25s -0:04:25 -
+Rule	sol88	1988	only	-	Jul	5	12:04:35s -0:04:35 -
+Rule	sol88	1988	only	-	Jul	6	12:04:45s -0:04:45 -
+Rule	sol88	1988	only	-	Jul	7	12:04:55s -0:04:55 -
+Rule	sol88	1988	only	-	Jul	8	12:05:05s -0:05:05 -
+Rule	sol88	1988	only	-	Jul	9	12:05:10s -0:05:10 -
+Rule	sol88	1988	only	-	Jul	10	12:05:20s -0:05:20 -
+Rule	sol88	1988	only	-	Jul	11	12:05:30s -0:05:30 -
+Rule	sol88	1988	only	-	Jul	12	12:05:35s -0:05:35 -
+Rule	sol88	1988	only	-	Jul	13	12:05:45s -0:05:45 -
+Rule	sol88	1988	only	-	Jul	14	12:05:50s -0:05:50 -
+Rule	sol88	1988	only	-	Jul	15	12:05:55s -0:05:55 -
+Rule	sol88	1988	only	-	Jul	16	12:06:00s -0:06:00 -
+Rule	sol88	1988	only	-	Jul	17	12:06:05s -0:06:05 -
+Rule	sol88	1988	only	-	Jul	18	12:06:10s -0:06:10 -
+Rule	sol88	1988	only	-	Jul	19	12:06:15s -0:06:15 -
+Rule	sol88	1988	only	-	Jul	20	12:06:20s -0:06:20 -
+Rule	sol88	1988	only	-	Jul	21	12:06:25s -0:06:25 -
+Rule	sol88	1988	only	-	Jul	22	12:06:25s -0:06:25 -
+Rule	sol88	1988	only	-	Jul	23	12:06:25s -0:06:25 -
+Rule	sol88	1988	only	-	Jul	24	12:06:30s -0:06:30 -
+Rule	sol88	1988	only	-	Jul	25	12:06:30s -0:06:30 -
+Rule	sol88	1988	only	-	Jul	26	12:06:30s -0:06:30 -
+Rule	sol88	1988	only	-	Jul	27	12:06:30s -0:06:30 -
+Rule	sol88	1988	only	-	Jul	28	12:06:30s -0:06:30 -
+Rule	sol88	1988	only	-	Jul	29	12:06:25s -0:06:25 -
+Rule	sol88	1988	only	-	Jul	30	12:06:25s -0:06:25 -
+Rule	sol88	1988	only	-	Jul	31	12:06:20s -0:06:20 -
+Rule	sol88	1988	only	-	Aug	1	12:06:15s -0:06:15 -
+Rule	sol88	1988	only	-	Aug	2	12:06:15s -0:06:15 -
+Rule	sol88	1988	only	-	Aug	3	12:06:10s -0:06:10 -
+Rule	sol88	1988	only	-	Aug	4	12:06:05s -0:06:05 -
+Rule	sol88	1988	only	-	Aug	5	12:05:55s -0:05:55 -
+Rule	sol88	1988	only	-	Aug	6	12:05:50s -0:05:50 -
+Rule	sol88	1988	only	-	Aug	7	12:05:45s -0:05:45 -
+Rule	sol88	1988	only	-	Aug	8	12:05:35s -0:05:35 -
+Rule	sol88	1988	only	-	Aug	9	12:05:25s -0:05:25 -
+Rule	sol88	1988	only	-	Aug	10	12:05:20s -0:05:20 -
+Rule	sol88	1988	only	-	Aug	11	12:05:10s -0:05:10 -
+Rule	sol88	1988	only	-	Aug	12	12:05:00s -0:05:00 -
+Rule	sol88	1988	only	-	Aug	13	12:04:50s -0:04:50 -
+Rule	sol88	1988	only	-	Aug	14	12:04:35s -0:04:35 -
+Rule	sol88	1988	only	-	Aug	15	12:04:25s -0:04:25 -
+Rule	sol88	1988	only	-	Aug	16	12:04:15s -0:04:15 -
+Rule	sol88	1988	only	-	Aug	17	12:04:00s -0:04:00 -
+Rule	sol88	1988	only	-	Aug	18	12:03:50s -0:03:50 -
+Rule	sol88	1988	only	-	Aug	19	12:03:35s -0:03:35 -
+Rule	sol88	1988	only	-	Aug	20	12:03:20s -0:03:20 -
+Rule	sol88	1988	only	-	Aug	21	12:03:05s -0:03:05 -
+Rule	sol88	1988	only	-	Aug	22	12:02:50s -0:02:50 -
+Rule	sol88	1988	only	-	Aug	23	12:02:35s -0:02:35 -
+Rule	sol88	1988	only	-	Aug	24	12:02:20s -0:02:20 -
+Rule	sol88	1988	only	-	Aug	25	12:02:00s -0:02:00 -
+Rule	sol88	1988	only	-	Aug	26	12:01:45s -0:01:45 -
+Rule	sol88	1988	only	-	Aug	27	12:01:30s -0:01:30 -
+Rule	sol88	1988	only	-	Aug	28	12:01:10s -0:01:10 -
+Rule	sol88	1988	only	-	Aug	29	12:00:50s -0:00:50 -
+Rule	sol88	1988	only	-	Aug	30	12:00:35s -0:00:35 -
+Rule	sol88	1988	only	-	Aug	31	12:00:15s -0:00:15 -
+Rule	sol88	1988	only	-	Sep	1	11:59:55s 0:00:05 -
+Rule	sol88	1988	only	-	Sep	2	11:59:35s 0:00:25 -
+Rule	sol88	1988	only	-	Sep	3	11:59:20s 0:00:40 -
+Rule	sol88	1988	only	-	Sep	4	11:59:00s 0:01:00 -
+Rule	sol88	1988	only	-	Sep	5	11:58:40s 0:01:20 -
+Rule	sol88	1988	only	-	Sep	6	11:58:20s 0:01:40 -
+Rule	sol88	1988	only	-	Sep	7	11:58:00s 0:02:00 -
+Rule	sol88	1988	only	-	Sep	8	11:57:35s 0:02:25 -
+Rule	sol88	1988	only	-	Sep	9	11:57:15s 0:02:45 -
+Rule	sol88	1988	only	-	Sep	10	11:56:55s 0:03:05 -
+Rule	sol88	1988	only	-	Sep	11	11:56:35s 0:03:25 -
+Rule	sol88	1988	only	-	Sep	12	11:56:15s 0:03:45 -
+Rule	sol88	1988	only	-	Sep	13	11:55:50s 0:04:10 -
+Rule	sol88	1988	only	-	Sep	14	11:55:30s 0:04:30 -
+Rule	sol88	1988	only	-	Sep	15	11:55:10s 0:04:50 -
+Rule	sol88	1988	only	-	Sep	16	11:54:50s 0:05:10 -
+Rule	sol88	1988	only	-	Sep	17	11:54:25s 0:05:35 -
+Rule	sol88	1988	only	-	Sep	18	11:54:05s 0:05:55 -
+Rule	sol88	1988	only	-	Sep	19	11:53:45s 0:06:15 -
+Rule	sol88	1988	only	-	Sep	20	11:53:25s 0:06:35 -
+Rule	sol88	1988	only	-	Sep	21	11:53:00s 0:07:00 -
+Rule	sol88	1988	only	-	Sep	22	11:52:40s 0:07:20 -
+Rule	sol88	1988	only	-	Sep	23	11:52:20s 0:07:40 -
+Rule	sol88	1988	only	-	Sep	24	11:52:00s 0:08:00 -
+Rule	sol88	1988	only	-	Sep	25	11:51:40s 0:08:20 -
+Rule	sol88	1988	only	-	Sep	26	11:51:15s 0:08:45 -
+Rule	sol88	1988	only	-	Sep	27	11:50:55s 0:09:05 -
+Rule	sol88	1988	only	-	Sep	28	11:50:35s 0:09:25 -
+Rule	sol88	1988	only	-	Sep	29	11:50:15s 0:09:45 -
+Rule	sol88	1988	only	-	Sep	30	11:49:55s 0:10:05 -
+Rule	sol88	1988	only	-	Oct	1	11:49:35s 0:10:25 -
+Rule	sol88	1988	only	-	Oct	2	11:49:20s 0:10:40 -
+Rule	sol88	1988	only	-	Oct	3	11:49:00s 0:11:00 -
+Rule	sol88	1988	only	-	Oct	4	11:48:40s 0:11:20 -
+Rule	sol88	1988	only	-	Oct	5	11:48:25s 0:11:35 -
+Rule	sol88	1988	only	-	Oct	6	11:48:05s 0:11:55 -
+Rule	sol88	1988	only	-	Oct	7	11:47:50s 0:12:10 -
+Rule	sol88	1988	only	-	Oct	8	11:47:30s 0:12:30 -
+Rule	sol88	1988	only	-	Oct	9	11:47:15s 0:12:45 -
+Rule	sol88	1988	only	-	Oct	10	11:47:00s 0:13:00 -
+Rule	sol88	1988	only	-	Oct	11	11:46:45s 0:13:15 -
+Rule	sol88	1988	only	-	Oct	12	11:46:30s 0:13:30 -
+Rule	sol88	1988	only	-	Oct	13	11:46:15s 0:13:45 -
+Rule	sol88	1988	only	-	Oct	14	11:46:00s 0:14:00 -
+Rule	sol88	1988	only	-	Oct	15	11:45:45s 0:14:15 -
+Rule	sol88	1988	only	-	Oct	16	11:45:35s 0:14:25 -
+Rule	sol88	1988	only	-	Oct	17	11:45:20s 0:14:40 -
+Rule	sol88	1988	only	-	Oct	18	11:45:10s 0:14:50 -
+Rule	sol88	1988	only	-	Oct	19	11:45:00s 0:15:00 -
+Rule	sol88	1988	only	-	Oct	20	11:44:45s 0:15:15 -
+Rule	sol88	1988	only	-	Oct	21	11:44:40s 0:15:20 -
+Rule	sol88	1988	only	-	Oct	22	11:44:30s 0:15:30 -
+Rule	sol88	1988	only	-	Oct	23	11:44:20s 0:15:40 -
+Rule	sol88	1988	only	-	Oct	24	11:44:10s 0:15:50 -
+Rule	sol88	1988	only	-	Oct	25	11:44:05s 0:15:55 -
+Rule	sol88	1988	only	-	Oct	26	11:44:00s 0:16:00 -
+Rule	sol88	1988	only	-	Oct	27	11:43:55s 0:16:05 -
+Rule	sol88	1988	only	-	Oct	28	11:43:50s 0:16:10 -
+Rule	sol88	1988	only	-	Oct	29	11:43:45s 0:16:15 -
+Rule	sol88	1988	only	-	Oct	30	11:43:40s 0:16:20 -
+Rule	sol88	1988	only	-	Oct	31	11:43:40s 0:16:20 -
+Rule	sol88	1988	only	-	Nov	1	11:43:35s 0:16:25 -
+Rule	sol88	1988	only	-	Nov	2	11:43:35s 0:16:25 -
+Rule	sol88	1988	only	-	Nov	3	11:43:35s 0:16:25 -
+Rule	sol88	1988	only	-	Nov	4	11:43:35s 0:16:25 -
+Rule	sol88	1988	only	-	Nov	5	11:43:40s 0:16:20 -
+Rule	sol88	1988	only	-	Nov	6	11:43:40s 0:16:20 -
+Rule	sol88	1988	only	-	Nov	7	11:43:45s 0:16:15 -
+Rule	sol88	1988	only	-	Nov	8	11:43:45s 0:16:15 -
+Rule	sol88	1988	only	-	Nov	9	11:43:50s 0:16:10 -
+Rule	sol88	1988	only	-	Nov	10	11:44:00s 0:16:00 -
+Rule	sol88	1988	only	-	Nov	11	11:44:05s 0:15:55 -
+Rule	sol88	1988	only	-	Nov	12	11:44:10s 0:15:50 -
+Rule	sol88	1988	only	-	Nov	13	11:44:20s 0:15:40 -
+Rule	sol88	1988	only	-	Nov	14	11:44:30s 0:15:30 -
+Rule	sol88	1988	only	-	Nov	15	11:44:40s 0:15:20 -
+Rule	sol88	1988	only	-	Nov	16	11:44:50s 0:15:10 -
+Rule	sol88	1988	only	-	Nov	17	11:45:00s 0:15:00 -
+Rule	sol88	1988	only	-	Nov	18	11:45:15s 0:14:45 -
+Rule	sol88	1988	only	-	Nov	19	11:45:25s 0:14:35 -
+Rule	sol88	1988	only	-	Nov	20	11:45:40s 0:14:20 -
+Rule	sol88	1988	only	-	Nov	21	11:45:55s 0:14:05 -
+Rule	sol88	1988	only	-	Nov	22	11:46:10s 0:13:50 -
+Rule	sol88	1988	only	-	Nov	23	11:46:30s 0:13:30 -
+Rule	sol88	1988	only	-	Nov	24	11:46:45s 0:13:15 -
+Rule	sol88	1988	only	-	Nov	25	11:47:05s 0:12:55 -
+Rule	sol88	1988	only	-	Nov	26	11:47:20s 0:12:40 -
+Rule	sol88	1988	only	-	Nov	27	11:47:40s 0:12:20 -
+Rule	sol88	1988	only	-	Nov	28	11:48:00s 0:12:00 -
+Rule	sol88	1988	only	-	Nov	29	11:48:25s 0:11:35 -
+Rule	sol88	1988	only	-	Nov	30	11:48:45s 0:11:15 -
+Rule	sol88	1988	only	-	Dec	1	11:49:05s 0:10:55 -
+Rule	sol88	1988	only	-	Dec	2	11:49:30s 0:10:30 -
+Rule	sol88	1988	only	-	Dec	3	11:49:55s 0:10:05 -
+Rule	sol88	1988	only	-	Dec	4	11:50:15s 0:09:45 -
+Rule	sol88	1988	only	-	Dec	5	11:50:40s 0:09:20 -
+Rule	sol88	1988	only	-	Dec	6	11:51:05s 0:08:55 -
+Rule	sol88	1988	only	-	Dec	7	11:51:35s 0:08:25 -
+Rule	sol88	1988	only	-	Dec	8	11:52:00s 0:08:00 -
+Rule	sol88	1988	only	-	Dec	9	11:52:25s 0:07:35 -
+Rule	sol88	1988	only	-	Dec	10	11:52:55s 0:07:05 -
+Rule	sol88	1988	only	-	Dec	11	11:53:20s 0:06:40 -
+Rule	sol88	1988	only	-	Dec	12	11:53:50s 0:06:10 -
+Rule	sol88	1988	only	-	Dec	13	11:54:15s 0:05:45 -
+Rule	sol88	1988	only	-	Dec	14	11:54:45s 0:05:15 -
+Rule	sol88	1988	only	-	Dec	15	11:55:15s 0:04:45 -
+Rule	sol88	1988	only	-	Dec	16	11:55:45s 0:04:15 -
+Rule	sol88	1988	only	-	Dec	17	11:56:15s 0:03:45 -
+Rule	sol88	1988	only	-	Dec	18	11:56:40s 0:03:20 -
+Rule	sol88	1988	only	-	Dec	19	11:57:10s 0:02:50 -
+Rule	sol88	1988	only	-	Dec	20	11:57:40s 0:02:20 -
+Rule	sol88	1988	only	-	Dec	21	11:58:10s 0:01:50 -
+Rule	sol88	1988	only	-	Dec	22	11:58:40s 0:01:20 -
+Rule	sol88	1988	only	-	Dec	23	11:59:10s 0:00:50 -
+Rule	sol88	1988	only	-	Dec	24	11:59:40s 0:00:20 -
+Rule	sol88	1988	only	-	Dec	25	12:00:10s -0:00:10 -
+Rule	sol88	1988	only	-	Dec	26	12:00:40s -0:00:40 -
+Rule	sol88	1988	only	-	Dec	27	12:01:10s -0:01:10 -
+Rule	sol88	1988	only	-	Dec	28	12:01:40s -0:01:40 -
+Rule	sol88	1988	only	-	Dec	29	12:02:10s -0:02:10 -
+Rule	sol88	1988	only	-	Dec	30	12:02:35s -0:02:35 -
+Rule	sol88	1988	only	-	Dec	31	12:03:05s -0:03:05 -
+
+# Riyadh is at about 46 degrees 46 minutes East:  3 hrs, 7 mins, 4 secs
+# Before and after 1988, we'll operate on local mean solar time.
+
+# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
+Zone	Asia/Riyadh88	3:07:04	-		zzz	1988
+			3:07:04	sol88		zzz	1989
+			3:07:04	-		zzz
+# For backward compatibility...
+Link	Asia/Riyadh88	Mideast/Riyadh88
diff --git a/extra/zoneinfo/solar89 b/extra/zoneinfo/solar89
new file mode 100644
index 0000000000..8c48531461
--- /dev/null
+++ b/extra/zoneinfo/solar89
@@ -0,0 +1,393 @@
+# @(#)solar89	8.1
+
+# Apparent noon times below are for Riyadh; they're a bit off for other places.
+# Times were computed using a formula provided by the U. S. Naval Observatory:
+#	eqt = -105.8 * sin(l) + 596.2 * sin(2 * l) + 4.4 * sin(3 * l)
+#		-12.7 * sin(4 * l) - 429.0 * cos(l) - 2.1 * cos (2 * l)
+#		+ 19.3 * cos(3 * l);
+# where l is the "mean longitude of the Sun" given by
+#	l = 279.642 degrees + 0.985647 * d
+# and d is the interval in days from January 0, 0 hours Universal Time
+# (equaling the day of the year plus the fraction of a day from zero hours).
+# The accuracy of the formula is plus or minus three seconds.
+#
+# Rounding to the nearest five seconds results in fewer than
+# 256 different "time types"--a limit that's faced because time types are
+# stored on disk as unsigned chars.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	sol89	1989	only	-	Jan	1	12:03:35s -0:03:35 -
+Rule	sol89	1989	only	-	Jan	2	12:04:05s -0:04:05 -
+Rule	sol89	1989	only	-	Jan	3	12:04:30s -0:04:30 -
+Rule	sol89	1989	only	-	Jan	4	12:05:00s -0:05:00 -
+Rule	sol89	1989	only	-	Jan	5	12:05:25s -0:05:25 -
+Rule	sol89	1989	only	-	Jan	6	12:05:50s -0:05:50 -
+Rule	sol89	1989	only	-	Jan	7	12:06:15s -0:06:15 -
+Rule	sol89	1989	only	-	Jan	8	12:06:45s -0:06:45 -
+Rule	sol89	1989	only	-	Jan	9	12:07:10s -0:07:10 -
+Rule	sol89	1989	only	-	Jan	10	12:07:35s -0:07:35 -
+Rule	sol89	1989	only	-	Jan	11	12:07:55s -0:07:55 -
+Rule	sol89	1989	only	-	Jan	12	12:08:20s -0:08:20 -
+Rule	sol89	1989	only	-	Jan	13	12:08:45s -0:08:45 -
+Rule	sol89	1989	only	-	Jan	14	12:09:05s -0:09:05 -
+Rule	sol89	1989	only	-	Jan	15	12:09:25s -0:09:25 -
+Rule	sol89	1989	only	-	Jan	16	12:09:45s -0:09:45 -
+Rule	sol89	1989	only	-	Jan	17	12:10:05s -0:10:05 -
+Rule	sol89	1989	only	-	Jan	18	12:10:25s -0:10:25 -
+Rule	sol89	1989	only	-	Jan	19	12:10:45s -0:10:45 -
+Rule	sol89	1989	only	-	Jan	20	12:11:05s -0:11:05 -
+Rule	sol89	1989	only	-	Jan	21	12:11:20s -0:11:20 -
+Rule	sol89	1989	only	-	Jan	22	12:11:35s -0:11:35 -
+Rule	sol89	1989	only	-	Jan	23	12:11:55s -0:11:55 -
+Rule	sol89	1989	only	-	Jan	24	12:12:10s -0:12:10 -
+Rule	sol89	1989	only	-	Jan	25	12:12:20s -0:12:20 -
+Rule	sol89	1989	only	-	Jan	26	12:12:35s -0:12:35 -
+Rule	sol89	1989	only	-	Jan	27	12:12:50s -0:12:50 -
+Rule	sol89	1989	only	-	Jan	28	12:13:00s -0:13:00 -
+Rule	sol89	1989	only	-	Jan	29	12:13:10s -0:13:10 -
+Rule	sol89	1989	only	-	Jan	30	12:13:20s -0:13:20 -
+Rule	sol89	1989	only	-	Jan	31	12:13:30s -0:13:30 -
+Rule	sol89	1989	only	-	Feb	1	12:13:40s -0:13:40 -
+Rule	sol89	1989	only	-	Feb	2	12:13:45s -0:13:45 -
+Rule	sol89	1989	only	-	Feb	3	12:13:55s -0:13:55 -
+Rule	sol89	1989	only	-	Feb	4	12:14:00s -0:14:00 -
+Rule	sol89	1989	only	-	Feb	5	12:14:05s -0:14:05 -
+Rule	sol89	1989	only	-	Feb	6	12:14:10s -0:14:10 -
+Rule	sol89	1989	only	-	Feb	7	12:14:10s -0:14:10 -
+Rule	sol89	1989	only	-	Feb	8	12:14:15s -0:14:15 -
+Rule	sol89	1989	only	-	Feb	9	12:14:15s -0:14:15 -
+Rule	sol89	1989	only	-	Feb	10	12:14:20s -0:14:20 -
+Rule	sol89	1989	only	-	Feb	11	12:14:20s -0:14:20 -
+Rule	sol89	1989	only	-	Feb	12	12:14:20s -0:14:20 -
+Rule	sol89	1989	only	-	Feb	13	12:14:15s -0:14:15 -
+Rule	sol89	1989	only	-	Feb	14	12:14:15s -0:14:15 -
+Rule	sol89	1989	only	-	Feb	15	12:14:10s -0:14:10 -
+Rule	sol89	1989	only	-	Feb	16	12:14:10s -0:14:10 -
+Rule	sol89	1989	only	-	Feb	17	12:14:05s -0:14:05 -
+Rule	sol89	1989	only	-	Feb	18	12:14:00s -0:14:00 -
+Rule	sol89	1989	only	-	Feb	19	12:13:55s -0:13:55 -
+Rule	sol89	1989	only	-	Feb	20	12:13:50s -0:13:50 -
+Rule	sol89	1989	only	-	Feb	21	12:13:40s -0:13:40 -
+Rule	sol89	1989	only	-	Feb	22	12:13:35s -0:13:35 -
+Rule	sol89	1989	only	-	Feb	23	12:13:25s -0:13:25 -
+Rule	sol89	1989	only	-	Feb	24	12:13:15s -0:13:15 -
+Rule	sol89	1989	only	-	Feb	25	12:13:05s -0:13:05 -
+Rule	sol89	1989	only	-	Feb	26	12:12:55s -0:12:55 -
+Rule	sol89	1989	only	-	Feb	27	12:12:45s -0:12:45 -
+Rule	sol89	1989	only	-	Feb	28	12:12:35s -0:12:35 -
+Rule	sol89	1989	only	-	Mar	1	12:12:25s -0:12:25 -
+Rule	sol89	1989	only	-	Mar	2	12:12:10s -0:12:10 -
+Rule	sol89	1989	only	-	Mar	3	12:12:00s -0:12:00 -
+Rule	sol89	1989	only	-	Mar	4	12:11:45s -0:11:45 -
+Rule	sol89	1989	only	-	Mar	5	12:11:35s -0:11:35 -
+Rule	sol89	1989	only	-	Mar	6	12:11:20s -0:11:20 -
+Rule	sol89	1989	only	-	Mar	7	12:11:05s -0:11:05 -
+Rule	sol89	1989	only	-	Mar	8	12:10:50s -0:10:50 -
+Rule	sol89	1989	only	-	Mar	9	12:10:35s -0:10:35 -
+Rule	sol89	1989	only	-	Mar	10	12:10:20s -0:10:20 -
+Rule	sol89	1989	only	-	Mar	11	12:10:05s -0:10:05 -
+Rule	sol89	1989	only	-	Mar	12	12:09:50s -0:09:50 -
+Rule	sol89	1989	only	-	Mar	13	12:09:30s -0:09:30 -
+Rule	sol89	1989	only	-	Mar	14	12:09:15s -0:09:15 -
+Rule	sol89	1989	only	-	Mar	15	12:09:00s -0:09:00 -
+Rule	sol89	1989	only	-	Mar	16	12:08:40s -0:08:40 -
+Rule	sol89	1989	only	-	Mar	17	12:08:25s -0:08:25 -
+Rule	sol89	1989	only	-	Mar	18	12:08:05s -0:08:05 -
+Rule	sol89	1989	only	-	Mar	19	12:07:50s -0:07:50 -
+Rule	sol89	1989	only	-	Mar	20	12:07:30s -0:07:30 -
+Rule	sol89	1989	only	-	Mar	21	12:07:15s -0:07:15 -
+Rule	sol89	1989	only	-	Mar	22	12:06:55s -0:06:55 -
+Rule	sol89	1989	only	-	Mar	23	12:06:35s -0:06:35 -
+Rule	sol89	1989	only	-	Mar	24	12:06:20s -0:06:20 -
+Rule	sol89	1989	only	-	Mar	25	12:06:00s -0:06:00 -
+Rule	sol89	1989	only	-	Mar	26	12:05:40s -0:05:40 -
+Rule	sol89	1989	only	-	Mar	27	12:05:25s -0:05:25 -
+Rule	sol89	1989	only	-	Mar	28	12:05:05s -0:05:05 -
+Rule	sol89	1989	only	-	Mar	29	12:04:50s -0:04:50 -
+Rule	sol89	1989	only	-	Mar	30	12:04:30s -0:04:30 -
+Rule	sol89	1989	only	-	Mar	31	12:04:10s -0:04:10 -
+Rule	sol89	1989	only	-	Apr	1	12:03:55s -0:03:55 -
+Rule	sol89	1989	only	-	Apr	2	12:03:35s -0:03:35 -
+Rule	sol89	1989	only	-	Apr	3	12:03:20s -0:03:20 -
+Rule	sol89	1989	only	-	Apr	4	12:03:00s -0:03:00 -
+Rule	sol89	1989	only	-	Apr	5	12:02:45s -0:02:45 -
+Rule	sol89	1989	only	-	Apr	6	12:02:25s -0:02:25 -
+Rule	sol89	1989	only	-	Apr	7	12:02:10s -0:02:10 -
+Rule	sol89	1989	only	-	Apr	8	12:01:50s -0:01:50 -
+Rule	sol89	1989	only	-	Apr	9	12:01:35s -0:01:35 -
+Rule	sol89	1989	only	-	Apr	10	12:01:20s -0:01:20 -
+Rule	sol89	1989	only	-	Apr	11	12:01:05s -0:01:05 -
+Rule	sol89	1989	only	-	Apr	12	12:00:50s -0:00:50 -
+Rule	sol89	1989	only	-	Apr	13	12:00:35s -0:00:35 -
+Rule	sol89	1989	only	-	Apr	14	12:00:20s -0:00:20 -
+Rule	sol89	1989	only	-	Apr	15	12:00:05s -0:00:05 -
+Rule	sol89	1989	only	-	Apr	16	11:59:50s 0:00:10 -
+Rule	sol89	1989	only	-	Apr	17	11:59:35s 0:00:25 -
+Rule	sol89	1989	only	-	Apr	18	11:59:20s 0:00:40 -
+Rule	sol89	1989	only	-	Apr	19	11:59:10s 0:00:50 -
+Rule	sol89	1989	only	-	Apr	20	11:58:55s 0:01:05 -
+Rule	sol89	1989	only	-	Apr	21	11:58:45s 0:01:15 -
+Rule	sol89	1989	only	-	Apr	22	11:58:30s 0:01:30 -
+Rule	sol89	1989	only	-	Apr	23	11:58:20s 0:01:40 -
+Rule	sol89	1989	only	-	Apr	24	11:58:10s 0:01:50 -
+Rule	sol89	1989	only	-	Apr	25	11:58:00s 0:02:00 -
+Rule	sol89	1989	only	-	Apr	26	11:57:50s 0:02:10 -
+Rule	sol89	1989	only	-	Apr	27	11:57:40s 0:02:20 -
+Rule	sol89	1989	only	-	Apr	28	11:57:30s 0:02:30 -
+Rule	sol89	1989	only	-	Apr	29	11:57:20s 0:02:40 -
+Rule	sol89	1989	only	-	Apr	30	11:57:15s 0:02:45 -
+Rule	sol89	1989	only	-	May	1	11:57:05s 0:02:55 -
+Rule	sol89	1989	only	-	May	2	11:57:00s 0:03:00 -
+Rule	sol89	1989	only	-	May	3	11:56:50s 0:03:10 -
+Rule	sol89	1989	only	-	May	4	11:56:45s 0:03:15 -
+Rule	sol89	1989	only	-	May	5	11:56:40s 0:03:20 -
+Rule	sol89	1989	only	-	May	6	11:56:35s 0:03:25 -
+Rule	sol89	1989	only	-	May	7	11:56:30s 0:03:30 -
+Rule	sol89	1989	only	-	May	8	11:56:30s 0:03:30 -
+Rule	sol89	1989	only	-	May	9	11:56:25s 0:03:35 -
+Rule	sol89	1989	only	-	May	10	11:56:25s 0:03:35 -
+Rule	sol89	1989	only	-	May	11	11:56:20s 0:03:40 -
+Rule	sol89	1989	only	-	May	12	11:56:20s 0:03:40 -
+Rule	sol89	1989	only	-	May	13	11:56:20s 0:03:40 -
+Rule	sol89	1989	only	-	May	14	11:56:20s 0:03:40 -
+Rule	sol89	1989	only	-	May	15	11:56:20s 0:03:40 -
+Rule	sol89	1989	only	-	May	16	11:56:20s 0:03:40 -
+Rule	sol89	1989	only	-	May	17	11:56:20s 0:03:40 -
+Rule	sol89	1989	only	-	May	18	11:56:25s 0:03:35 -
+Rule	sol89	1989	only	-	May	19	11:56:25s 0:03:35 -
+Rule	sol89	1989	only	-	May	20	11:56:30s 0:03:30 -
+Rule	sol89	1989	only	-	May	21	11:56:35s 0:03:25 -
+Rule	sol89	1989	only	-	May	22	11:56:35s 0:03:25 -
+Rule	sol89	1989	only	-	May	23	11:56:40s 0:03:20 -
+Rule	sol89	1989	only	-	May	24	11:56:45s 0:03:15 -
+Rule	sol89	1989	only	-	May	25	11:56:55s 0:03:05 -
+Rule	sol89	1989	only	-	May	26	11:57:00s 0:03:00 -
+Rule	sol89	1989	only	-	May	27	11:57:05s 0:02:55 -
+Rule	sol89	1989	only	-	May	28	11:57:15s 0:02:45 -
+Rule	sol89	1989	only	-	May	29	11:57:20s 0:02:40 -
+Rule	sol89	1989	only	-	May	30	11:57:30s 0:02:30 -
+Rule	sol89	1989	only	-	May	31	11:57:35s 0:02:25 -
+Rule	sol89	1989	only	-	Jun	1	11:57:45s 0:02:15 -
+Rule	sol89	1989	only	-	Jun	2	11:57:55s 0:02:05 -
+Rule	sol89	1989	only	-	Jun	3	11:58:05s 0:01:55 -
+Rule	sol89	1989	only	-	Jun	4	11:58:15s 0:01:45 -
+Rule	sol89	1989	only	-	Jun	5	11:58:25s 0:01:35 -
+Rule	sol89	1989	only	-	Jun	6	11:58:35s 0:01:25 -
+Rule	sol89	1989	only	-	Jun	7	11:58:45s 0:01:15 -
+Rule	sol89	1989	only	-	Jun	8	11:59:00s 0:01:00 -
+Rule	sol89	1989	only	-	Jun	9	11:59:10s 0:00:50 -
+Rule	sol89	1989	only	-	Jun	10	11:59:20s 0:00:40 -
+Rule	sol89	1989	only	-	Jun	11	11:59:35s 0:00:25 -
+Rule	sol89	1989	only	-	Jun	12	11:59:45s 0:00:15 -
+Rule	sol89	1989	only	-	Jun	13	12:00:00s 0:00:00 -
+Rule	sol89	1989	only	-	Jun	14	12:00:10s -0:00:10 -
+Rule	sol89	1989	only	-	Jun	15	12:00:25s -0:00:25 -
+Rule	sol89	1989	only	-	Jun	16	12:00:35s -0:00:35 -
+Rule	sol89	1989	only	-	Jun	17	12:00:50s -0:00:50 -
+Rule	sol89	1989	only	-	Jun	18	12:01:05s -0:01:05 -
+Rule	sol89	1989	only	-	Jun	19	12:01:15s -0:01:15 -
+Rule	sol89	1989	only	-	Jun	20	12:01:30s -0:01:30 -
+Rule	sol89	1989	only	-	Jun	21	12:01:40s -0:01:40 -
+Rule	sol89	1989	only	-	Jun	22	12:01:55s -0:01:55 -
+Rule	sol89	1989	only	-	Jun	23	12:02:10s -0:02:10 -
+Rule	sol89	1989	only	-	Jun	24	12:02:20s -0:02:20 -
+Rule	sol89	1989	only	-	Jun	25	12:02:35s -0:02:35 -
+Rule	sol89	1989	only	-	Jun	26	12:02:45s -0:02:45 -
+Rule	sol89	1989	only	-	Jun	27	12:03:00s -0:03:00 -
+Rule	sol89	1989	only	-	Jun	28	12:03:10s -0:03:10 -
+Rule	sol89	1989	only	-	Jun	29	12:03:25s -0:03:25 -
+Rule	sol89	1989	only	-	Jun	30	12:03:35s -0:03:35 -
+Rule	sol89	1989	only	-	Jul	1	12:03:45s -0:03:45 -
+Rule	sol89	1989	only	-	Jul	2	12:04:00s -0:04:00 -
+Rule	sol89	1989	only	-	Jul	3	12:04:10s -0:04:10 -
+Rule	sol89	1989	only	-	Jul	4	12:04:20s -0:04:20 -
+Rule	sol89	1989	only	-	Jul	5	12:04:30s -0:04:30 -
+Rule	sol89	1989	only	-	Jul	6	12:04:40s -0:04:40 -
+Rule	sol89	1989	only	-	Jul	7	12:04:50s -0:04:50 -
+Rule	sol89	1989	only	-	Jul	8	12:05:00s -0:05:00 -
+Rule	sol89	1989	only	-	Jul	9	12:05:10s -0:05:10 -
+Rule	sol89	1989	only	-	Jul	10	12:05:20s -0:05:20 -
+Rule	sol89	1989	only	-	Jul	11	12:05:25s -0:05:25 -
+Rule	sol89	1989	only	-	Jul	12	12:05:35s -0:05:35 -
+Rule	sol89	1989	only	-	Jul	13	12:05:40s -0:05:40 -
+Rule	sol89	1989	only	-	Jul	14	12:05:50s -0:05:50 -
+Rule	sol89	1989	only	-	Jul	15	12:05:55s -0:05:55 -
+Rule	sol89	1989	only	-	Jul	16	12:06:00s -0:06:00 -
+Rule	sol89	1989	only	-	Jul	17	12:06:05s -0:06:05 -
+Rule	sol89	1989	only	-	Jul	18	12:06:10s -0:06:10 -
+Rule	sol89	1989	only	-	Jul	19	12:06:15s -0:06:15 -
+Rule	sol89	1989	only	-	Jul	20	12:06:20s -0:06:20 -
+Rule	sol89	1989	only	-	Jul	21	12:06:20s -0:06:20 -
+Rule	sol89	1989	only	-	Jul	22	12:06:25s -0:06:25 -
+Rule	sol89	1989	only	-	Jul	23	12:06:25s -0:06:25 -
+Rule	sol89	1989	only	-	Jul	24	12:06:30s -0:06:30 -
+Rule	sol89	1989	only	-	Jul	25	12:06:30s -0:06:30 -
+Rule	sol89	1989	only	-	Jul	26	12:06:30s -0:06:30 -
+Rule	sol89	1989	only	-	Jul	27	12:06:30s -0:06:30 -
+Rule	sol89	1989	only	-	Jul	28	12:06:30s -0:06:30 -
+Rule	sol89	1989	only	-	Jul	29	12:06:25s -0:06:25 -
+Rule	sol89	1989	only	-	Jul	30	12:06:25s -0:06:25 -
+Rule	sol89	1989	only	-	Jul	31	12:06:20s -0:06:20 -
+Rule	sol89	1989	only	-	Aug	1	12:06:20s -0:06:20 -
+Rule	sol89	1989	only	-	Aug	2	12:06:15s -0:06:15 -
+Rule	sol89	1989	only	-	Aug	3	12:06:10s -0:06:10 -
+Rule	sol89	1989	only	-	Aug	4	12:06:05s -0:06:05 -
+Rule	sol89	1989	only	-	Aug	5	12:06:00s -0:06:00 -
+Rule	sol89	1989	only	-	Aug	6	12:05:50s -0:05:50 -
+Rule	sol89	1989	only	-	Aug	7	12:05:45s -0:05:45 -
+Rule	sol89	1989	only	-	Aug	8	12:05:35s -0:05:35 -
+Rule	sol89	1989	only	-	Aug	9	12:05:30s -0:05:30 -
+Rule	sol89	1989	only	-	Aug	10	12:05:20s -0:05:20 -
+Rule	sol89	1989	only	-	Aug	11	12:05:10s -0:05:10 -
+Rule	sol89	1989	only	-	Aug	12	12:05:00s -0:05:00 -
+Rule	sol89	1989	only	-	Aug	13	12:04:50s -0:04:50 -
+Rule	sol89	1989	only	-	Aug	14	12:04:40s -0:04:40 -
+Rule	sol89	1989	only	-	Aug	15	12:04:30s -0:04:30 -
+Rule	sol89	1989	only	-	Aug	16	12:04:15s -0:04:15 -
+Rule	sol89	1989	only	-	Aug	17	12:04:05s -0:04:05 -
+Rule	sol89	1989	only	-	Aug	18	12:03:50s -0:03:50 -
+Rule	sol89	1989	only	-	Aug	19	12:03:35s -0:03:35 -
+Rule	sol89	1989	only	-	Aug	20	12:03:25s -0:03:25 -
+Rule	sol89	1989	only	-	Aug	21	12:03:10s -0:03:10 -
+Rule	sol89	1989	only	-	Aug	22	12:02:55s -0:02:55 -
+Rule	sol89	1989	only	-	Aug	23	12:02:40s -0:02:40 -
+Rule	sol89	1989	only	-	Aug	24	12:02:20s -0:02:20 -
+Rule	sol89	1989	only	-	Aug	25	12:02:05s -0:02:05 -
+Rule	sol89	1989	only	-	Aug	26	12:01:50s -0:01:50 -
+Rule	sol89	1989	only	-	Aug	27	12:01:30s -0:01:30 -
+Rule	sol89	1989	only	-	Aug	28	12:01:15s -0:01:15 -
+Rule	sol89	1989	only	-	Aug	29	12:00:55s -0:00:55 -
+Rule	sol89	1989	only	-	Aug	30	12:00:40s -0:00:40 -
+Rule	sol89	1989	only	-	Aug	31	12:00:20s -0:00:20 -
+Rule	sol89	1989	only	-	Sep	1	12:00:00s 0:00:00 -
+Rule	sol89	1989	only	-	Sep	2	11:59:45s 0:00:15 -
+Rule	sol89	1989	only	-	Sep	3	11:59:25s 0:00:35 -
+Rule	sol89	1989	only	-	Sep	4	11:59:05s 0:00:55 -
+Rule	sol89	1989	only	-	Sep	5	11:58:45s 0:01:15 -
+Rule	sol89	1989	only	-	Sep	6	11:58:25s 0:01:35 -
+Rule	sol89	1989	only	-	Sep	7	11:58:05s 0:01:55 -
+Rule	sol89	1989	only	-	Sep	8	11:57:45s 0:02:15 -
+Rule	sol89	1989	only	-	Sep	9	11:57:20s 0:02:40 -
+Rule	sol89	1989	only	-	Sep	10	11:57:00s 0:03:00 -
+Rule	sol89	1989	only	-	Sep	11	11:56:40s 0:03:20 -
+Rule	sol89	1989	only	-	Sep	12	11:56:20s 0:03:40 -
+Rule	sol89	1989	only	-	Sep	13	11:56:00s 0:04:00 -
+Rule	sol89	1989	only	-	Sep	14	11:55:35s 0:04:25 -
+Rule	sol89	1989	only	-	Sep	15	11:55:15s 0:04:45 -
+Rule	sol89	1989	only	-	Sep	16	11:54:55s 0:05:05 -
+Rule	sol89	1989	only	-	Sep	17	11:54:35s 0:05:25 -
+Rule	sol89	1989	only	-	Sep	18	11:54:10s 0:05:50 -
+Rule	sol89	1989	only	-	Sep	19	11:53:50s 0:06:10 -
+Rule	sol89	1989	only	-	Sep	20	11:53:30s 0:06:30 -
+Rule	sol89	1989	only	-	Sep	21	11:53:10s 0:06:50 -
+Rule	sol89	1989	only	-	Sep	22	11:52:45s 0:07:15 -
+Rule	sol89	1989	only	-	Sep	23	11:52:25s 0:07:35 -
+Rule	sol89	1989	only	-	Sep	24	11:52:05s 0:07:55 -
+Rule	sol89	1989	only	-	Sep	25	11:51:45s 0:08:15 -
+Rule	sol89	1989	only	-	Sep	26	11:51:25s 0:08:35 -
+Rule	sol89	1989	only	-	Sep	27	11:51:05s 0:08:55 -
+Rule	sol89	1989	only	-	Sep	28	11:50:40s 0:09:20 -
+Rule	sol89	1989	only	-	Sep	29	11:50:20s 0:09:40 -
+Rule	sol89	1989	only	-	Sep	30	11:50:00s 0:10:00 -
+Rule	sol89	1989	only	-	Oct	1	11:49:45s 0:10:15 -
+Rule	sol89	1989	only	-	Oct	2	11:49:25s 0:10:35 -
+Rule	sol89	1989	only	-	Oct	3	11:49:05s 0:10:55 -
+Rule	sol89	1989	only	-	Oct	4	11:48:45s 0:11:15 -
+Rule	sol89	1989	only	-	Oct	5	11:48:30s 0:11:30 -
+Rule	sol89	1989	only	-	Oct	6	11:48:10s 0:11:50 -
+Rule	sol89	1989	only	-	Oct	7	11:47:50s 0:12:10 -
+Rule	sol89	1989	only	-	Oct	8	11:47:35s 0:12:25 -
+Rule	sol89	1989	only	-	Oct	9	11:47:20s 0:12:40 -
+Rule	sol89	1989	only	-	Oct	10	11:47:00s 0:13:00 -
+Rule	sol89	1989	only	-	Oct	11	11:46:45s 0:13:15 -
+Rule	sol89	1989	only	-	Oct	12	11:46:30s 0:13:30 -
+Rule	sol89	1989	only	-	Oct	13	11:46:15s 0:13:45 -
+Rule	sol89	1989	only	-	Oct	14	11:46:00s 0:14:00 -
+Rule	sol89	1989	only	-	Oct	15	11:45:50s 0:14:10 -
+Rule	sol89	1989	only	-	Oct	16	11:45:35s 0:14:25 -
+Rule	sol89	1989	only	-	Oct	17	11:45:20s 0:14:40 -
+Rule	sol89	1989	only	-	Oct	18	11:45:10s 0:14:50 -
+Rule	sol89	1989	only	-	Oct	19	11:45:00s 0:15:00 -
+Rule	sol89	1989	only	-	Oct	20	11:44:50s 0:15:10 -
+Rule	sol89	1989	only	-	Oct	21	11:44:40s 0:15:20 -
+Rule	sol89	1989	only	-	Oct	22	11:44:30s 0:15:30 -
+Rule	sol89	1989	only	-	Oct	23	11:44:20s 0:15:40 -
+Rule	sol89	1989	only	-	Oct	24	11:44:10s 0:15:50 -
+Rule	sol89	1989	only	-	Oct	25	11:44:05s 0:15:55 -
+Rule	sol89	1989	only	-	Oct	26	11:44:00s 0:16:00 -
+Rule	sol89	1989	only	-	Oct	27	11:43:50s 0:16:10 -
+Rule	sol89	1989	only	-	Oct	28	11:43:45s 0:16:15 -
+Rule	sol89	1989	only	-	Oct	29	11:43:40s 0:16:20 -
+Rule	sol89	1989	only	-	Oct	30	11:43:40s 0:16:20 -
+Rule	sol89	1989	only	-	Oct	31	11:43:35s 0:16:25 -
+Rule	sol89	1989	only	-	Nov	1	11:43:35s 0:16:25 -
+Rule	sol89	1989	only	-	Nov	2	11:43:35s 0:16:25 -
+Rule	sol89	1989	only	-	Nov	3	11:43:30s 0:16:30 -
+Rule	sol89	1989	only	-	Nov	4	11:43:35s 0:16:25 -
+Rule	sol89	1989	only	-	Nov	5	11:43:35s 0:16:25 -
+Rule	sol89	1989	only	-	Nov	6	11:43:35s 0:16:25 -
+Rule	sol89	1989	only	-	Nov	7	11:43:40s 0:16:20 -
+Rule	sol89	1989	only	-	Nov	8	11:43:45s 0:16:15 -
+Rule	sol89	1989	only	-	Nov	9	11:43:50s 0:16:10 -
+Rule	sol89	1989	only	-	Nov	10	11:43:55s 0:16:05 -
+Rule	sol89	1989	only	-	Nov	11	11:44:00s 0:16:00 -
+Rule	sol89	1989	only	-	Nov	12	11:44:05s 0:15:55 -
+Rule	sol89	1989	only	-	Nov	13	11:44:15s 0:15:45 -
+Rule	sol89	1989	only	-	Nov	14	11:44:25s 0:15:35 -
+Rule	sol89	1989	only	-	Nov	15	11:44:35s 0:15:25 -
+Rule	sol89	1989	only	-	Nov	16	11:44:45s 0:15:15 -
+Rule	sol89	1989	only	-	Nov	17	11:44:55s 0:15:05 -
+Rule	sol89	1989	only	-	Nov	18	11:45:10s 0:14:50 -
+Rule	sol89	1989	only	-	Nov	19	11:45:20s 0:14:40 -
+Rule	sol89	1989	only	-	Nov	20	11:45:35s 0:14:25 -
+Rule	sol89	1989	only	-	Nov	21	11:45:50s 0:14:10 -
+Rule	sol89	1989	only	-	Nov	22	11:46:05s 0:13:55 -
+Rule	sol89	1989	only	-	Nov	23	11:46:25s 0:13:35 -
+Rule	sol89	1989	only	-	Nov	24	11:46:40s 0:13:20 -
+Rule	sol89	1989	only	-	Nov	25	11:47:00s 0:13:00 -
+Rule	sol89	1989	only	-	Nov	26	11:47:20s 0:12:40 -
+Rule	sol89	1989	only	-	Nov	27	11:47:35s 0:12:25 -
+Rule	sol89	1989	only	-	Nov	28	11:47:55s 0:12:05 -
+Rule	sol89	1989	only	-	Nov	29	11:48:20s 0:11:40 -
+Rule	sol89	1989	only	-	Nov	30	11:48:40s 0:11:20 -
+Rule	sol89	1989	only	-	Dec	1	11:49:00s 0:11:00 -
+Rule	sol89	1989	only	-	Dec	2	11:49:25s 0:10:35 -
+Rule	sol89	1989	only	-	Dec	3	11:49:50s 0:10:10 -
+Rule	sol89	1989	only	-	Dec	4	11:50:15s 0:09:45 -
+Rule	sol89	1989	only	-	Dec	5	11:50:35s 0:09:25 -
+Rule	sol89	1989	only	-	Dec	6	11:51:00s 0:09:00 -
+Rule	sol89	1989	only	-	Dec	7	11:51:30s 0:08:30 -
+Rule	sol89	1989	only	-	Dec	8	11:51:55s 0:08:05 -
+Rule	sol89	1989	only	-	Dec	9	11:52:20s 0:07:40 -
+Rule	sol89	1989	only	-	Dec	10	11:52:50s 0:07:10 -
+Rule	sol89	1989	only	-	Dec	11	11:53:15s 0:06:45 -
+Rule	sol89	1989	only	-	Dec	12	11:53:45s 0:06:15 -
+Rule	sol89	1989	only	-	Dec	13	11:54:10s 0:05:50 -
+Rule	sol89	1989	only	-	Dec	14	11:54:40s 0:05:20 -
+Rule	sol89	1989	only	-	Dec	15	11:55:10s 0:04:50 -
+Rule	sol89	1989	only	-	Dec	16	11:55:40s 0:04:20 -
+Rule	sol89	1989	only	-	Dec	17	11:56:05s 0:03:55 -
+Rule	sol89	1989	only	-	Dec	18	11:56:35s 0:03:25 -
+Rule	sol89	1989	only	-	Dec	19	11:57:05s 0:02:55 -
+Rule	sol89	1989	only	-	Dec	20	11:57:35s 0:02:25 -
+Rule	sol89	1989	only	-	Dec	21	11:58:05s 0:01:55 -
+Rule	sol89	1989	only	-	Dec	22	11:58:35s 0:01:25 -
+Rule	sol89	1989	only	-	Dec	23	11:59:05s 0:00:55 -
+Rule	sol89	1989	only	-	Dec	24	11:59:35s 0:00:25 -
+Rule	sol89	1989	only	-	Dec	25	12:00:05s -0:00:05 -
+Rule	sol89	1989	only	-	Dec	26	12:00:35s -0:00:35 -
+Rule	sol89	1989	only	-	Dec	27	12:01:05s -0:01:05 -
+Rule	sol89	1989	only	-	Dec	28	12:01:35s -0:01:35 -
+Rule	sol89	1989	only	-	Dec	29	12:02:00s -0:02:00 -
+Rule	sol89	1989	only	-	Dec	30	12:02:30s -0:02:30 -
+Rule	sol89	1989	only	-	Dec	31	12:03:00s -0:03:00 -
+
+# Riyadh is at about 46 degrees 46 minutes East:  3 hrs, 7 mins, 4 secs
+# Before and after 1989, we'll operate on local mean solar time.
+
+# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
+Zone	Asia/Riyadh89	3:07:04	-		zzz	1989
+			3:07:04	sol89		zzz	1990
+			3:07:04	-		zzz
+# For backward compatibility...
+Link	Asia/Riyadh89	Mideast/Riyadh89
diff --git a/extra/zoneinfo/southamerica b/extra/zoneinfo/southamerica
new file mode 100644
index 0000000000..5824b7fad8
--- /dev/null
+++ b/extra/zoneinfo/southamerica
@@ -0,0 +1,1473 @@
+# @(#)southamerica	8.34
+# 
+
+# This data is by no means authoritative; if you think you know better,
+# go ahead and edit the file (and please send any changes to
+# tz@elsie.nci.nih.gov for general use in the future).
+
+# From Paul Eggert (2006-03-22):
+# A good source for time zone historical data outside the U.S. is
+# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
+# San Diego: ACS Publications, Inc. (2003).
+#
+# Gwillim Law writes that a good source
+# for recent time zone data is the International Air Transport
+# Association's Standard Schedules Information Manual (IATA SSIM),
+# published semiannually.  Law sent in several helpful summaries
+# of the IATA's data after 1990.
+#
+# Except where otherwise noted, Shanks & Pottenger is the source for
+# entries through 1990, and IATA SSIM is the source for entries afterwards.
+#
+# Earlier editions of these tables used the North American style (e.g. ARST and
+# ARDT for Argentine Standard and Daylight Time), but the following quote
+# suggests that it's better to use European style (e.g. ART and ARST).
+#	I suggest the use of _Summer time_ instead of the more cumbersome
+#	_daylight-saving time_.  _Summer time_ seems to be in general use
+#	in Europe and South America.
+#	-- E O Cutler, _New York Times_ (1937-02-14), quoted in
+#	H L Mencken, _The American Language: Supplement I_ (1960), p 466
+#
+# Earlier editions of these tables also used the North American style
+# for time zones in Brazil, but this was incorrect, as Brazilians say
+# "summer time".  Reinaldo Goulart, a Sao Paulo businessman active in
+# the railroad sector, writes (1999-07-06):
+#	The subject of time zones is currently a matter of discussion/debate in
+#	Brazil.  Let's say that "the Brasilia time" is considered the
+#	"official time" because Brasilia is the capital city.
+#	The other three time zones are called "Brasilia time "minus one" or
+#	"plus one" or "plus two".  As far as I know there is no such
+#	name/designation as "Eastern Time" or "Central Time".
+# So I invented the following (English-language) abbreviations for now.
+# Corrections are welcome!
+#		std	dst
+#	-2:00	FNT	FNST	Fernando de Noronha
+#	-3:00	BRT	BRST	Brasilia
+#	-4:00	AMT	AMST	Amazon
+#	-5:00	ACT	ACST	Acre
+
+###############################################################################
+
+###############################################################################
+
+# Argentina
+
+# From Bob Devine (1988-01-28):
+# Argentina: first Sunday in October to first Sunday in April since 1976.
+# Double Summer time from 1969 to 1974.  Switches at midnight.
+
+# From U. S. Naval Observatory (1988-01-199):
+# ARGENTINA           3 H BEHIND   UTC
+
+# From Hernan G. Otero (1995-06-26):
+# I am sending modifications to the Argentine time zone table...
+# AR was chosen because they are the ISO letters that represent Argentina.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Arg	1930	only	-	Dec	 1	0:00	1:00	S
+Rule	Arg	1931	only	-	Apr	 1	0:00	0	-
+Rule	Arg	1931	only	-	Oct	15	0:00	1:00	S
+Rule	Arg	1932	1940	-	Mar	 1	0:00	0	-
+Rule	Arg	1932	1939	-	Nov	 1	0:00	1:00	S
+Rule	Arg	1940	only	-	Jul	 1	0:00	1:00	S
+Rule	Arg	1941	only	-	Jun	15	0:00	0	-
+Rule	Arg	1941	only	-	Oct	15	0:00	1:00	S
+Rule	Arg	1943	only	-	Aug	 1	0:00	0	-
+Rule	Arg	1943	only	-	Oct	15	0:00	1:00	S
+Rule	Arg	1946	only	-	Mar	 1	0:00	0	-
+Rule	Arg	1946	only	-	Oct	 1	0:00	1:00	S
+Rule	Arg	1963	only	-	Oct	 1	0:00	0	-
+Rule	Arg	1963	only	-	Dec	15	0:00	1:00	S
+Rule	Arg	1964	1966	-	Mar	 1	0:00	0	-
+Rule	Arg	1964	1966	-	Oct	15	0:00	1:00	S
+Rule	Arg	1967	only	-	Apr	 2	0:00	0	-
+Rule	Arg	1967	1968	-	Oct	Sun>=1	0:00	1:00	S
+Rule	Arg	1968	1969	-	Apr	Sun>=1	0:00	0	-
+Rule	Arg	1974	only	-	Jan	23	0:00	1:00	S
+Rule	Arg	1974	only	-	May	 1	0:00	0	-
+Rule	Arg	1988	only	-	Dec	 1	0:00	1:00	S
+#
+# From Hernan G. Otero (1995-06-26):
+# These corrections were contributed by InterSoft Argentina S.A.,
+# obtaining the data from the:
+# Talleres de Hidrografia Naval Argentina
+# (Argentine Naval Hydrography Institute)
+Rule	Arg	1989	1993	-	Mar	Sun>=1	0:00	0	-
+Rule	Arg	1989	1992	-	Oct	Sun>=15	0:00	1:00	S
+#
+# From Hernan G. Otero (1995-06-26):
+# From this moment on, the law that mandated the daylight saving
+# time corrections was derogated and no more modifications
+# to the time zones (for daylight saving) are now made.
+#
+# From Rives McDow (2000-01-10):
+# On October 3, 1999, 0:00 local, Argentina implemented daylight savings time,
+# which did not result in the switch of a time zone, as they stayed 9 hours
+# from the International Date Line.
+Rule	Arg	1999	only	-	Oct	Sun>=1	0:00	1:00	S
+# From Paul Eggert (2007-12-28):
+# DST was set to expire on March 5, not March 3, but since it was converted
+# to standard time on March 3 it's more convenient for us to pretend that
+# it ended on March 3.
+Rule	Arg	2000	only	-	Mar	3	0:00	0	-
+#
+# From Peter Gradelski via Steffen Thorsen (2000-03-01):
+# We just checked with our Sao Paulo office and they say the government of
+# Argentina decided not to become one of the countries that go on or off DST.
+# So Buenos Aires should be -3 hours from GMT at all times.
+#
+# From Fabian L. Arce Jofre (2000-04-04):
+# The law that claimed DST for Argentina was derogated by President Fernando
+# de la Rua on March 2, 2000, because it would make people spend more energy
+# in the winter time, rather than less.  The change took effect on March 3.
+#
+# From Mariano Absatz (2001-06-06):
+# one of the major newspapers here in Argentina said that the 1999
+# Timezone Law (which never was effectively applied) will (would?) be
+# in effect.... The article is at
+# http://ar.clarin.com/diario/2001-06-06/e-01701.htm
+# ... The Law itself is "Ley No 25155", sanctioned on 1999-08-25, enacted
+# 1999-09-17, and published 1999-09-21.  The official publication is at:
+# http://www.boletin.jus.gov.ar/BON/Primera/1999/09-Septiembre/21/PDF/BO21-09-99LEG.PDF
+# Regretfully, you have to subscribe (and pay) for the on-line version....
+#
+# (2001-06-12):
+# the timezone for Argentina will not change next Sunday.
+# Apparently it will do so on Sunday 24th....
+# http://ar.clarin.com/diario/2001-06-12/s-03501.htm
+#
+# (2001-06-25):
+# Last Friday (yes, the last working day before the date of the change), the
+# Senate annulled the 1999 law that introduced the changes later postponed.
+# http://www.clarin.com.ar/diario/2001-06-22/s-03601.htm
+# It remains the vote of the Deputies..., but it will be the same....
+# This kind of things had always been done this way in Argentina.
+# We are still -03:00 all year round in all of the country.
+#
+# From Steffen Thorsen (2007-12-21):
+# A user (Leonardo Chaim) reported that Argentina will adopt DST....
+# all of the country (all Zone-entries) are affected.  News reports like
+# http://www.lanacion.com.ar/opinion/nota.asp?nota_id=973037 indicate
+# that Argentina will use DST next year as well, from October to
+# March, although exact rules are not given.
+#
+# From Jesper Norgaard Welen (2007-12-26)
+# The last hurdle of Argentina DST is over, the proposal was approved in
+# the lower chamber too (Deputados) with a vote 192 for and 2 against.
+# By the way thanks to Mariano Absatz and Daniel Mario Vega for the link to
+# the original scanned proposal, where the dates and the zero hours are
+# clear and unambiguous...This is the article about final approval:
+# 
+# http://www.lanacion.com.ar/politica/nota.asp?nota_id=973996
+# 
+#
+# From Paul Eggert (2007-12-22):
+# For dates after mid-2008, the following rules are my guesses and
+# are quite possibly wrong, but are more likely than no DST at all.
+
+# From Alexander Krivenyshev (2008-09-05):
+# As per message from Carlos Alberto Fonseca Arauz (Nicaragua),
+# Argentina will start DST on Sunday October 19, 2008.
+#
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_argentina03.html
+# 
+# OR
+# 
+# http://www.impulsobaires.com.ar/nota.php?id=57832 (in spanish)
+# 
+
+# From Rodrigo Severo (2008-10-06):
+# Here is some info available at a Gentoo bug related to TZ on Argentina's DST:
+# ...
+# ------- Comment #1 from [jmdocile]  2008-10-06 16:28 0000 -------
+# Hi, there is a problem with timezone-data-2008e and maybe with
+# timezone-data-2008f
+# Argentinian law [Number] 25.155 is no longer valid.
+# 
+# http://www.infoleg.gov.ar/infolegInternet/anexos/60000-64999/60036/norma.htm
+# 
+# The new one is law [Number] 26.350
+# 
+# http://www.infoleg.gov.ar/infolegInternet/anexos/135000-139999/136191/norma.htm
+# 
+# So there is no summer time in Argentina for now.
+
+# From Mariano Absatz (2008-10-20):
+# Decree 1693/2008 applies Law 26.350 for the summer 2008/2009 establishing DST in Argentina
+# From 2008-10-19 until 2009-03-15
+# 
+# http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=16102008&pi=3&pf=4&s=0&sec=01
+# 
+#
+# Decree 1705/2008 excepting 12 Provinces from applying DST in the summer 2008/2009:
+# Catamarca, La Rioja, Mendoza, Salta, San Juan, San Luis, La Pampa, Neuquen, Rio Negro, Chubut, Santa Cruz
+# and Tierra del Fuego
+# 
+# http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=17102008&pi=1&pf=1&s=0&sec=01
+# 
+#
+# Press release 235 dated Saturday October 18th, from the Government of the Province of Jujuy saying
+# it will not apply DST either (even when it was not included in Decree 1705/2008)
+# 
+# http://www.jujuy.gov.ar/index2/partes_prensa/18_10_08/235-181008.doc
+# 
+
+Rule	Arg	2007	only	-	Dec	30	0:00	1:00	S
+Rule	Arg	2008	max	-	Mar	Sun>=15	0:00	0	-
+Rule	Arg	2008	max	-	Oct	Sun>=15	0:00	1:00	S
+ 
+# From Mariano Absatz (2004-05-21):
+# Today it was officially published that the Province of Mendoza is changing
+# its timezone this winter... starting tomorrow night....
+# http://www.gobernac.mendoza.gov.ar/boletin/pdf/20040521-27158-normas.pdf
+# From Paul Eggert (2004-05-24):
+# It's Law No. 7,210.  This change is due to a public power emergency, so for
+# now we'll assume it's for this year only.
+#
+# From Paul Eggert (2006-03-22):
+# 
+# Hora de verano para la Republica Argentina (2003-06-08)
+#  says that standard time in Argentina from 1894-10-31
+# to 1920-05-01 was -4:16:48.25.  Go with this more-precise value
+# over Shanks & Pottenger.
+#
+# From Mariano Absatz (2004-06-05):
+# These media articles from a major newspaper mostly cover the current state:
+# http://www.lanacion.com.ar/04/05/27/de_604825.asp
+# http://www.lanacion.com.ar/04/05/28/de_605203.asp
+#
+# The following eight (8) provinces pulled clocks back to UTC-04:00 at
+# midnight Monday May 31st. (that is, the night between 05/31 and 06/01).
+# Apparently, all nine provinces would go back to UTC-03:00 at the same
+# time in October 17th.
+#
+# Catamarca, Chubut, La Rioja, San Juan, San Luis, Santa Cruz,
+# Tierra del Fuego, Tucuman.
+#
+# From Mariano Absatz (2004-06-14):
+# ... this weekend, the Province of Tucuman decided it'd go back to UTC-03:00
+# yesterday midnight (that is, at 24:00 Saturday 12th), since the people's
+# annoyance with the change is much higher than the power savings obtained....
+#
+# From Gwillim Law (2004-06-14):
+# http://www.lanacion.com.ar/04/06/10/de_609078.asp ...
+#     "The time change in Tierra del Fuego was a conflicted decision from
+#   the start.  The government had decreed that the measure would take
+#   effect on June 1, but a normative error forced the new time to begin
+#   three days earlier, from a Saturday to a Sunday....
+# Our understanding was that the change was originally scheduled to take place
+# on June 1 at 00:00 in Chubut, Santa Cruz, Tierra del Fuego (and some other
+# provinces).  Sunday was May 30, only two days earlier.  So the article
+# contains a contradiction.  I would give more credence to the Saturday/Sunday
+# date than the "three days earlier" phrase, and conclude that Tierra del
+# Fuego set its clocks back at 2004-05-30 00:00.
+#
+# From Steffen Thorsen (2004-10-05):
+# The previous law 7210 which changed the province of Mendoza's time zone
+# back in May have been modified slightly in a new law 7277, which set the
+# new end date to 2004-09-26 (original date was 2004-10-17).
+# http://www.gobernac.mendoza.gov.ar/boletin/pdf/20040924-27244-normas.pdf
+#
+# From Mariano Absatz (2004-10-05):
+# San Juan changed from UTC-03:00 to UTC-04:00 at midnight between
+# Sunday, May 30th and Monday, May 31st.  It changed back to UTC-03:00
+# at midnight between Saturday, July 24th and Sunday, July 25th....
+# http://www.sanjuan.gov.ar/prensa/archivo/000329.html
+# http://www.sanjuan.gov.ar/prensa/archivo/000426.html
+# http://www.sanjuan.gov.ar/prensa/archivo/000441.html
+
+# From Alex Krivenyshev (2008-01-17):
+# Here are articles that Argentina Province San Luis is planning to end DST
+# as earlier as upcoming Monday January 21, 2008 or February 2008:
+#
+# Provincia argentina retrasa reloj y marca diferencia con resto del pais
+# (Argentine Province delayed clock and mark difference with the rest of the
+# country)
+# 
+# http://cl.invertia.com/noticias/noticia.aspx?idNoticia=200801171849_EFE_ET4373&idtel
+# 
+#
+# Es inminente que en San Luis atrasen una hora los relojes
+# (It is imminent in San Luis clocks one hour delay)
+# 
+# http://www.lagaceta.com.ar/vernotae.asp?id_nota=253414
+# 
+#
+# 
+# http://www.worldtimezone.net/dst_news/dst_news_argentina02.html
+# 
+
+# From Jesper Norgaard Welen (2008-01-18):
+# The page of the San Luis provincial government
+# 
+# http://www.sanluis.gov.ar/notas.asp?idCanal=0&id=22812
+# 
+# confirms what Alex Krivenyshev has earlier sent to the tz
+# emailing list about that San Luis plans to return to standard
+# time much earlier than the rest of the country. It also
+# confirms that upon request the provinces San Juan and Mendoza 
+# refused to follow San Luis in this change. 
+# 
+# The change is supposed to take place Monday the 21.st at 0:00
+# hours. As far as I understand it if this goes ahead, we need
+# a new timezone for San Luis (although there are also documented
+# independent changes in the southamerica file of San Luis in
+# 1990 and 1991 which has not been confirmed).
+
+# From Jesper Norgaard Welen (2008-01-25):
+# Unfortunately the below page has become defunct, about the San Luis
+# time change. Perhaps because it now is part of a group of pages "Most
+# important pages of 2008."
+#
+# You can use
+# 
+# http://www.sanluis.gov.ar/notas.asp?idCanal=8141&id=22834
+# 
+# instead it seems. Or use "Buscador" from the main page of the San Luis
+# government, and fill in "huso" and click OK, and you will get 3 pages
+# from which the first one is identical to the above.
+
+# From Mariano Absatz (2008-01-28):
+# I can confirm that the Province of San Luis (and so far only that
+# province) decided to go back to UTC-3 effective midnight Jan 20th 2008
+# (that is, Monday 21st at 0:00 is the time the clocks were delayed back
+# 1 hour), and they intend to keep UTC-3 as their timezone all year round
+# (that is, unless they change their mind any minute now).
+#
+# So we'll have to add yet another city to 'southamerica' (I think San
+# Luis city is the mos populated city in the Province, so it'd be
+# America/Argentina/San_Luis... of course I can't remember if San Luis's
+# history of particular changes goes along with Mendoza or San Juan :-(
+# (I only remember not being able to collect hard facts about San Luis
+# back in 2004, when these provinces changed to UTC-4 for a few days, I
+# mailed them personally and never got an answer).
+
+# From Paul Eggert (2008-06-30):
+# Unless otherwise specified, data are from Shanks & Pottenger through 1992,
+# from the IATA otherwise.  As noted below, Shanks & Pottenger say that
+# America/Cordoba split into 6 subregions during 1991/1992, one of which
+# was America/San_Luis, but we haven't verified this yet so for now we'll
+# keep America/Cordoba a single region rather than splitting it into the
+# other 5 subregions.
+
+# From Mariano Absatz (2009-03-13):
+# Yesterday (with our usual 2-day notice) the Province of San Luis
+# decided that next Sunday instead of "staying" @utc-03:00 they will go
+# to utc-04:00 until the second Saturday in October...
+#
+# The press release is at
+# 
+# http://www.sanluis.gov.ar/SL/Paginas/NoticiaDetalle.asp?TemaId=1&InfoPrensaId=3102
+# 
+# (I couldn't find the decree, but
+# 
+# www.sanluis.gov.ar
+# 
+# is the official page for the Province Government).
+#
+# There's also a note in only one of the major national papers (La Nación) at
+# 
+# http://www.lanacion.com.ar/nota.asp?nota_id=1107912
+# 
+# 
+# The press release says:
+#  (...) anunció que el próximo domingo a las 00:00 los puntanos deberán
+# atrasar una hora sus relojes.
+#
+# A partir de entonces, San Luis establecerá el huso horario propio de
+# la Provincia. De esta manera, durante el periodo del calendario anual
+# 2009, el cambio horario quedará comprendido entre las 00:00 del tercer
+# domingo de marzo y las 24:00 del segundo sábado de octubre.
+# Quick&dirty translation
+# (...) announced that next Sunday, at 00:00, Puntanos (the San Luis
+# inhabitants) will have to turn back one hour their clocks
+#
+# Since then, San Luis will establish its own Province timezone. Thus,
+# during 2009, this timezone change will run from 00:00 the third Sunday
+# in March until 24:00 of the second Saturday in October.
+
+# From Arthur David Olson (2009-03-16):
+# The unofficial claim at
+# 
+# http://www.timeanddate.com/news/time/san-luis-new-time-zone.html
+# 
+# is that "The province will most likely follow the next daylight saving schedule,
+# which is planned for the second Sunday in October."
+
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+#
+# Buenos Aires (BA), Capital Federal (CF),
+Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31
+			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	Arg	AR%sT
+#
+# Cordoba (CB), Santa Fe (SF), Entre Rios (ER), Corrientes (CN), Misiones (MN),
+# Chaco (CC), Formosa (FM), Santiago del Estero (SE)
+#
+# Shanks & Pottenger also make the following claims, which we haven't verified:
+# - Formosa switched to -3:00 on 1991-01-07.
+# - Misiones switched to -3:00 on 1990-12-29.
+# - Chaco switched to -3:00 on 1991-01-04.
+# - Santiago del Estero switched to -4:00 on 1991-04-01,
+#   then to -3:00 on 1991-04-26.
+#
+Zone America/Argentina/Cordoba -4:16:48 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1991 Mar  3
+			-4:00	-	WART	1991 Oct 20
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	Arg	AR%sT
+#
+# Salta (SA), La Pampa (LP), Neuquen (NQ), Rio Negro (RN)
+Zone America/Argentina/Salta -4:21:40 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1991 Mar  3
+			-4:00	-	WART	1991 Oct 20
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	Arg	AR%sT	2008 Oct 18
+			-3:00	-	ART
+#
+# Tucuman (TM)
+Zone America/Argentina/Tucuman -4:20:52 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1991 Mar  3
+			-4:00	-	WART	1991 Oct 20
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	-	ART	2004 Jun  1
+			-4:00	-	WART	2004 Jun 13
+			-3:00	Arg	AR%sT
+#
+# La Rioja (LR)
+Zone America/Argentina/La_Rioja -4:27:24 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1991 Mar  1
+			-4:00	-	WART	1991 May  7
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	-	ART	2004 Jun  1
+			-4:00	-	WART	2004 Jun 20
+			-3:00	Arg	AR%sT	2008 Oct 18
+			-3:00	-	ART
+#
+# San Juan (SJ)
+Zone America/Argentina/San_Juan -4:34:04 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1991 Mar  1
+			-4:00	-	WART	1991 May  7
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	-	ART	2004 May 31
+			-4:00	-	WART	2004 Jul 25
+			-3:00	Arg	AR%sT	2008 Oct 18
+			-3:00	-	ART
+#
+# Jujuy (JY)
+Zone America/Argentina/Jujuy -4:21:12 -	LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1990 Mar  4
+			-4:00	-	WART	1990 Oct 28
+			-4:00	1:00	WARST	1991 Mar 17
+			-4:00	-	WART	1991 Oct  6
+			-3:00	1:00	ARST	1992
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	Arg	AR%sT	2008 Oct 18
+			-3:00	-	ART
+#
+# Catamarca (CT), Chubut (CH)
+Zone America/Argentina/Catamarca -4:23:08 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1991 Mar  3
+			-4:00	-	WART	1991 Oct 20
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	-	ART	2004 Jun  1
+			-4:00	-	WART	2004 Jun 20
+			-3:00	Arg	AR%sT	2008 Oct 18
+			-3:00	-	ART
+#
+# Mendoza (MZ)
+Zone America/Argentina/Mendoza -4:35:16 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1990 Mar  4
+			-4:00	-	WART	1990 Oct 15
+			-4:00	1:00	WARST	1991 Mar  1
+			-4:00	-	WART	1991 Oct 15
+			-4:00	1:00	WARST	1992 Mar  1
+			-4:00	-	WART	1992 Oct 18
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	-	ART	2004 May 23
+			-4:00	-	WART	2004 Sep 26
+			-3:00	Arg	AR%sT	2008 Oct 18
+			-3:00	-	ART
+#
+# San Luis (SL)
+Zone America/Argentina/San_Luis -4:25:24 - LMT	1894 Oct 31
+			-4:16:48 -	CMT	1920 May
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1990
+			-3:00	1:00	ARST	1990 Mar 14
+			-4:00	-	WART	1990 Oct 15
+			-4:00	1:00	WARST	1991 Mar  1
+			-4:00	-	WART	1991 Jun  1
+			-3:00	-	ART	1999 Oct  3
+			-4:00	1:00	WARST	2000 Mar  3
+			-3:00	-	ART	2004 May 31
+			-4:00	-	WART	2004 Jul 25
+			-3:00	Arg	AR%sT	2008 Jan 21
+			-3:00	-	ART	2009 Mar 15
+			-4:00	Arg	WAR%sT
+#
+# Santa Cruz (SC)
+Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
+			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	-	ART	2004 Jun  1
+			-4:00	-	WART	2004 Jun 20
+			-3:00	Arg	AR%sT	2008 Oct 18
+			-3:00	-	ART
+#
+# Tierra del Fuego, Antartida e Islas del Atlantico Sur (TF)
+Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31
+			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
+			-4:00	-	ART	1930 Dec
+			-4:00	Arg	AR%sT	1969 Oct  5
+			-3:00	Arg	AR%sT	1999 Oct  3
+			-4:00	Arg	AR%sT	2000 Mar  3
+			-3:00	-	ART	2004 May 30
+			-4:00	-	WART	2004 Jun 20
+			-3:00	Arg	AR%sT	2008 Oct 18
+			-3:00	-	ART
+
+# Aruba
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Aruba	-4:40:24 -	LMT	1912 Feb 12	# Oranjestad
+			-4:30	-	ANT	1965 # Netherlands Antilles Time
+			-4:00	-	AST
+
+# Bolivia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/La_Paz	-4:32:36 -	LMT	1890
+			-4:32:36 -	CMT	1931 Oct 15 # Calamarca MT
+			-4:32:36 1:00	BOST	1932 Mar 21 # Bolivia ST
+			-4:00	-	BOT	# Bolivia Time
+
+# Brazil
+
+# From Paul Eggert (1993-11-18):
+# The mayor of Rio recently attempted to change the time zone rules
+# just in his city, in order to leave more summer time for the tourist trade.
+# The rule change lasted only part of the day;
+# the federal government refused to follow the city's rules, and business
+# was in a chaos, so the mayor backed down that afternoon.
+
+# From IATA SSIM (1996-02):
+# _Only_ the following states in BR1 observe DST: Rio Grande do Sul (RS),
+# Santa Catarina (SC), Parana (PR), Sao Paulo (SP), Rio de Janeiro (RJ),
+# Espirito Santo (ES), Minas Gerais (MG), Bahia (BA), Goias (GO),
+# Distrito Federal (DF), Tocantins (TO), Sergipe [SE] and Alagoas [AL].
+# [The last three states are new to this issue of the IATA SSIM.]
+
+# From Gwillim Law (1996-10-07):
+# Geography, history (Tocantins was part of Goias until 1989), and other
+# sources of time zone information lead me to believe that AL, SE, and TO were
+# always in BR1, and so the only change was whether or not they observed DST....
+# The earliest issue of the SSIM I have is 2/91.  Each issue from then until
+# 9/95 says that DST is observed only in the ten states I quoted from 9/95,
+# along with Mato Grosso (MT) and Mato Grosso do Sul (MS), which are in BR2
+# (UTC-4)....  The other two time zones given for Brazil are BR3, which is
+# UTC-5, no DST, and applies only in the state of Acre (AC); and BR4, which is
+# UTC-2, and applies to Fernando de Noronha (formerly FN, but I believe it's
+# become part of the state of Pernambuco).  The boundary between BR1 and BR2
+# has never been clearly stated.  They've simply been called East and West.
+# However, some conclusions can be drawn from another IATA manual: the Airline
+# Coding Directory, which lists close to 400 airports in Brazil.  For each
+# airport it gives a time zone which is coded to the SSIM.  From that
+# information, I'm led to conclude that the states of Amapa (AP), Ceara (CE),
+# Maranhao (MA), Paraiba (PR), Pernambuco (PE), Piaui (PI), and Rio Grande do
+# Norte (RN), and the eastern part of Para (PA) are all in BR1 without DST.
+
+# From Marcos Tadeu (1998-09-27):
+# 
+# Brazilian official page
+# 
+
+# From Jesper Norgaard (2000-11-03):
+# [For an official list of which regions in Brazil use which time zones, see:]
+# http://pcdsh01.on.br/Fusbr.htm
+# http://pcdsh01.on.br/Fusbrhv.htm
+
+# From Celso Doria via David Madeo (2002-10-09):
+# The reason for the delay this year has to do with elections in Brazil.
+#
+# Unlike in the United States, elections in Brazil are 100% computerized and
+# the results are known almost immediately.  Yesterday, it was the first
+# round of the elections when 115 million Brazilians voted for President,
+# Governor, Senators, Federal Deputies, and State Deputies.  Nobody is
+# counting (or re-counting) votes anymore and we know there will be a second
+# round for the Presidency and also for some Governors.  The 2nd round will
+# take place on October 27th.
+#
+# The reason why the DST will only begin November 3rd is that the thousands
+# of electoral machines used cannot have their time changed, and since the
+# Constitution says the elections must begin at 8:00 AM and end at 5:00 PM,
+# the Government decided to postpone DST, instead of changing the Constitution
+# (maybe, for the next elections, it will be possible to change the clock)...
+
+# From Rodrigo Severo (2004-10-04):
+# It's just the biannual change made necessary by the much hyped, supposedly
+# modern Brazilian eletronic voting machines which, apparently, can't deal
+# with a time change between the first and the second rounds of the elections.
+
+# From Steffen Thorsen (2007-09-20):
+# Brazil will start DST on 2007-10-14 00:00 and end on 2008-02-17 00:00:
+# http://www.mme.gov.br/site/news/detail.do;jsessionid=BBA06811AFCAAC28F0285210913513DA?newsId=13975
+
+# From Paul Schulze (2008-06-24):
+# ...by law number 11.662 of April 24, 2008 (published in the "Diario
+# Oficial da Uniao"...) in Brazil there are changes in the timezones,
+# effective today (00:00am at June 24, 2008) as follows:
+#
+# a) The timezone UTC+5 is e[x]tinguished, with all the Acre state and the
+# part of the Amazonas state that had this timezone now being put to the
+# timezone UTC+4
+# b) The whole Para state now is put at timezone UTC+3, instead of just
+# part of it, as was before.
+#
+# This change follows a proposal of senator Tiao Viana of Acre state, that
+# proposed it due to concerns about open television channels displaying
+# programs inappropriate to youths in the states that had the timezone
+# UTC+5 too early in the night. In the occasion, some more corrections
+# were proposed, trying to unify the timezones of any given state. This
+# change modifies timezone rules defined in decree 2.784 of 18 June,
+# 1913.
+
+# From Rodrigo Severo (2008-06-24):
+# Just correcting the URL:
+# 
+# https://www.in.gov.br/imprensa/visualiza/index.jsp?jornal=3Ddo&secao=3D1&pagina=3D1&data=3D25/04/2008
+# 
+#
+# As a result of the above Decree I believe the America/Rio_Branco
+# timezone shall be modified from UTC-5 to UTC-4 and a new timezone shall
+# be created to represent the the west side of the Para State. I
+# suggest this new timezone be called Santarem as the most
+# important/populated city in the affected area.
+#
+# This new timezone would be the same as the Rio_Branco timezone up to
+# the 2008/06/24 change which would be to UTC-3 instead of UTC-4.
+
+# From Alex Krivenyshev (2008-06-24):
+# This is a quick reference page for New and Old Brazil Time Zones map.
+# 
+# http://www.worldtimezone.com/brazil-time-new-old.php
+# 
+#
+# - 4 time zones replaced by 3 time zones-eliminating time zone UTC- 05
+# (state Acre and the part of the Amazonas will be UTC/GMT- 04) - western
+# part of Par state is moving to one timezone UTC- 03 (from UTC -04).
+
+# From Paul Eggert (2002-10-10):
+# The official decrees referenced below are mostly taken from
+# 
+# Decretos sobre o Horario de Verao no Brasil
+# .
+
+# From Steffen Thorsen (2008-08-29):
+# As announced by the government and many newspapers in Brazil late
+# yesterday, Brazil will start DST on 2008-10-19 (need to change rule) and
+# it will end on 2009-02-15 (current rule for Brazil is fine). Based on
+# past years experience with the elections, there was a good chance that
+# the start was postponed to November, but it did not happen this year.
+#
+# It has not yet been posted to http://pcdsh01.on.br/DecHV.html
+#
+# An official page about it:
+# 
+# http://www.mme.gov.br/site/news/detail.do?newsId=16722
+# 
+# Note that this link does not always work directly, but must be accessed
+# by going to
+# 
+# http://www.mme.gov.br/first
+# 
+#
+# One example link that works directly:
+# 
+# http://jornale.com.br/index.php?option=com_content&task=view&id=13530&Itemid=54
+# (Portuguese)
+# 
+#
+# We have a written a short article about it as well:
+# 
+# http://www.timeanddate.com/news/time/brazil-dst-2008-2009.html
+# 
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+# Decree 20,466 (1931-10-01)
+# Decree 21,896 (1932-01-10)
+Rule	Brazil	1931	only	-	Oct	 3	11:00	1:00	S
+Rule	Brazil	1932	1933	-	Apr	 1	 0:00	0	-
+Rule	Brazil	1932	only	-	Oct	 3	 0:00	1:00	S
+# Decree 23,195 (1933-10-10)
+# revoked DST.
+# Decree 27,496 (1949-11-24)
+# Decree 27,998 (1950-04-13)
+Rule	Brazil	1949	1952	-	Dec	 1	 0:00	1:00	S
+Rule	Brazil	1950	only	-	Apr	16	 1:00	0	-
+Rule	Brazil	1951	1952	-	Apr	 1	 0:00	0	-
+# Decree 32,308 (1953-02-24)
+Rule	Brazil	1953	only	-	Mar	 1	 0:00	0	-
+# Decree 34,724 (1953-11-30)
+# revoked DST.
+# Decree 52,700 (1963-10-18)
+# established DST from 1963-10-23 00:00 to 1964-02-29 00:00
+# in SP, RJ, GB, MG, ES, due to the prolongation of the drought.
+# Decree 53,071 (1963-12-03)
+# extended the above decree to all of the national territory on 12-09.
+Rule	Brazil	1963	only	-	Dec	 9	 0:00	1:00	S
+# Decree 53,604 (1964-02-25)
+# extended summer time by one day to 1964-03-01 00:00 (start of school).
+Rule	Brazil	1964	only	-	Mar	 1	 0:00	0	-
+# Decree 55,639 (1965-01-27)
+Rule	Brazil	1965	only	-	Jan	31	 0:00	1:00	S
+Rule	Brazil	1965	only	-	Mar	31	 0:00	0	-
+# Decree 57,303 (1965-11-22)
+Rule	Brazil	1965	only	-	Dec	 1	 0:00	1:00	S
+# Decree 57,843 (1966-02-18)
+Rule	Brazil	1966	1968	-	Mar	 1	 0:00	0	-
+Rule	Brazil	1966	1967	-	Nov	 1	 0:00	1:00	S
+# Decree 63,429 (1968-10-15)
+# revoked DST.
+# Decree 91,698 (1985-09-27)
+Rule	Brazil	1985	only	-	Nov	 2	 0:00	1:00	S
+# Decree 92,310 (1986-01-21)
+# Decree 92,463 (1986-03-13)
+Rule	Brazil	1986	only	-	Mar	15	 0:00	0	-
+# Decree 93,316 (1986-10-01)
+Rule	Brazil	1986	only	-	Oct	25	 0:00	1:00	S
+Rule	Brazil	1987	only	-	Feb	14	 0:00	0	-
+# Decree 94,922 (1987-09-22)
+Rule	Brazil	1987	only	-	Oct	25	 0:00	1:00	S
+Rule	Brazil	1988	only	-	Feb	 7	 0:00	0	-
+# Decree 96,676 (1988-09-12)
+# except for the states of AC, AM, PA, RR, RO, and AP (then a territory)
+Rule	Brazil	1988	only	-	Oct	16	 0:00	1:00	S
+Rule	Brazil	1989	only	-	Jan	29	 0:00	0	-
+# Decree 98,077 (1989-08-21)
+# with the same exceptions
+Rule	Brazil	1989	only	-	Oct	15	 0:00	1:00	S
+Rule	Brazil	1990	only	-	Feb	11	 0:00	0	-
+# Decree 99,530 (1990-09-17)
+# adopted by RS, SC, PR, SP, RJ, ES, MG, GO, MS, DF.
+# Decree 99,629 (1990-10-19) adds BA, MT.
+Rule	Brazil	1990	only	-	Oct	21	 0:00	1:00	S
+Rule	Brazil	1991	only	-	Feb	17	 0:00	0	-
+# Unnumbered decree (1991-09-25)
+# adopted by RS, SC, PR, SP, RJ, ES, MG, BA, GO, MT, MS, DF.
+Rule	Brazil	1991	only	-	Oct	20	 0:00	1:00	S
+Rule	Brazil	1992	only	-	Feb	 9	 0:00	0	-
+# Unnumbered decree (1992-10-16)
+# adopted by same states.
+Rule	Brazil	1992	only	-	Oct	25	 0:00	1:00	S
+Rule	Brazil	1993	only	-	Jan	31	 0:00	0	-
+# Decree 942 (1993-09-28)
+# adopted by same states, plus AM.
+# Decree 1,252 (1994-09-22;
+# web page corrected 2004-01-07) adopted by same states, minus AM.
+# Decree 1,636 (1995-09-14)
+# adopted by same states, plus MT and TO.
+# Decree 1,674 (1995-10-13)
+# adds AL, SE.
+Rule	Brazil	1993	1995	-	Oct	Sun>=11	 0:00	1:00	S
+Rule	Brazil	1994	1995	-	Feb	Sun>=15	 0:00	0	-
+Rule	Brazil	1996	only	-	Feb	11	 0:00	0	-
+# Decree 2,000 (1996-09-04)
+# adopted by same states, minus AL, SE.
+Rule	Brazil	1996	only	-	Oct	 6	 0:00	1:00	S
+Rule	Brazil	1997	only	-	Feb	16	 0:00	0	-
+# From Daniel C. Sobral (1998-02-12):
+# In 1997, the DS began on October 6. The stated reason was that
+# because international television networks ignored Brazil's policy on DS,
+# they bought the wrong times on satellite for coverage of Pope's visit.
+# This year, the ending date of DS was postponed to March 1
+# to help dealing with the shortages of electric power.
+#
+# Decree 2,317 (1997-09-04), adopted by same states.
+Rule	Brazil	1997	only	-	Oct	 6	 0:00	1:00	S
+# Decree 2,495
+# (1998-02-10)
+Rule	Brazil	1998	only	-	Mar	 1	 0:00	0	-
+# Decree 2,780 (1998-09-11)
+# adopted by the same states as before.
+Rule	Brazil	1998	only	-	Oct	11	 0:00	1:00	S
+Rule	Brazil	1999	only	-	Feb	21	 0:00	0	-
+# Decree 3,150
+# (1999-08-23) adopted by same states.
+# Decree 3,188 (1999-09-30)
+# adds SE, AL, PB, PE, RN, CE, PI, MA and RR.
+Rule	Brazil	1999	only	-	Oct	 3	 0:00	1:00	S
+Rule	Brazil	2000	only	-	Feb	27	 0:00	0	-
+# Decree 3,592 (2000-09-06)
+# adopted by the same states as before.
+# Decree 3,630 (2000-10-13)
+# repeals DST in PE and RR, effective 2000-10-15 00:00.
+# Decree 3,632 (2000-10-17)
+# repeals DST in SE, AL, PB, RN, CE, PI and MA, effective 2000-10-22 00:00.
+# Decree 3,916
+# (2001-09-13) reestablishes DST in AL, CE, MA, PB, PE, PI, RN, SE.
+Rule	Brazil	2000	2001	-	Oct	Sun>=8	 0:00	1:00	S
+Rule	Brazil	2001	2006	-	Feb	Sun>=15	 0:00	0	-
+# Decree 4,399 (2002-10-01) repeals DST in AL, CE, MA, PB, PE, PI, RN, SE.
+# 4,399
+Rule	Brazil	2002	only	-	Nov	 3	 0:00	1:00	S
+# Decree 4,844 (2003-09-24; corrected 2003-09-26) repeals DST in BA, MT, TO.
+# 4,844
+Rule	Brazil	2003	only	-	Oct	19	 0:00	1:00	S
+# Decree 5,223 (2004-10-01) reestablishes DST in MT.
+# 5,223
+Rule	Brazil	2004	only	-	Nov	 2	 0:00	1:00	S
+# Decree 5,539 (2005-09-19),
+# adopted by the same states as before.
+Rule	Brazil	2005	only	-	Oct	16	 0:00	1:00	S
+# Decree 5,920 (2006-10-03),
+# adopted by the same states as before.
+Rule	Brazil	2006	only	-	Nov	 5	 0:00	1:00	S
+Rule	Brazil	2007	only	-	Feb	25	 0:00	0	-
+# Decree 6,212 (2007-09-26),
+# adopted by the same states as before.
+Rule	Brazil	2007	only	-	Oct	Sun>=8	 0:00	1:00	S
+# From Frederico A. C. Neves (2008-09-10):
+# Acording to this decree
+# 
+# http://www.planalto.gov.br/ccivil_03/_Ato2007-2010/2008/Decreto/D6558.htm
+# 
+# [t]he DST period in Brazil now on will be from the 3rd Oct Sunday to the
+# 3rd Feb Sunday. There is an exception on the return date when this is
+# the Carnival Sunday then the return date will be the next Sunday...
+Rule	Brazil	2008	max	-	Oct	Sun>=15	0:00	1:00	S
+Rule	Brazil	2008	2011	-	Feb	Sun>=15	0:00	0	-
+Rule	Brazil	2012	only	-	Feb	Sun>=22	0:00	0	-
+Rule	Brazil	2013	2014	-	Feb	Sun>=15	0:00	0	-
+Rule	Brazil	2015	only	-	Feb	Sun>=22	0:00	0	-
+Rule	Brazil	2016	2022	-	Feb	Sun>=15	0:00	0	-
+Rule	Brazil	2023	only	-	Feb	Sun>=22	0:00	0	-
+Rule	Brazil	2024	2025	-	Feb	Sun>=15	0:00	0	-
+Rule	Brazil	2026	only	-	Feb	Sun>=22	0:00	0	-
+Rule	Brazil	2027	2033	-	Feb	Sun>=15	0:00	0	-
+Rule	Brazil	2034	only	-	Feb	Sun>=22	0:00	0	-
+Rule	Brazil	2035	2036	-	Feb	Sun>=15	0:00	0	-
+Rule	Brazil	2037	only	-	Feb	Sun>=22	0:00	0	-
+# From Arthur David Olson (2008-09-29):
+# The next is wrong in some years but is better than nothing.
+Rule	Brazil	2038	max	-	Feb	Sun>=15	0:00	0	-
+
+# The latest ruleset listed above says that the following states observe DST:
+# DF, ES, GO, MG, MS, MT, PR, RJ, RS, SC, SP.
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+#
+# Fernando de Noronha (administratively part of PE)
+Zone America/Noronha	-2:09:40 -	LMT	1914
+			-2:00	Brazil	FN%sT	1990 Sep 17
+			-2:00	-	FNT	1999 Sep 30
+			-2:00	Brazil	FN%sT	2000 Oct 15
+			-2:00	-	FNT	2001 Sep 13
+			-2:00	Brazil	FN%sT	2002 Oct  1
+			-2:00	-	FNT
+# Other Atlantic islands have no permanent settlement.
+# These include Trindade and Martin Vaz (administratively part of ES),
+# Atol das Rocas (RN), and Penedos de Sao Pedro e Sao Paulo (PE).
+# Fernando de Noronha was a separate territory from 1942-09-02 to 1989-01-01;
+# it also included the Penedos.
+#
+# Amapa (AP), east Para (PA)
+# East Para includes Belem, Maraba, Serra Norte, and Sao Felix do Xingu.
+# The division between east and west Para is the river Xingu.
+# In the north a very small part from the river Javary (now Jari I guess,
+# the border with Amapa) to the Amazon, then to the Xingu.
+Zone America/Belem	-3:13:56 -	LMT	1914
+			-3:00	Brazil	BR%sT	1988 Sep 12
+			-3:00	-	BRT
+#
+# west Para (PA)
+# West Para includes Altamira, Oribidos, Prainha, Oriximina, and Santarem.
+Zone America/Santarem	-3:38:48 -	LMT	1914
+			-4:00	Brazil	AM%sT	1988 Sep 12
+			-4:00	-	AMT	2008 Jun 24 00:00
+			-3:00	-	BRT
+#
+# Maranhao (MA), Piaui (PI), Ceara (CE), Rio Grande do Norte (RN),
+# Paraiba (PB)
+Zone America/Fortaleza	-2:34:00 -	LMT	1914
+			-3:00	Brazil	BR%sT	1990 Sep 17
+			-3:00	-	BRT	1999 Sep 30
+			-3:00	Brazil	BR%sT	2000 Oct 22
+			-3:00	-	BRT	2001 Sep 13
+			-3:00	Brazil	BR%sT	2002 Oct  1
+			-3:00	-	BRT
+#
+# Pernambuco (PE) (except Atlantic islands)
+Zone America/Recife	-2:19:36 -	LMT	1914
+			-3:00	Brazil	BR%sT	1990 Sep 17
+			-3:00	-	BRT	1999 Sep 30
+			-3:00	Brazil	BR%sT	2000 Oct 15
+			-3:00	-	BRT	2001 Sep 13
+			-3:00	Brazil	BR%sT	2002 Oct  1
+			-3:00	-	BRT
+#
+# Tocantins (TO)
+Zone America/Araguaina	-3:12:48 -	LMT	1914
+			-3:00	Brazil	BR%sT	1990 Sep 17
+			-3:00	-	BRT	1995 Sep 14
+			-3:00	Brazil	BR%sT	2003 Sep 24
+			-3:00	-	BRT
+#
+# Alagoas (AL), Sergipe (SE)
+Zone America/Maceio	-2:22:52 -	LMT	1914
+			-3:00	Brazil	BR%sT	1990 Sep 17
+			-3:00	-	BRT	1995 Oct 13
+			-3:00	Brazil	BR%sT	1996 Sep  4
+			-3:00	-	BRT	1999 Sep 30
+			-3:00	Brazil	BR%sT	2000 Oct 22
+			-3:00	-	BRT	2001 Sep 13
+			-3:00	Brazil	BR%sT	2002 Oct  1
+			-3:00	-	BRT
+#
+# Bahia (BA)
+# There are too many Salvadors elsewhere, so use America/Bahia instead
+# of America/Salvador.
+Zone America/Bahia	-2:34:04 -	LMT	1914
+			-3:00	Brazil	BR%sT	2003 Sep 24
+			-3:00	-	BRT
+#
+# Goias (GO), Distrito Federal (DF), Minas Gerais (MG),
+# Espirito Santo (ES), Rio de Janeiro (RJ), Sao Paulo (SP), Parana (PR),
+# Santa Catarina (SC), Rio Grande do Sul (RS)
+Zone America/Sao_Paulo	-3:06:28 -	LMT	1914
+			-3:00	Brazil	BR%sT	1963 Oct 23 00:00
+			-3:00	1:00	BRST	1964
+			-3:00	Brazil	BR%sT
+#
+# Mato Grosso do Sul (MS)
+Zone America/Campo_Grande -3:38:28 -	LMT	1914
+			-4:00	Brazil	AM%sT
+#
+# Mato Grosso (MT)
+Zone America/Cuiaba	-3:44:20 -	LMT	1914
+			-4:00	Brazil	AM%sT	2003 Sep 24
+			-4:00	-	AMT	2004 Oct  1
+			-4:00	Brazil	AM%sT
+#
+# Rondonia (RO)
+Zone America/Porto_Velho -4:15:36 -	LMT	1914
+			-4:00	Brazil	AM%sT	1988 Sep 12
+			-4:00	-	AMT
+#
+# Roraima (RR)
+Zone America/Boa_Vista	-4:02:40 -	LMT	1914
+			-4:00	Brazil	AM%sT	1988 Sep 12
+			-4:00	-	AMT	1999 Sep 30
+			-4:00	Brazil	AM%sT	2000 Oct 15
+			-4:00	-	AMT
+#
+# east Amazonas (AM): Boca do Acre, Jutai, Manaus, Floriano Peixoto
+# The great circle line from Tabatinga to Porto Acre divides
+# east from west Amazonas.
+Zone America/Manaus	-4:00:04 -	LMT	1914
+			-4:00	Brazil	AM%sT	1988 Sep 12
+			-4:00	-	AMT	1993 Sep 28
+			-4:00	Brazil	AM%sT	1994 Sep 22
+			-4:00	-	AMT
+#
+# west Amazonas (AM): Atalaia do Norte, Boca do Maoco, Benjamin Constant,
+#	Eirunepe, Envira, Ipixuna
+Zone America/Eirunepe	-4:39:28 -	LMT	1914
+			-5:00	Brazil	AC%sT	1988 Sep 12
+			-5:00	-	ACT	1993 Sep 28
+			-5:00	Brazil	AC%sT	1994 Sep 22
+			-5:00	-	ACT	2008 Jun 24 00:00
+			-4:00	-	AMT
+#
+# Acre (AC)
+Zone America/Rio_Branco	-4:31:12 -	LMT	1914
+			-5:00	Brazil	AC%sT	1988 Sep 12
+			-5:00	-	ACT	2008 Jun 24 00:00
+			-4:00	-	AMT
+
+# Chile
+
+# From Eduardo Krell (1995-10-19):
+# The law says to switch to DST at midnight [24:00] on the second SATURDAY
+# of October....  The law is the same for March and October.
+# (1998-09-29):
+# Because of the drought this year, the government decided to go into
+# DST earlier (saturday 9/26 at 24:00). This is a one-time change only ...
+# (unless there's another dry season next year, I guess).
+
+# From Julio I. Pacheco Troncoso (1999-03-18):
+# Because of the same drought, the government decided to end DST later,
+# on April 3, (one-time change).
+
+# From Oscar van Vlijmen (2006-10-08):
+# http://www.horaoficial.cl/cambio.htm
+
+# From Jesper Norgaard Welen (2006-10-08):
+# I think that there are some obvious mistakes in the suggested link
+# from Oscar van Vlijmen,... for instance entry 66 says that GMT-4
+# ended 1990-09-12 while entry 67 only begins GMT-3 at 1990-09-15
+# (they should have been 1990-09-15 and 1990-09-16 respectively), but
+# anyhow it clears up some doubts too.
+
+# From Paul Eggert (2006-12-27):
+# The following data for Chile and America/Santiago are from
+#  (2006-09-20), transcribed by
+# Jesper Norgaard Welen.  The data for Pacific/Easter are from Shanks
+# & Pottenger, except with DST transitions after 1932 cloned from
+# America/Santiago.  The pre-1980 Pacific/Easter data are dubious,
+# but we have no other source.
+
+# From German Poo-Caaman~o (2008-03-03):
+# Due to drought, Chile extends Daylight Time in three weeks.  This
+# is one-time change (Saturday 3/29 at 24:00 for America/Santiago
+# and Saturday 3/29 at 22:00 for Pacific/Easter)
+# The Supreme Decree is located at 
+# 
+# http://www.shoa.cl/servicios/supremo316.pdf
+# 
+# and the instructions for 2008 are located in:
+# 
+# http://www.horaoficial.cl/cambio.htm
+# .
+
+# From Jose Miguel Garrido (2008-03-05):
+# ...
+# You could see the announces of the change on 
+# 
+# http://www.shoa.cl/noticias/2008/04hora/hora.htm
+# .
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Chile	1927	1932	-	Sep	 1	0:00	1:00	S
+Rule	Chile	1928	1932	-	Apr	 1	0:00	0	-
+Rule	Chile	1942	only	-	Jun	 1	4:00u	0	-
+Rule	Chile	1942	only	-	Aug	 1	5:00u	1:00	S
+Rule	Chile	1946	only	-	Jul	15	4:00u	1:00	S
+Rule	Chile	1946	only	-	Sep	 1	3:00u	0:00	-
+Rule	Chile	1947	only	-	Apr	 1	4:00u	0	-
+Rule	Chile	1968	only	-	Nov	 3	4:00u	1:00	S
+Rule	Chile	1969	only	-	Mar	30	3:00u	0	-
+Rule	Chile	1969	only	-	Nov	23	4:00u	1:00	S
+Rule	Chile	1970	only	-	Mar	29	3:00u	0	-
+Rule	Chile	1971	only	-	Mar	14	3:00u	0	-
+Rule	Chile	1970	1972	-	Oct	Sun>=9	4:00u	1:00	S
+Rule	Chile	1972	1986	-	Mar	Sun>=9	3:00u	0	-
+Rule	Chile	1973	only	-	Sep	30	4:00u	1:00	S
+Rule	Chile	1974	1987	-	Oct	Sun>=9	4:00u	1:00	S
+Rule	Chile	1987	only	-	Apr	12	3:00u	0	-
+Rule	Chile	1988	1989	-	Mar	Sun>=9	3:00u	0	-
+Rule	Chile	1988	only	-	Oct	Sun>=1	4:00u	1:00	S
+Rule	Chile	1989	only	-	Oct	Sun>=9	4:00u	1:00	S
+Rule	Chile	1990	only	-	Mar	18	3:00u	0	-
+Rule	Chile	1990	only	-	Sep	16	4:00u	1:00	S
+Rule	Chile	1991	1996	-	Mar	Sun>=9	3:00u	0	-
+Rule	Chile	1991	1997	-	Oct	Sun>=9	4:00u	1:00	S
+Rule	Chile	1997	only	-	Mar	30	3:00u	0	-
+Rule	Chile	1998	only	-	Mar	Sun>=9	3:00u	0	-
+Rule	Chile	1998	only	-	Sep	27	4:00u	1:00	S
+Rule	Chile	1999	only	-	Apr	 4	3:00u	0	-
+Rule	Chile	1999	max	-	Oct	Sun>=9	4:00u	1:00	S
+Rule	Chile	2000	2007	-	Mar	Sun>=9	3:00u	0	-
+# N.B.: the end of March 29 in Chile is March 30 in Universal time,
+# which is used below in specifying the transition.
+Rule	Chile	2008	only	-	Mar	30	3:00u	0	-
+Rule	Chile	2009	max	-	Mar	Sun>=9	3:00u	0	-
+# IATA SSIM anomalies: (1992-02) says 1992-03-14;
+# (1996-09) says 1998-03-08.  Ignore these.
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Santiago	-4:42:46 -	LMT	1890
+			-4:42:46 -	SMT	1910 	    # Santiago Mean Time
+			-5:00	-	CLT	1916 Jul  1 # Chile Time
+			-4:42:46 -	SMT	1918 Sep  1 # Santiago Mean Time
+			-4:00	-	CLT	1919 Jul  1 # Chile Time
+			-4:42:46 -	SMT	1927 Sep  1 # Santiago Mean Time
+			-5:00	Chile	CL%sT	1947 May 22 # Chile Time
+			-4:00	Chile	CL%sT
+Zone Pacific/Easter	-7:17:44 -	LMT	1890
+			-7:17:28 -	EMT	1932 Sep    # Easter Mean Time
+			-7:00	Chile	EAS%sT	1982 Mar 13 21:00 # Easter I Time
+			-6:00	Chile	EAS%sT
+#
+# Sala y Gomez Island is like Pacific/Easter.
+# Other Chilean locations, including Juan Fernandez Is, San Ambrosio,
+# San Felix, and Antarctic bases, are like America/Santiago.
+
+# Colombia
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	CO	1992	only	-	May	 3	0:00	1:00	S
+Rule	CO	1993	only	-	Apr	 4	0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Bogota	-4:56:20 -	LMT	1884 Mar 13
+			-4:56:20 -	BMT	1914 Nov 23 # Bogota Mean Time
+			-5:00	CO	CO%sT	# Colombia Time
+# Malpelo, Providencia, San Andres
+# no information; probably like America/Bogota
+
+# Curacao
+#
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger say that The Bottom and Philipsburg have been at
+# -4:00 since standard time was introduced on 1912-03-02; and that
+# Kralendijk and Rincon used Kralendijk Mean Time (-4:33:08) from
+# 1912-02-02 to 1965-01-01.  The former is dubious, since S&P also say
+# Saba Island has been like Curacao.
+# This all predates our 1970 cutoff, though.
+#
+# By July 2007 Curacao and St Maarten are planned to become
+# associated states within the Netherlands, much like Aruba;
+# Bonaire, Saba and St Eustatius would become directly part of the
+# Netherlands as Kingdom Islands.  This won't affect their time zones
+# though, as far as we know.
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Curacao	-4:35:44 -	LMT	1912 Feb 12	# Willemstad
+			-4:30	-	ANT	1965 # Netherlands Antilles Time
+			-4:00	-	AST
+
+# Ecuador
+#
+# From Paul Eggert (2007-03-04):
+# Apparently Ecuador had a failed experiment with DST in 1992.
+#  (2007-02-27) and
+#  (2006-11-06) both
+# talk about "hora Sixto".  Leave this alone for now, as we have no data.
+#
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Guayaquil	-5:19:20 -	LMT	1890
+			-5:14:00 -	QMT	1931 # Quito Mean Time
+			-5:00	-	ECT	     # Ecuador Time
+Zone Pacific/Galapagos	-5:58:24 -	LMT	1931 # Puerto Baquerizo Moreno
+			-5:00	-	ECT	1986
+			-6:00	-	GALT	     # Galapagos Time
+
+# Falklands
+
+# From Paul Eggert (2006-03-22):
+# Between 1990 and 2000 inclusive, Shanks & Pottenger and the IATA agree except
+# the IATA gives 1996-09-08.  Go with Shanks & Pottenger.
+
+# From Falkland Islands Government Office, London (2001-01-22)
+# via Jesper Norgaard:
+# ... the clocks revert back to Local Mean Time at 2 am on Sunday 15
+# April 2001 and advance one hour to summer time at 2 am on Sunday 2
+# September.  It is anticipated that the clocks will revert back at 2
+# am on Sunday 21 April 2002 and advance to summer time at 2 am on
+# Sunday 1 September.
+
+# From Rives McDow (2001-02-13):
+#
+# I have communicated several times with people there, and the last
+# time I had communications that was helpful was in 1998.  Here is
+# what was said then:
+#
+# "The general rule was that Stanley used daylight saving and the Camp
+# did not. However for various reasons many people in the Camp have
+# started to use daylight saving (known locally as 'Stanley Time')
+# There is no rule as to who uses daylight saving - it is a matter of
+# personal choice and so it is impossible to draw a map showing who
+# uses it and who does not. Any list would be out of date as soon as
+# it was produced. This year daylight saving ended on April 18/19th
+# and started again on September 12/13th.  I do not know what the rule
+# is, but can find out if you like.  We do not change at the same time
+# as UK or Chile."
+#
+# I did have in my notes that the rule was "Second Saturday in Sep at
+# 0:00 until third Saturday in Apr at 0:00".  I think that this does
+# not agree in some cases with Shanks; is this true?
+#
+# Also, there is no mention in the list that some areas in the
+# Falklands do not use DST.  I have found in my communications there
+# that these areas are on the western half of East Falkland and all of
+# West Falkland.  Stanley is the only place that consistently observes
+# DST.  Again, as in other places in the world, the farmers don't like
+# it.  West Falkland is almost entirely sheep farmers.
+#
+# I know one lady there that keeps a list of which farm keeps DST and
+# which doesn't each year.  She runs a shop in Stanley, and says that
+# the list changes each year.  She uses it to communicate to her
+# customers, catching them when they are home for lunch or dinner.
+
+# From Paul Eggert (2001-03-05):
+# For now, we'll just record the time in Stanley, since we have no
+# better info.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Falk	1937	1938	-	Sep	lastSun	0:00	1:00	S
+Rule	Falk	1938	1942	-	Mar	Sun>=19	0:00	0	-
+Rule	Falk	1939	only	-	Oct	1	0:00	1:00	S
+Rule	Falk	1940	1942	-	Sep	lastSun	0:00	1:00	S
+Rule	Falk	1943	only	-	Jan	1	0:00	0	-
+Rule	Falk	1983	only	-	Sep	lastSun	0:00	1:00	S
+Rule	Falk	1984	1985	-	Apr	lastSun	0:00	0	-
+Rule	Falk	1984	only	-	Sep	16	0:00	1:00	S
+Rule	Falk	1985	2000	-	Sep	Sun>=9	0:00	1:00	S
+Rule	Falk	1986	2000	-	Apr	Sun>=16	0:00	0	-
+Rule	Falk	2001	max	-	Apr	Sun>=15	2:00	0	-
+Rule	Falk	2001	max	-	Sep	Sun>=1	2:00	1:00	S
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Atlantic/Stanley	-3:51:24 -	LMT	1890
+			-3:51:24 -	SMT	1912 Mar 12  # Stanley Mean Time
+			-4:00	Falk	FK%sT	1983 May     # Falkland Is Time
+			-3:00	Falk	FK%sT	1985 Sep 15
+			-4:00	Falk	FK%sT
+
+# French Guiana
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Cayenne	-3:29:20 -	LMT	1911 Jul
+			-4:00	-	GFT	1967 Oct # French Guiana Time
+			-3:00	-	GFT
+
+# Guyana
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Guyana	-3:52:40 -	LMT	1915 Mar	# Georgetown
+			-3:45	-	GBGT	1966 May 26 # Br Guiana Time
+			-3:45	-	GYT	1975 Jul 31 # Guyana Time
+			-3:00	-	GYT	1991
+# IATA SSIM (1996-06) says -4:00.  Assume a 1991 switch.
+			-4:00	-	GYT
+
+# Paraguay
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger say that spring transitions are from 01:00 -> 02:00,
+# and autumn transitions are from 00:00 -> 23:00.  Go with pre-1999
+# editions of Shanks, and with the IATA, who say transitions occur at 00:00.
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Para	1975	1988	-	Oct	 1	0:00	1:00	S
+Rule	Para	1975	1978	-	Mar	 1	0:00	0	-
+Rule	Para	1979	1991	-	Apr	 1	0:00	0	-
+Rule	Para	1989	only	-	Oct	22	0:00	1:00	S
+Rule	Para	1990	only	-	Oct	 1	0:00	1:00	S
+Rule	Para	1991	only	-	Oct	 6	0:00	1:00	S
+Rule	Para	1992	only	-	Mar	 1	0:00	0	-
+Rule	Para	1992	only	-	Oct	 5	0:00	1:00	S
+Rule	Para	1993	only	-	Mar	31	0:00	0	-
+Rule	Para	1993	1995	-	Oct	 1	0:00	1:00	S
+Rule	Para	1994	1995	-	Feb	lastSun	0:00	0	-
+Rule	Para	1996	only	-	Mar	 1	0:00	0	-
+# IATA SSIM (2000-02) says 1999-10-10; ignore this for now.
+# From Steffen Thorsen (2000-10-02):
+# I have three independent reports that Paraguay changed to DST this Sunday
+# (10-01).
+#
+# Translated by Gwillim Law (2001-02-27) from
+# 
+# Noticias, a daily paper in Asuncion, Paraguay (2000-10-01)
+# :
+# Starting at 0:00 today, the clock will be set forward 60 minutes, in
+# fulfillment of Decree No. 7,273 of the Executive Power....  The time change
+# system has been operating for several years.  Formerly there was a separate
+# decree each year; the new law has the same effect, but permanently.  Every
+# year, the time will change on the first Sunday of October; likewise, the
+# clock will be set back on the first Sunday of March.
+#
+Rule	Para	1996	2001	-	Oct	Sun>=1	0:00	1:00	S
+# IATA SSIM (1997-09) says Mar 1; go with Shanks & Pottenger.
+Rule	Para	1997	only	-	Feb	lastSun	0:00	0	-
+# Shanks & Pottenger say 1999-02-28; IATA SSIM (1999-02) says 1999-02-27, but
+# (1999-09) reports no date; go with above sources and Gerd Knops (2001-02-27).
+Rule	Para	1998	2001	-	Mar	Sun>=1	0:00	0	-
+# From Rives McDow (2002-02-28):
+# A decree was issued in Paraguay (no. 16350) on 2002-02-26 that changed the
+# dst method to be from the first Sunday in September to the first Sunday in
+# April.
+Rule	Para	2002	2004	-	Apr	Sun>=1	0:00	0	-
+Rule	Para	2002	2003	-	Sep	Sun>=1	0:00	1:00	S
+#
+# From Jesper Norgaard Welen (2005-01-02):
+# There are several sources that claim that Paraguay made
+# a timezone rule change in autumn 2004.
+# From Steffen Thorsen (2005-01-05):
+# Decree 1,867 (2004-03-05)
+# From Carlos Raul Perasso via Jesper Norgaard Welen (2006-10-13)
+# 
+Rule	Para	2004	max	-	Oct	Sun>=15	0:00	1:00	S
+Rule	Para	2005	max	-	Mar	Sun>=8	0:00	0	-
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Asuncion	-3:50:40 -	LMT	1890
+			-3:50:40 -	AMT	1931 Oct 10 # Asuncion Mean Time
+			-4:00	-	PYT	1972 Oct # Paraguay Time
+			-3:00	-	PYT	1974 Apr
+			-4:00	Para	PY%sT
+
+# Peru
+#
+# 
+# From Evelyn C. Leeper via Mark Brader (2003-10-26):
+# When we were in Peru in 1985-1986, they apparently switched over
+# sometime between December 29 and January 3 while we were on the Amazon.
+#
+# From Paul Eggert (2006-03-22):
+# Shanks & Pottenger don't have this transition.  Assume 1986 was like 1987.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	Peru	1938	only	-	Jan	 1	0:00	1:00	S
+Rule	Peru	1938	only	-	Apr	 1	0:00	0	-
+Rule	Peru	1938	1939	-	Sep	lastSun	0:00	1:00	S
+Rule	Peru	1939	1940	-	Mar	Sun>=24	0:00	0	-
+Rule	Peru	1986	1987	-	Jan	 1	0:00	1:00	S
+Rule	Peru	1986	1987	-	Apr	 1	0:00	0	-
+Rule	Peru	1990	only	-	Jan	 1	0:00	1:00	S
+Rule	Peru	1990	only	-	Apr	 1	0:00	0	-
+# IATA is ambiguous for 1993/1995; go with Shanks & Pottenger.
+Rule	Peru	1994	only	-	Jan	 1	0:00	1:00	S
+Rule	Peru	1994	only	-	Apr	 1	0:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Lima	-5:08:12 -	LMT	1890
+			-5:08:36 -	LMT	1908 Jul 28 # Lima Mean Time?
+			-5:00	Peru	PE%sT	# Peru Time
+
+# South Georgia
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone Atlantic/South_Georgia -2:26:08 -	LMT	1890		# Grytviken
+			-2:00	-	GST	# South Georgia Time
+
+# South Sandwich Is
+# uninhabited; scientific personnel have wintered
+
+# Suriname
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Paramaribo	-3:40:40 -	LMT	1911
+			-3:40:52 -	PMT	1935     # Paramaribo Mean Time
+			-3:40:36 -	PMT	1945 Oct # The capital moved?
+			-3:30	-	NEGT	1975 Nov 20 # Dutch Guiana Time
+			-3:30	-	SRT	1984 Oct # Suriname Time
+			-3:00	-	SRT
+
+# Trinidad and Tobago
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Port_of_Spain -4:06:04 -	LMT	1912 Mar 2
+			-4:00	-	AST
+
+# Uruguay
+# From Paul Eggert (1993-11-18):
+# Uruguay wins the prize for the strangest peacetime manipulation of the rules.
+# From Shanks & Pottenger:
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+# Whitman gives 1923 Oct 1; go with Shanks & Pottenger.
+Rule	Uruguay	1923	only	-	Oct	 2	 0:00	0:30	HS
+Rule	Uruguay	1924	1926	-	Apr	 1	 0:00	0	-
+Rule	Uruguay	1924	1925	-	Oct	 1	 0:00	0:30	HS
+Rule	Uruguay	1933	1935	-	Oct	lastSun	 0:00	0:30	HS
+# Shanks & Pottenger give 1935 Apr 1 0:00 & 1936 Mar 30 0:00; go with Whitman.
+Rule	Uruguay	1934	1936	-	Mar	Sat>=25	23:30s	0	-
+Rule	Uruguay	1936	only	-	Nov	 1	 0:00	0:30	HS
+Rule	Uruguay	1937	1941	-	Mar	lastSun	 0:00	0	-
+# Whitman gives 1937 Oct 3; go with Shanks & Pottenger.
+Rule	Uruguay	1937	1940	-	Oct	lastSun	 0:00	0:30	HS
+# Whitman gives 1941 Oct 24 - 1942 Mar 27, 1942 Dec 14 - 1943 Apr 13,
+# and 1943 Apr 13 ``to present time''; go with Shanks & Pottenger.
+Rule	Uruguay	1941	only	-	Aug	 1	 0:00	0:30	HS
+Rule	Uruguay	1942	only	-	Jan	 1	 0:00	0	-
+Rule	Uruguay	1942	only	-	Dec	14	 0:00	1:00	S
+Rule	Uruguay	1943	only	-	Mar	14	 0:00	0	-
+Rule	Uruguay	1959	only	-	May	24	 0:00	1:00	S
+Rule	Uruguay	1959	only	-	Nov	15	 0:00	0	-
+Rule	Uruguay	1960	only	-	Jan	17	 0:00	1:00	S
+Rule	Uruguay	1960	only	-	Mar	 6	 0:00	0	-
+Rule	Uruguay	1965	1967	-	Apr	Sun>=1	 0:00	1:00	S
+Rule	Uruguay	1965	only	-	Sep	26	 0:00	0	-
+Rule	Uruguay	1966	1967	-	Oct	31	 0:00	0	-
+Rule	Uruguay	1968	1970	-	May	27	 0:00	0:30	HS
+Rule	Uruguay	1968	1970	-	Dec	 2	 0:00	0	-
+Rule	Uruguay	1972	only	-	Apr	24	 0:00	1:00	S
+Rule	Uruguay	1972	only	-	Aug	15	 0:00	0	-
+Rule	Uruguay	1974	only	-	Mar	10	 0:00	0:30	HS
+Rule	Uruguay	1974	only	-	Dec	22	 0:00	1:00	S
+Rule	Uruguay	1976	only	-	Oct	 1	 0:00	0	-
+Rule	Uruguay	1977	only	-	Dec	 4	 0:00	1:00	S
+Rule	Uruguay	1978	only	-	Apr	 1	 0:00	0	-
+Rule	Uruguay	1979	only	-	Oct	 1	 0:00	1:00	S
+Rule	Uruguay	1980	only	-	May	 1	 0:00	0	-
+Rule	Uruguay	1987	only	-	Dec	14	 0:00	1:00	S
+Rule	Uruguay	1988	only	-	Mar	14	 0:00	0	-
+Rule	Uruguay	1988	only	-	Dec	11	 0:00	1:00	S
+Rule	Uruguay	1989	only	-	Mar	12	 0:00	0	-
+Rule	Uruguay	1989	only	-	Oct	29	 0:00	1:00	S
+# Shanks & Pottenger say no DST was observed in 1990/1 and 1991/2,
+# and that 1992/3's DST was from 10-25 to 03-01.  Go with IATA.
+Rule	Uruguay	1990	1992	-	Mar	Sun>=1	 0:00	0	-
+Rule	Uruguay	1990	1991	-	Oct	Sun>=21	 0:00	1:00	S
+Rule	Uruguay	1992	only	-	Oct	18	 0:00	1:00	S
+Rule	Uruguay	1993	only	-	Feb	28	 0:00	0	-
+# From Eduardo Cota (2004-09-20):
+# The uruguayan government has decreed a change in the local time....
+# http://www.presidencia.gub.uy/decretos/2004091502.htm
+Rule	Uruguay	2004	only	-	Sep	19	 0:00	1:00	S
+# From Steffen Thorsen (2005-03-11):
+# Uruguay's DST was scheduled to end on Sunday, 2005-03-13, but in order to
+# save energy ... it was postponed two weeks....
+# http://www.presidencia.gub.uy/_Web/noticias/2005/03/2005031005.htm
+Rule	Uruguay	2005	only	-	Mar	27	 2:00	0	-
+# From Eduardo Cota (2005-09-27):
+# http://www.presidencia.gub.uy/_Web/decretos/2005/09/CM%20119_09%2009%202005_00001.PDF
+# This means that from 2005-10-09 at 02:00 local time, until 2006-03-12 at
+# 02:00 local time, official time in Uruguay will be at GMT -2.
+Rule	Uruguay	2005	only	-	Oct	 9	 2:00	1:00	S
+Rule	Uruguay	2006	only	-	Mar	12	 2:00	0	-
+# From Jesper Norgaard Welen (2006-09-06):
+# http://www.presidencia.gub.uy/_web/decretos/2006/09/CM%20210_08%2006%202006_00001.PDF
+Rule	Uruguay	2006	max	-	Oct	Sun>=1	 2:00	1:00	S
+Rule	Uruguay	2007	max	-	Mar	Sun>=8	 2:00	0	-
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone America/Montevideo	-3:44:44 -	LMT	1898 Jun 28
+			-3:44:44 -	MMT	1920 May  1	# Montevideo MT
+			-3:30	Uruguay	UY%sT	1942 Dec 14	# Uruguay Time
+			-3:00	Uruguay	UY%sT
+
+# Venezuela
+#
+# From John Stainforth (2007-11-28):
+# ... the change for Venezuela originally expected for 2007-12-31 has
+# been brought forward to 2007-12-09.  The official announcement was
+# published today in the "Gaceta Oficial de la Republica Bolivariana
+# de Venezuela, numero 38.819" (official document for all laws or
+# resolution publication)
+# http://www.globovision.com/news.php?nid=72208
+
+# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
+Zone	America/Caracas	-4:27:44 -	LMT	1890
+			-4:27:40 -	CMT	1912 Feb 12 # Caracas Mean Time?
+			-4:30	-	VET	1965	     # Venezuela Time
+			-4:00	-	VET	2007 Dec  9 03:00
+			-4:30	-	VET
diff --git a/extra/zoneinfo/systemv b/extra/zoneinfo/systemv
new file mode 100644
index 0000000000..6cf9645de0
--- /dev/null
+++ b/extra/zoneinfo/systemv
@@ -0,0 +1,36 @@
+# @(#)systemv	8.1
+
+# Old rules, should the need arise.
+# No attempt is made to handle Newfoundland, since it cannot be expressed
+# using the System V "TZ" scheme (half-hour offset), or anything outside
+# North America (no support for non-standard DST start/end dates), nor
+# the changes in the DST rules in the US after 1976 (which occurred after
+# the old rules were written).
+#
+# If you need the old rules, uncomment ## lines.
+# Compile this *without* leap second correction for true conformance.
+
+# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
+Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
+Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
+Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
+Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
+Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
+Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
+Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
+
+# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
+## Zone	SystemV/AST4ADT	-4:00	SystemV		A%sT
+## Zone	SystemV/EST5EDT	-5:00	SystemV		E%sT
+## Zone	SystemV/CST6CDT	-6:00	SystemV		C%sT
+## Zone	SystemV/MST7MDT	-7:00	SystemV		M%sT
+## Zone	SystemV/PST8PDT	-8:00	SystemV		P%sT
+## Zone	SystemV/YST9YDT	-9:00	SystemV		Y%sT
+## Zone	SystemV/AST4	-4:00	-		AST
+## Zone	SystemV/EST5	-5:00	-		EST
+## Zone	SystemV/CST6	-6:00	-		CST
+## Zone	SystemV/MST7	-7:00	-		MST
+## Zone	SystemV/PST8	-8:00	-		PST
+## Zone	SystemV/YST9	-9:00	-		YST
+## Zone	SystemV/HST10	-10:00	-		HST
diff --git a/extra/zoneinfo/zoneinfo.factor b/extra/zoneinfo/zoneinfo.factor
new file mode 100644
index 0000000000..e298046dd3
--- /dev/null
+++ b/extra/zoneinfo/zoneinfo.factor
@@ -0,0 +1,157 @@
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: combinators combinators.smart io.encodings.utf8 io.files
+kernel namespaces sequences splitting unicode.case accessors
+math.parser calendar ;
+IN: zoneinfo
+
+CONSTANT: zoneinfo-paths
+{
+    "vocab:zoneinfo/africa"
+    "vocab:zoneinfo/antarctica"
+    "vocab:zoneinfo/asia"
+    "vocab:zoneinfo/australasia"
+    "vocab:zoneinfo/europe"
+    "vocab:zoneinfo/northamerica"
+    "vocab:zoneinfo/pacificnew"
+    "vocab:zoneinfo/solar87"
+    "vocab:zoneinfo/solar88"
+    "vocab:zoneinfo/solar89"
+    "vocab:zoneinfo/southamerica"
+    "vocab:zoneinfo/systemv"
+    "vocab:zoneinfo/leapseconds"
+}
+
+SYMBOL: last-zone
+
+TUPLE: raw-zone name gmt-offset rules/save format until ;
+TUPLE: raw-rule name from to type in on at save letters ;
+TUPLE: raw-link from to ;
+TUPLE: raw-leap year month day hms corr r/s ;
+
+TUPLE: zone name ;
+TUPLE: rule name from to at ;
+TUPLE: link ;
+TUPLE: leap ;
+
+: rule-to ( m string -- m n )
+    {
+        { "only" [ dup ] }
+        { "max" [ 1/0. ] }
+        [ string>number ]
+    } case ;
+
+: raw-rule>rule ( raw-rule -- rule )
+    ;
+
+: parse-rule ( seq -- rule )
+    [
+        {
+            [ drop ]
+            [ ]
+            [ ]
+            [ ]
+            [ ]
+            [ ]
+            [ ]
+            [ ]
+            [ ]
+            [ ]
+        } spread
+    ] inputzone ( raw-zone -- zone )
+    ;
+
+: parse-zone ( seq -- zone )
+    {
+        [ second ]
+        [ third ]
+        [ fourth ]
+        [ 4 swap nth ]
+        [ 5 tail harvest ]
+    } cleave raw-zone boa ;
+
+: parse-partial-zone ( seq -- zone )
+    [ last-zone get name>> ] dip
+    {
+        [ first ]
+        [ second ]
+        [ 2 swap nth ]
+        [ 3 tail harvest ]
+    } cleave raw-zone boa ;
+
+: raw-link>link ( raw-link -- link )
+    ;
+
+: parse-link ( seq -- link )
+    [
+        {
+            [ drop ]
+            [ ]
+            [ ]
+        } spread
+    ] inputleap ( raw-leap -- leap )
+    ;
+
+: parse-leap ( seq -- link )
+    [
+        {
+            [ drop ]
+            [ ]
+            [ ]
+            [ ]
+            [ ]
+            [ ]
+            [ ]
+        } spread
+    ] inputlower
+    {
+        { "zone" [ parse-zone dup last-zone set raw-zone>zone ] }
+        { "rule" [ parse-rule raw-rule>rule ] }
+        { "link" [ parse-link raw-link>link ] }
+        { "leap" [ parse-leap raw-leap>leap ] }
+        [ drop harvest parse-partial-zone ]
+    } case ;
+
+: parse-zoneinfo-file ( path -- seq )
+    utf8 file-lines
+    [ "#" split1 drop ] map harvest
+    [ "\t " split harvest ] map harvest
+    [ [ parse-line ] map ] with-scope ;
+
+: load-zoneinfo-files ( -- seq )
+    zoneinfo-paths [ parse-zoneinfo-file ] map ;
+
+
+
+! Rule
+! name - string
+! from - year or "min"
+! name    "France"
+! from    "1938"  or "min"
+! to      "1945" or "max" or "only"
+! type    "-"  always "-"
+! in      "Mar"  -- 3-letter month name
+! on      "26"  or "Mon>=15"  or lastSun lastFri
+! at      "23:00s"  "12:13:00s" "1:00s" "1:00u"
+! save    "-0:00:05" "1:00" "0:14:15"
+! letters "S" or "-" or "AMT" "BDST"
+
+! Zone
+! name       "Indian/Maldives"
+! gmt-offset "4:54:00" "9:55:56" "-9:55:56"
+! rules/save "-" "0:20" "0:30" "1:00" "AN" "W-Eur" "Winn" "Zion" "sol87" "sol88"
+! format     "LMT" "%s" "%sT" "A%sT" "AC%sT" "ACT"
+! until      { "1880" }
+    ! { "1847" "Dec" "1" "0:00s" }
+    ! { "1883" "Nov" "18" "12:12:57" }
+    ! { "1989" "Sep" "lastSun" "2:00s" }
+
+! Link
+! T{ link { from "Asia/Riyadh88" } { to "Mideast/Riyadh88" } }
diff --git a/unmaintained/4DNav/4DNav-docs.factor b/unmaintained/4DNav/4DNav-docs.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/4DNav.factor b/unmaintained/4DNav/4DNav.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/camera/camera-docs.factor b/unmaintained/4DNav/camera/camera-docs.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/camera/camera.factor b/unmaintained/4DNav/camera/camera.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/deep/deep-docs.factor b/unmaintained/4DNav/deep/deep-docs.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/deep/deep.factor b/unmaintained/4DNav/deep/deep.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/deploy.factor b/unmaintained/4DNav/deploy.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/file-chooser/file-chooser.factor b/unmaintained/4DNav/file-chooser/file-chooser.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/space-file-decoder/space-file-decoder-docs.factor b/unmaintained/4DNav/space-file-decoder/space-file-decoder-docs.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/space-file-decoder/space-file-decoder.factor b/unmaintained/4DNav/space-file-decoder/space-file-decoder.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/turtle/turtle-docs.factor b/unmaintained/4DNav/turtle/turtle-docs.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/turtle/turtle.factor b/unmaintained/4DNav/turtle/turtle.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/window3D/window3D-docs.factor b/unmaintained/4DNav/window3D/window3D-docs.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/4DNav/window3D/window3D.factor b/unmaintained/4DNav/window3D/window3D.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/adsoda/adsoda-docs.factor b/unmaintained/adsoda/adsoda-docs.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/adsoda/adsoda-tests.factor b/unmaintained/adsoda/adsoda-tests.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/adsoda/adsoda.factor b/unmaintained/adsoda/adsoda.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/adsoda/combinators/combinators-docs.factor b/unmaintained/adsoda/combinators/combinators-docs.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/adsoda/combinators/combinators-tests.factor b/unmaintained/adsoda/combinators/combinators-tests.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/adsoda/combinators/combinators.factor b/unmaintained/adsoda/combinators/combinators.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/adsoda/solution2/solution2.factor b/unmaintained/adsoda/solution2/solution2.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/adsoda/tools/tools-docs.factor b/unmaintained/adsoda/tools/tools-docs.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/adsoda/tools/tools-tests.factor b/unmaintained/adsoda/tools/tools-tests.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/adsoda/tools/tools.factor b/unmaintained/adsoda/tools/tools.factor
old mode 100755
new mode 100644
diff --git a/extra/animations/animations-docs.factor b/unmaintained/animations/animations-docs.factor
similarity index 100%
rename from extra/animations/animations-docs.factor
rename to unmaintained/animations/animations-docs.factor
diff --git a/extra/animations/animations.factor b/unmaintained/animations/animations.factor
similarity index 100%
rename from extra/animations/animations.factor
rename to unmaintained/animations/animations.factor
diff --git a/extra/animations/authors.txt b/unmaintained/animations/authors.txt
similarity index 100%
rename from extra/animations/authors.txt
rename to unmaintained/animations/authors.txt
diff --git a/unmaintained/arm/4/4.factor b/unmaintained/arm/4/4.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/arm/allot/allot.factor b/unmaintained/arm/allot/allot.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/arm/architecture/architecture.factor b/unmaintained/arm/architecture/architecture.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/arm/arm.factor b/unmaintained/arm/arm.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/arm/bootstrap.factor b/unmaintained/arm/bootstrap.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/arm/intrinsics/intrinsics.factor b/unmaintained/arm/intrinsics/intrinsics.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/automata/ui/deploy.factor b/unmaintained/automata/ui/deploy.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/ce/backend/backend.factor b/unmaintained/ce/backend/backend.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/ce/ce.factor b/unmaintained/ce/ce.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/ce/files/files.factor b/unmaintained/ce/files/files.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/ce/privileges/privileges.factor b/unmaintained/ce/privileges/privileges.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/ce/sockets/sockets.factor b/unmaintained/ce/sockets/sockets.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/cont-responder/callbacks-tests.factor b/unmaintained/cont-responder/callbacks-tests.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/cont-responder/callbacks.factor b/unmaintained/cont-responder/callbacks.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/cryptlib/streams/streams.factor b/unmaintained/cryptlib/streams/streams.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/db/mysql/mysql.factor b/unmaintained/db/mysql/mysql.factor
old mode 100755
new mode 100644
diff --git a/extra/drills/deployed/deploy.factor b/unmaintained/drills/deployed/deploy.factor
similarity index 100%
rename from extra/drills/deployed/deploy.factor
rename to unmaintained/drills/deployed/deploy.factor
diff --git a/extra/drills/deployed/deployed.factor b/unmaintained/drills/deployed/deployed.factor
similarity index 100%
rename from extra/drills/deployed/deployed.factor
rename to unmaintained/drills/deployed/deployed.factor
diff --git a/unmaintained/drills/deployed/tags.txt b/unmaintained/drills/deployed/tags.txt
new file mode 100644
index 0000000000..6bf68304bb
--- /dev/null
+++ b/unmaintained/drills/deployed/tags.txt
@@ -0,0 +1 @@
+unportable
diff --git a/extra/drills/drills.factor b/unmaintained/drills/drills.factor
similarity index 100%
rename from extra/drills/drills.factor
rename to unmaintained/drills/drills.factor
diff --git a/unmaintained/drills/tags.txt b/unmaintained/drills/tags.txt
new file mode 100644
index 0000000000..6bf68304bb
--- /dev/null
+++ b/unmaintained/drills/tags.txt
@@ -0,0 +1 @@
+unportable
diff --git a/unmaintained/golden-section/deploy.factor b/unmaintained/golden-section/deploy.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/headers/bsd/bsd.factor b/unmaintained/headers/bsd/bsd.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/headers/headers.factor b/unmaintained/headers/headers.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/images/processing/rotation/rotation-tests.factor b/unmaintained/images/processing/rotation/rotation-tests.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/irc-ui/commandparser/commandparser.factor b/unmaintained/irc-ui/commandparser/commandparser.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/irc-ui/commands/commands.factor b/unmaintained/irc-ui/commands/commands.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/irc-ui/load/load.factor b/unmaintained/irc-ui/load/load.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/irc-ui/ui.factor b/unmaintained/irc-ui/ui.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/ldap/ldap-tests.factor b/unmaintained/ldap/ldap-tests.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/ldap/libldap/libldap.factor b/unmaintained/ldap/libldap/libldap.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/lint/lint.factor b/unmaintained/lint/lint.factor
old mode 100755
new mode 100644
diff --git a/extra/models/combinators/authors.txt b/unmaintained/models/combinators/authors.txt
similarity index 100%
rename from extra/models/combinators/authors.txt
rename to unmaintained/models/combinators/authors.txt
diff --git a/extra/models/combinators/combinators-docs.factor b/unmaintained/models/combinators/combinators-docs.factor
similarity index 100%
rename from extra/models/combinators/combinators-docs.factor
rename to unmaintained/models/combinators/combinators-docs.factor
diff --git a/extra/models/combinators/combinators.factor b/unmaintained/models/combinators/combinators.factor
similarity index 98%
rename from extra/models/combinators/combinators.factor
rename to unmaintained/models/combinators/combinators.factor
index c7b864d404..4896910618 100644
--- a/extra/models/combinators/combinators.factor
+++ b/unmaintained/models/combinators/combinators.factor
@@ -1,5 +1,5 @@
 USING: accessors arrays kernel models models.product monads
-sequences sequences.extras ;
+sequences sequences.extras shuffle ;
 FROM: syntax => >> ;
 IN: models.combinators
 
@@ -102,4 +102,4 @@ M: (when-model) (model-changed) [ quot>> ] 2keep
 : with-self ( quot: ( model -- model ) -- model ) [ f  dup ] dip call swap [ add-dependency ] keep ; inline
 
 USE: models.combinators.templates
-<< { "$>" "<$" "fmap" } [ fmaps ] each >>
\ No newline at end of file
+<< { "$>" "<$" "fmap" } [ fmaps ] each >>
diff --git a/extra/models/combinators/summary.txt b/unmaintained/models/combinators/summary.txt
similarity index 100%
rename from extra/models/combinators/summary.txt
rename to unmaintained/models/combinators/summary.txt
diff --git a/extra/models/combinators/templates/templates.factor b/unmaintained/models/combinators/templates/templates.factor
similarity index 100%
rename from extra/models/combinators/templates/templates.factor
rename to unmaintained/models/combinators/templates/templates.factor
diff --git a/unmaintained/ogg/player/player.factor b/unmaintained/ogg/player/player.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/oracle/oracle-tests.factor b/unmaintained/oracle/oracle-tests.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/pdf/pdf-tests.factor b/unmaintained/pdf/pdf-tests.factor
old mode 100755
new mode 100644
diff --git a/extra/recipes/authors.txt b/unmaintained/recipes/authors.txt
similarity index 100%
rename from extra/recipes/authors.txt
rename to unmaintained/recipes/authors.txt
diff --git a/extra/recipes/icons/back.tiff b/unmaintained/recipes/icons/back.tiff
similarity index 100%
rename from extra/recipes/icons/back.tiff
rename to unmaintained/recipes/icons/back.tiff
diff --git a/extra/recipes/icons/hate.tiff b/unmaintained/recipes/icons/hate.tiff
similarity index 100%
rename from extra/recipes/icons/hate.tiff
rename to unmaintained/recipes/icons/hate.tiff
diff --git a/extra/recipes/icons/love.tiff b/unmaintained/recipes/icons/love.tiff
similarity index 100%
rename from extra/recipes/icons/love.tiff
rename to unmaintained/recipes/icons/love.tiff
diff --git a/extra/recipes/icons/more.tiff b/unmaintained/recipes/icons/more.tiff
similarity index 100%
rename from extra/recipes/icons/more.tiff
rename to unmaintained/recipes/icons/more.tiff
diff --git a/extra/recipes/icons/submit.tiff b/unmaintained/recipes/icons/submit.tiff
similarity index 100%
rename from extra/recipes/icons/submit.tiff
rename to unmaintained/recipes/icons/submit.tiff
diff --git a/extra/recipes/recipes.factor b/unmaintained/recipes/recipes.factor
similarity index 100%
rename from extra/recipes/recipes.factor
rename to unmaintained/recipes/recipes.factor
diff --git a/extra/recipes/summary.txt b/unmaintained/recipes/summary.txt
similarity index 100%
rename from extra/recipes/summary.txt
rename to unmaintained/recipes/summary.txt
diff --git a/unmaintained/semantic-db/semantic-db.factor b/unmaintained/semantic-db/semantic-db.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/sniffer/channels/bsd/bsd.factor b/unmaintained/sniffer/channels/bsd/bsd.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/sniffer/channels/sniffer.factor b/unmaintained/sniffer/channels/sniffer.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/sniffer/io/filter/filter.factor b/unmaintained/sniffer/io/filter/filter.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/sniffer/io/sniffer.factor b/unmaintained/sniffer/io/sniffer.factor
old mode 100755
new mode 100644
diff --git a/unmaintained/springies/springies.factor b/unmaintained/springies/springies.factor
old mode 100755
new mode 100644
diff --git a/extra/sudokus/authors.txt b/unmaintained/sudokus/authors.txt
similarity index 100%
rename from extra/sudokus/authors.txt
rename to unmaintained/sudokus/authors.txt
diff --git a/extra/sudokus/sudokus.factor b/unmaintained/sudokus/sudokus.factor
similarity index 96%
rename from extra/sudokus/sudokus.factor
rename to unmaintained/sudokus/sudokus.factor
index ff20f15204..c7bc6944fb 100644
--- a/extra/sudokus/sudokus.factor
+++ b/unmaintained/sudokus/sudokus.factor
@@ -21,7 +21,7 @@ IN: sudokus
 : solution ( puzzle random? -- solution ) dupd solutions dup +nil+ = [ drop "Unsolvable" alert* ] [ nip car ] if ;
 : hint ( puzzle -- puzzle' ) [ [ f swap indices random dup ] [ f solution ] bi nth ] keep swapd >vector [ set-nth ] keep ;
 : create ( difficulty -- puzzle ) 81 [ f ] replicate
-    40 random solution [ [ dup length random f spin set-nth ] curry times ] keep ;
+    40 random solution [ [ f swap [ length random ] keep set-nth ] curry times ] keep ;
 
 : do-sudoku ( -- ) [ [
         [
diff --git a/extra/sudokus/summary.txt b/unmaintained/sudokus/summary.txt
similarity index 100%
rename from extra/sudokus/summary.txt
rename to unmaintained/sudokus/summary.txt
diff --git a/unmaintained/tabs/tabs.factor b/unmaintained/tabs/tabs.factor
old mode 100755
new mode 100644
diff --git a/extra/ui/gadgets/alerts/alerts.factor b/unmaintained/ui/gadgets/alerts/alerts.factor
similarity index 100%
rename from extra/ui/gadgets/alerts/alerts.factor
rename to unmaintained/ui/gadgets/alerts/alerts.factor
diff --git a/extra/ui/gadgets/alerts/authors.txt b/unmaintained/ui/gadgets/alerts/authors.txt
similarity index 100%
rename from extra/ui/gadgets/alerts/authors.txt
rename to unmaintained/ui/gadgets/alerts/authors.txt
diff --git a/extra/ui/gadgets/alerts/summary.txt b/unmaintained/ui/gadgets/alerts/summary.txt
similarity index 100%
rename from extra/ui/gadgets/alerts/summary.txt
rename to unmaintained/ui/gadgets/alerts/summary.txt
diff --git a/extra/ui/gadgets/comboboxes/authors.txt b/unmaintained/ui/gadgets/comboboxes/authors.txt
similarity index 100%
rename from extra/ui/gadgets/comboboxes/authors.txt
rename to unmaintained/ui/gadgets/comboboxes/authors.txt
diff --git a/extra/ui/gadgets/comboboxes/comboboxes.factor b/unmaintained/ui/gadgets/comboboxes/comboboxes.factor
similarity index 100%
rename from extra/ui/gadgets/comboboxes/comboboxes.factor
rename to unmaintained/ui/gadgets/comboboxes/comboboxes.factor
diff --git a/extra/ui/gadgets/comboboxes/summary.txt b/unmaintained/ui/gadgets/comboboxes/summary.txt
similarity index 100%
rename from extra/ui/gadgets/comboboxes/summary.txt
rename to unmaintained/ui/gadgets/comboboxes/summary.txt
diff --git a/extra/ui/gadgets/controls/authors.txt b/unmaintained/ui/gadgets/controls/authors.txt
similarity index 100%
rename from extra/ui/gadgets/controls/authors.txt
rename to unmaintained/ui/gadgets/controls/authors.txt
diff --git a/extra/ui/gadgets/controls/controls-docs.factor b/unmaintained/ui/gadgets/controls/controls-docs.factor
similarity index 100%
rename from extra/ui/gadgets/controls/controls-docs.factor
rename to unmaintained/ui/gadgets/controls/controls-docs.factor
diff --git a/extra/ui/gadgets/controls/controls.factor b/unmaintained/ui/gadgets/controls/controls.factor
similarity index 100%
rename from extra/ui/gadgets/controls/controls.factor
rename to unmaintained/ui/gadgets/controls/controls.factor
diff --git a/extra/ui/gadgets/controls/summary.txt b/unmaintained/ui/gadgets/controls/summary.txt
similarity index 100%
rename from extra/ui/gadgets/controls/summary.txt
rename to unmaintained/ui/gadgets/controls/summary.txt
diff --git a/extra/ui/gadgets/layout/authors.txt b/unmaintained/ui/gadgets/layout/authors.txt
similarity index 100%
rename from extra/ui/gadgets/layout/authors.txt
rename to unmaintained/ui/gadgets/layout/authors.txt
diff --git a/extra/ui/gadgets/layout/layout-docs.factor b/unmaintained/ui/gadgets/layout/layout-docs.factor
similarity index 100%
rename from extra/ui/gadgets/layout/layout-docs.factor
rename to unmaintained/ui/gadgets/layout/layout-docs.factor
diff --git a/extra/ui/gadgets/layout/layout.factor b/unmaintained/ui/gadgets/layout/layout.factor
similarity index 95%
rename from extra/ui/gadgets/layout/layout.factor
rename to unmaintained/ui/gadgets/layout/layout.factor
index 7bdde95d60..c287b9a059 100644
--- a/extra/ui/gadgets/layout/layout.factor
+++ b/unmaintained/ui/gadgets/layout/layout.factor
@@ -23,8 +23,9 @@ TUPLE: placeholder < gadget members ;
 ! Just take the previous mentioned placeholder and use it
 ! If there is no previously mentioned placeholder, we're probably making a box, and will create the placeholder ourselves
 DEFER: with-interface
-: insertion-quot ( quot -- quot' ) make:building get [ [ placeholder? ] find-last nip [  dup , ] unless*
-    templates get spin '[ [ _ templates set _ , @ ] with-interface ] ] when* ;
+: insertion-quot ( quot -- quot' )
+    make:building get [ [ placeholder? ] find-last nip [  dup , ] unless*
+    [ templates get ] 2dip swap '[ [ _ templates set _ , @ ] with-interface ] ] when* ;
 
 SYNTAX: ,% scan string>number [  , ] curry append! ;
 SYNTAX: ->% scan string>number '[ [ _  , ] [ output-model ] bi ] append! ;
diff --git a/extra/ui/gadgets/layout/summary.txt b/unmaintained/ui/gadgets/layout/summary.txt
similarity index 100%
rename from extra/ui/gadgets/layout/summary.txt
rename to unmaintained/ui/gadgets/layout/summary.txt
diff --git a/extra/ui/gadgets/poppers/authors.txt b/unmaintained/ui/gadgets/poppers/authors.txt
similarity index 100%
rename from extra/ui/gadgets/poppers/authors.txt
rename to unmaintained/ui/gadgets/poppers/authors.txt
diff --git a/extra/ui/gadgets/poppers/poppers.factor b/unmaintained/ui/gadgets/poppers/poppers.factor
similarity index 100%
rename from extra/ui/gadgets/poppers/poppers.factor
rename to unmaintained/ui/gadgets/poppers/poppers.factor
diff --git a/unmaintained/ui/offscreen/offscreen.factor b/unmaintained/ui/offscreen/offscreen.factor
old mode 100755
new mode 100644
diff --git a/vm/Config.arm b/vm/Config.arm
index 1d7e6f9cc6..8b13789179 100644
--- a/vm/Config.arm
+++ b/vm/Config.arm
@@ -1 +1 @@
-PLAF_DLL_OBJS += vmpp/cpu-arm.o
+
diff --git a/vm/Config.freebsd b/vm/Config.freebsd
index 384b2fd57a..a0dbe228e5 100644
--- a/vm/Config.freebsd
+++ b/vm/Config.freebsd
@@ -1,4 +1,4 @@
 include vm/Config.unix
 PLAF_DLL_OBJS += vm/os-genunix.o vm/os-freebsd.o
 CFLAGS += -export-dynamic
-LIBS = -L/usr/local/lib/ -lm $(X11_UI_LIBS)
+LIBS = -L/usr/local/lib/ -lm -lrt $(X11_UI_LIBS)
diff --git a/vm/Config.linux b/vm/Config.linux
index eb3a19d75a..4a859b1216 100644
--- a/vm/Config.linux
+++ b/vm/Config.linux
@@ -1,4 +1,4 @@
 include vm/Config.unix
 PLAF_DLL_OBJS += vm/os-genunix.o vm/os-linux.o
 CFLAGS += -export-dynamic
-LIBS = -ldl -lm -lpthread $(X11_UI_LIBS)
+LIBS = -ldl -lm -lrt -lpthread $(X11_UI_LIBS)
diff --git a/vm/Config.netbsd b/vm/Config.netbsd
index ba5ecd19a5..72a4056c90 100644
--- a/vm/Config.netbsd
+++ b/vm/Config.netbsd
@@ -2,4 +2,4 @@ include vm/Config.unix
 PLAF_DLL_OBJS += vm/os-genunix.o vm/os-netbsd.o
 CFLAGS += -export-dynamic
 LIBPATH = -L/usr/X11R7/lib -Wl,-rpath,/usr/X11R7/lib -L/usr/pkg/lib -Wl,-rpath,/usr/pkg/lib
-LIBS = -lm -lssl -lcrypto $(X11_UI_LIBS)
+LIBS = -lm -lrt -lssl -lcrypto $(X11_UI_LIBS)
diff --git a/vm/Config.openbsd b/vm/Config.openbsd
index a172cbfaba..c7d2672e6b 100644
--- a/vm/Config.openbsd
+++ b/vm/Config.openbsd
@@ -2,5 +2,5 @@ include vm/Config.unix
 PLAF_DLL_OBJS += vm/os-genunix.o vm/os-openbsd.o
 CC = egcc
 CPP = eg++
-CFLAGS += -export-dynamic
+CFLAGS += -export-dynamic -fno-inline-functions
 LIBS = -L/usr/local/lib/ -lm $(X11_UI_LIBS) -lz -lssl -lcrypto -lpthread
diff --git a/vm/Config.solaris b/vm/Config.solaris
index 98b7de16d8..a2d7b1f271 100644
--- a/vm/Config.solaris
+++ b/vm/Config.solaris
@@ -1,6 +1,6 @@
 include vm/Config.unix
 PLAF_DLL_OBJS += vm/os-genunix.o vm/os-solaris.o
 CFLAGS += -D_STDC_C99 -Drestrict="" -export-dynamic
-LIBS += -ldl -lsocket -lnsl -lm -R/opt/PM/lib -R/opt/csw/lib \
+LIBS += -ldl -lsocket -lnsl -lm -lrt -R/opt/PM/lib -R/opt/csw/lib \
 	-R/usr/local/lib -R/usr/sfw/lib -R/usr/X11R6/lib \
 	-R/opt/sfw/lib $(X11_UI_LIBS)
diff --git a/vm/Config.windows b/vm/Config.windows
index b0b1352cb2..11df403541 100644
--- a/vm/Config.windows
+++ b/vm/Config.windows
@@ -1,4 +1,4 @@
-CFLAGS += -DWINDOWS -mno-cygwin
+CFLAGS += -mno-cygwin
 LIBS = -lm
 PLAF_DLL_OBJS += vm/os-windows.o
 SHARED_FLAG = -shared
diff --git a/vm/Config.x86.32 b/vm/Config.x86.32
index e060ef7019..8b13789179 100644
--- a/vm/Config.x86.32
+++ b/vm/Config.x86.32
@@ -1,5 +1 @@
-BOOT_ARCH = x86
-PLAF_DLL_OBJS += vm/cpu-x86.32.o
 
-# gcc bug workaround
-CFLAGS += -fno-builtin-strlen -fno-builtin-strcat
diff --git a/vm/Config.x86.64 b/vm/Config.x86.64
index 63f06d5a78..8b13789179 100644
--- a/vm/Config.x86.64
+++ b/vm/Config.x86.64
@@ -1,2 +1 @@
-PLAF_DLL_OBJS += vm/cpu-x86.64.o
-CFLAGS += -DFACTOR_64
+
diff --git a/vm/aging_collector.cpp b/vm/aging_collector.cpp
index 3572677aa6..c832ca792f 100644
--- a/vm/aging_collector.cpp
+++ b/vm/aging_collector.cpp
@@ -22,7 +22,7 @@ void factor_vm::collect_aging()
 
 		to_tenured_collector collector(this);
 
-		current_gc->event->started_code_scan();
+		current_gc->event->started_card_scan();
 		collector.trace_cards(data->tenured,
 			card_points_to_aging,
 			full_unmarker());
@@ -33,10 +33,6 @@ void factor_vm::collect_aging()
 		current_gc->event->ended_code_scan(collector.code_blocks_scanned);
 
 		collector.tenure_reachable_objects();
-
-		current_gc->event->started_code_sweep();
-		update_code_heap_for_minor_gc(&code->points_to_aging);
-		current_gc->event->ended_code_sweep();
 	}
 	{
 		/* If collection fails here, do a to_tenured collection. */
@@ -53,8 +49,7 @@ void factor_vm::collect_aging()
 		collector.cheneys_algorithm();
 
 		data->reset_generation(&nursery);
-		code->points_to_nursery.clear();
-		code->points_to_aging.clear();
+		code->clear_remembered_set();
 	}
 }
 
diff --git a/vm/aging_space.hpp b/vm/aging_space.hpp
index 7a28f54ebf..ccb2d1a1a2 100644
--- a/vm/aging_space.hpp
+++ b/vm/aging_space.hpp
@@ -15,15 +15,6 @@ struct aging_space : bump_allocator {
 		starts.record_object_start_offset(obj);
 		return obj;
 	}
-
-	cell next_object_after(cell scan)
-	{
-		cell size = ((object *)scan)->size();
-		if(scan + size < here)
-			return scan + size;
-		else
-			return 0;
-	}
 };
 
 }
diff --git a/vm/alien.cpp b/vm/alien.cpp
index d07b6e353b..38078b6679 100755
--- a/vm/alien.cpp
+++ b/vm/alien.cpp
@@ -27,9 +27,17 @@ char *factor_vm::pinned_alien_offset(cell obj)
 	}
 }
 
+VM_C_API char *pinned_alien_offset(cell obj, factor_vm *parent)
+{
+	return parent->pinned_alien_offset(obj);
+}
+
 /* make an alien */
 cell factor_vm::allot_alien(cell delegate_, cell displacement)
 {
+	if(delegate_ == false_object && displacement == 0)
+		return false_object;
+
 	data_root delegate(delegate_,this);
 	data_root new_alien(allot(sizeof(alien)),this);
 
@@ -49,27 +57,32 @@ cell factor_vm::allot_alien(cell delegate_, cell displacement)
 	return new_alien.value();
 }
 
+cell factor_vm::allot_alien(void *address)
+{
+	return allot_alien(false_object,(cell)address);
+}
+
+VM_C_API cell allot_alien(void *address, factor_vm *vm)
+{
+	return vm->allot_alien(address);
+}
+
 /* make an alien pointing at an offset of another alien */
 void factor_vm::primitive_displaced_alien()
 {
-	cell alien = dpop();
-	cell displacement = to_cell(dpop());
+	cell alien = ctx->pop();
+	cell displacement = to_cell(ctx->pop());
 
-	if(!to_boolean(alien) && displacement == 0)
-		dpush(false_object);
-	else
+	switch(tagged(alien).type())
 	{
-		switch(tagged(alien).type())
-		{
-		case BYTE_ARRAY_TYPE:
-		case ALIEN_TYPE:
-		case F_TYPE:
-			dpush(allot_alien(alien,displacement));
-			break;
-		default:
-			type_error(ALIEN_TYPE,alien);
-			break;
-		}
+	case BYTE_ARRAY_TYPE:
+	case ALIEN_TYPE:
+	case F_TYPE:
+		ctx->push(allot_alien(alien,displacement));
+		break;
+	default:
+		type_error(ALIEN_TYPE,alien);
+		break;
 	}
 }
 
@@ -77,59 +90,59 @@ void factor_vm::primitive_displaced_alien()
 if the object is a byte array, as a sanity check. */
 void factor_vm::primitive_alien_address()
 {
-	box_unsigned_cell((cell)pinned_alien_offset(dpop()));
+	ctx->push(allot_cell((cell)pinned_alien_offset(ctx->pop())));
 }
 
 /* pop ( alien n ) from datastack, return alien's address plus n */
 void *factor_vm::alien_pointer()
 {
-	fixnum offset = to_fixnum(dpop());
-	return unbox_alien() + offset;
+	fixnum offset = to_fixnum(ctx->pop());
+	return alien_offset(ctx->pop()) + offset;
 }
 
 /* define words to read/write values at an alien address */
-#define DEFINE_ALIEN_ACCESSOR(name,type,boxer,to) \
-	PRIMITIVE(alien_##name) \
+#define DEFINE_ALIEN_ACCESSOR(name,type,from,to) \
+	VM_C_API void primitive_alien_##name(factor_vm *parent) \
 	{ \
-		parent->boxer(*(type*)(parent->alien_pointer())); \
+		parent->ctx->push(from(*(type*)(parent->alien_pointer()),parent)); \
 	} \
-	PRIMITIVE(set_alien_##name) \
+	VM_C_API void primitive_set_alien_##name(factor_vm *parent) \
 	{ \
 		type *ptr = (type *)parent->alien_pointer(); \
-		type value = parent->to(dpop()); \
+		type value = (type)to(parent->ctx->pop(),parent); \
 		*ptr = value; \
 	}
 
-DEFINE_ALIEN_ACCESSOR(signed_cell,fixnum,box_signed_cell,to_fixnum)
-DEFINE_ALIEN_ACCESSOR(unsigned_cell,cell,box_unsigned_cell,to_cell)
-DEFINE_ALIEN_ACCESSOR(signed_8,s64,box_signed_8,to_signed_8)
-DEFINE_ALIEN_ACCESSOR(unsigned_8,u64,box_unsigned_8,to_unsigned_8)
-DEFINE_ALIEN_ACCESSOR(signed_4,s32,box_signed_4,to_fixnum)
-DEFINE_ALIEN_ACCESSOR(unsigned_4,u32,box_unsigned_4,to_cell)
-DEFINE_ALIEN_ACCESSOR(signed_2,s16,box_signed_2,to_fixnum)
-DEFINE_ALIEN_ACCESSOR(unsigned_2,u16,box_unsigned_2,to_cell)
-DEFINE_ALIEN_ACCESSOR(signed_1,s8,box_signed_1,to_fixnum)
-DEFINE_ALIEN_ACCESSOR(unsigned_1,u8,box_unsigned_1,to_cell)
-DEFINE_ALIEN_ACCESSOR(float,float,box_float,to_float)
-DEFINE_ALIEN_ACCESSOR(double,double,box_double,to_double)
-DEFINE_ALIEN_ACCESSOR(cell,void *,box_alien,pinned_alien_offset)
+DEFINE_ALIEN_ACCESSOR(signed_cell,fixnum,from_signed_cell,to_fixnum)
+DEFINE_ALIEN_ACCESSOR(unsigned_cell,cell,from_unsigned_cell,to_cell)
+DEFINE_ALIEN_ACCESSOR(signed_8,s64,from_signed_8,to_signed_8)
+DEFINE_ALIEN_ACCESSOR(unsigned_8,u64,from_unsigned_8,to_unsigned_8)
+DEFINE_ALIEN_ACCESSOR(signed_4,s32,from_signed_4,to_fixnum)
+DEFINE_ALIEN_ACCESSOR(unsigned_4,u32,from_unsigned_4,to_cell)
+DEFINE_ALIEN_ACCESSOR(signed_2,s16,from_signed_2,to_fixnum)
+DEFINE_ALIEN_ACCESSOR(unsigned_2,u16,from_unsigned_2,to_cell)
+DEFINE_ALIEN_ACCESSOR(signed_1,s8,from_signed_1,to_fixnum)
+DEFINE_ALIEN_ACCESSOR(unsigned_1,u8,from_unsigned_1,to_cell)
+DEFINE_ALIEN_ACCESSOR(float,float,from_float,to_float)
+DEFINE_ALIEN_ACCESSOR(double,double,from_double,to_double)
+DEFINE_ALIEN_ACCESSOR(cell,void *,allot_alien,pinned_alien_offset)
 
 /* open a native library and push a handle */
 void factor_vm::primitive_dlopen()
 {
-	data_root path(dpop(),this);
+	data_root path(ctx->pop(),this);
 	path.untag_check(this);
 	data_root library(allot(sizeof(dll)),this);
 	library->path = path.value();
 	ffi_dlopen(library.untagged());
-	dpush(library.value());
+	ctx->push(library.value());
 }
 
 /* look up a symbol in a native library */
 void factor_vm::primitive_dlsym()
 {
-	data_root library(dpop(),this);
-	data_root name(dpop(),this);
+	data_root library(ctx->pop(),this);
+	data_root name(ctx->pop(),this);
 	name.untag_check(this);
 
 	symbol_char *sym = name->data();
@@ -138,30 +151,30 @@ void factor_vm::primitive_dlsym()
 	{
 		dll *d = untag_check(library.value());
 
-		if(d->dll == NULL)
-			dpush(false_object);
+		if(d->handle == NULL)
+			ctx->push(false_object);
 		else
-			box_alien(ffi_dlsym(d,sym));
+			ctx->push(allot_alien(ffi_dlsym(d,sym)));
 	}
 	else
-		box_alien(ffi_dlsym(NULL,sym));
+		ctx->push(allot_alien(ffi_dlsym(NULL,sym)));
 }
 
 /* close a native library handle */
 void factor_vm::primitive_dlclose()
 {
-	dll *d = untag_check(dpop());
-	if(d->dll != NULL)
+	dll *d = untag_check(ctx->pop());
+	if(d->handle != NULL)
 		ffi_dlclose(d);
 }
 
 void factor_vm::primitive_dll_validp()
 {
-	cell library = dpop();
+	cell library = ctx->pop();
 	if(to_boolean(library))
-		dpush(tag_boolean(untag_check(library)->dll != NULL));
+		ctx->push(tag_boolean(untag_check(library)->handle != NULL));
 	else
-		dpush(true_object);
+		ctx->push(true_object);
 }
 
 /* gets the address of an object representing a C pointer */
@@ -186,32 +199,7 @@ VM_C_API char *alien_offset(cell obj, factor_vm *parent)
 	return parent->alien_offset(obj);
 }
 
-/* pop an object representing a C pointer */
-char *factor_vm::unbox_alien()
-{
-	return alien_offset(dpop());
-}
-
-VM_C_API char *unbox_alien(factor_vm *parent)
-{
-	return parent->unbox_alien();
-}
-
-/* make an alien and push */
-void factor_vm::box_alien(void *ptr)
-{
-	if(ptr == NULL)
-		dpush(false_object);
-	else
-		dpush(allot_alien(false_object,(cell)ptr));
-}
-
-VM_C_API void box_alien(void *ptr, factor_vm *parent)
-{
-	return parent->box_alien(ptr);
-}
-
-/* for FFI calls passing structs by value */
+/* For FFI calls passing structs by value. Cannot allocate */
 void factor_vm::to_value_struct(cell src, void *dest, cell size)
 {
 	memcpy(dest,alien_offset(src),size);
@@ -222,52 +210,47 @@ VM_C_API void to_value_struct(cell src, void *dest, cell size, factor_vm *parent
 	return parent->to_value_struct(src,dest,size);
 }
 
-/* for FFI callbacks receiving structs by value */
-void factor_vm::box_value_struct(void *src, cell size)
+/* For FFI callbacks receiving structs by value */
+cell factor_vm::from_value_struct(void *src, cell size)
 {
 	byte_array *bytes = allot_byte_array(size);
 	memcpy(bytes->data(),src,size);
-	dpush(tag(bytes));
+	return tag(bytes);
 }
 
-VM_C_API void box_value_struct(void *src, cell size,factor_vm *parent)
+VM_C_API cell from_value_struct(void *src, cell size, factor_vm *parent)
 {
-	return parent->box_value_struct(src,size);
+	return parent->from_value_struct(src,size);
 }
 
 /* On some x86 OSes, structs <= 8 bytes are returned in registers. */
-void factor_vm::box_small_struct(cell x, cell y, cell size)
+cell factor_vm::from_small_struct(cell x, cell y, cell size)
 {
 	cell data[2];
 	data[0] = x;
 	data[1] = y;
-	box_value_struct(data,size);
+	return from_value_struct(data,size);
 }
 
-VM_C_API void box_small_struct(cell x, cell y, cell size, factor_vm *parent)
+VM_C_API cell from_small_struct(cell x, cell y, cell size, factor_vm *parent)
 {
-	return parent->box_small_struct(x,y,size);
+	return parent->from_small_struct(x,y,size);
 }
 
 /* On OS X/PPC, complex numbers are returned in registers. */
-void factor_vm::box_medium_struct(cell x1, cell x2, cell x3, cell x4, cell size)
+cell factor_vm::from_medium_struct(cell x1, cell x2, cell x3, cell x4, cell size)
 {
 	cell data[4];
 	data[0] = x1;
 	data[1] = x2;
 	data[2] = x3;
 	data[3] = x4;
-	box_value_struct(data,size);
+	return from_value_struct(data,size);
 }
 
-VM_C_API void box_medium_struct(cell x1, cell x2, cell x3, cell x4, cell size, factor_vm *parent)
+VM_C_API cell from_medium_struct(cell x1, cell x2, cell x3, cell x4, cell size, factor_vm *parent)
 {
-	return parent->box_medium_struct(x1, x2, x3, x4, size);
-}
-
-void factor_vm::primitive_vm_ptr()
-{
-	box_alien(this);
+	return parent->from_medium_struct(x1, x2, x3, x4, size);
 }
 
 }
diff --git a/vm/alien.hpp b/vm/alien.hpp
index 129cc2560a..add6f4ba72 100755
--- a/vm/alien.hpp
+++ b/vm/alien.hpp
@@ -2,11 +2,11 @@ namespace factor
 {
 
 VM_C_API char *alien_offset(cell object, factor_vm *vm);
-VM_C_API char *unbox_alien(factor_vm *vm);
-VM_C_API void box_alien(void *ptr, factor_vm *vm);
+VM_C_API char *pinned_alien_offset(cell object, factor_vm *vm);
+VM_C_API cell allot_alien(void *address, factor_vm *vm);
 VM_C_API void to_value_struct(cell src, void *dest, cell size, factor_vm *vm);
-VM_C_API void box_value_struct(void *src, cell size,factor_vm *vm);
-VM_C_API void box_small_struct(cell x, cell y, cell size,factor_vm *vm);
-VM_C_API void box_medium_struct(cell x1, cell x2, cell x3, cell x4, cell size,factor_vm *vm);
+VM_C_API cell from_value_struct(void *src, cell size, factor_vm *vm);
+VM_C_API cell from_small_struct(cell x, cell y, cell size, factor_vm *vm);
+VM_C_API cell from_medium_struct(cell x1, cell x2, cell x3, cell x4, cell size, factor_vm *vm);
 
 }
diff --git a/vm/allot.hpp b/vm/allot.hpp
index 9a00bafd38..9a7c898efa 100644
--- a/vm/allot.hpp
+++ b/vm/allot.hpp
@@ -5,8 +5,12 @@ namespace factor
  * It is up to the caller to fill in the object's fields in a meaningful
  * fashion!
  */
-inline object *factor_vm::allot_object(header header, cell size)
+inline object *factor_vm::allot_object(cell type, cell size)
 {
+#ifdef FACTOR_DEBUG
+	assert(!current_gc);
+#endif
+
 	/* If the object is smaller than the nursery, allocate it in the nursery,
 	after a GC if needed */
 	if(nursery.size > size)
@@ -17,13 +21,13 @@ inline object *factor_vm::allot_object(header header, cell size)
 
 		object *obj = nursery.allot(size);
 
-		obj->h = header;
+		obj->initialize(type);
 		return obj;
 	}
 	/* If the object is bigger than the nursery, allocate it in
 	tenured space */
 	else
-		return allot_large_object(header,size);
+		return allot_large_object(type,size);
 }
 
 }
diff --git a/vm/arrays.cpp b/vm/arrays.cpp
index 3060ac70a3..cdfee274c7 100644
--- a/vm/arrays.cpp
+++ b/vm/arrays.cpp
@@ -3,21 +3,21 @@
 namespace factor
 {
 
-/* make a new array with an initial element */
 array *factor_vm::allot_array(cell capacity, cell fill_)
 {
 	data_root fill(fill_,this);
-	data_root new_array(allot_uninitialized_array(capacity),this);
+	array *new_array = allot_uninitialized_array(capacity);
 	memset_cell(new_array->data(),fill.value(),capacity * sizeof(cell));
-	return new_array.untagged();
+	return new_array;
 }
 
-/* push a new array on the stack */
 void factor_vm::primitive_array()
 {
-	cell initial = dpop();
-	cell size = unbox_array_size();
-	dpush(tag(allot_array(size,initial)));
+	data_root fill(ctx->pop(),this);
+	cell capacity = unbox_array_size();
+	array *new_array = allot_uninitialized_array(capacity);
+	memset_cell(new_array->data(),fill.value(),capacity * sizeof(cell));
+	ctx->push(tag(new_array));
 }
 
 cell factor_vm::allot_array_1(cell obj_)
@@ -54,9 +54,10 @@ cell factor_vm::allot_array_4(cell v1_, cell v2_, cell v3_, cell v4_)
 
 void factor_vm::primitive_resize_array()
 {
-	array *a = untag_check(dpop());
+	data_root a(ctx->pop(),this);
+	a.untag_check(this);
 	cell capacity = unbox_array_size();
-	dpush(tag(reallot_array(a,capacity)));
+	ctx->push(tag(reallot_array(a.untagged(),capacity)));
 }
 
 void growable_array::add(cell elt_)
diff --git a/vm/arrays.hpp b/vm/arrays.hpp
index 8eb2b530b0..5d6a0445fd 100755
--- a/vm/arrays.hpp
+++ b/vm/arrays.hpp
@@ -5,7 +5,7 @@ inline cell array_nth(array *array, cell slot)
 {
 #ifdef FACTOR_DEBUG
 	assert(slot < array_capacity(array));
-	assert(array->h.hi_tag() == ARRAY_TYPE);
+	assert(array->type() == ARRAY_TYPE);
 #endif
 	return array->data()[slot];
 }
@@ -14,7 +14,7 @@ inline void factor_vm::set_array_nth(array *array, cell slot, cell value)
 {
 #ifdef FACTOR_DEBUG
 	assert(slot < array_capacity(array));
-	assert(array->h.hi_tag() == ARRAY_TYPE);
+	assert(array->type() == ARRAY_TYPE);
 #endif
 	cell *slot_ptr = &array->data()[slot];
 	*slot_ptr = value;
diff --git a/vm/asm.h b/vm/asm.h
deleted file mode 100644
index 9719ae8af0..0000000000
--- a/vm/asm.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#if defined(__APPLE__) || (defined(WINDOWS) && !defined(__arm__))
-	#define MANGLE(sym) _##sym
-#else
-	#define MANGLE(sym) sym
-#endif
-
-/* Apple's PPC assembler is out of date? */
-#if defined(__APPLE__) && defined(__ppc__)
-	#define XX @
-#else
-	#define XX ;
-#endif
-
-/* The returns and args are just for documentation */
-#define DEF(returns,symbol,args) .globl MANGLE(symbol) XX \
-MANGLE(symbol)
diff --git a/vm/bignum.cpp b/vm/bignum.cpp
index 5a391e7625..c3d47d45f3 100755
--- a/vm/bignum.cpp
+++ b/vm/bignum.cpp
@@ -329,6 +329,7 @@ bignum *factor_vm::bignum_remainder(bignum * numerator, bignum * denominator)
 		}
 }
 
+/* allocates memory */
 #define FOO_TO_BIGNUM(name,type,utype)					\
 bignum * factor_vm::name##_to_bignum(type n)				\
 {									\
@@ -358,13 +359,13 @@ bignum * factor_vm::name##_to_bignum(type n)				\
 		return (result);					\
 	}								\
 }
-  
-/* all below allocate memory */
+
 FOO_TO_BIGNUM(cell,cell,cell)
 FOO_TO_BIGNUM(fixnum,fixnum,cell)
 FOO_TO_BIGNUM(long_long,s64,u64)
 FOO_TO_BIGNUM(ulong_long,u64,u64)
 
+/* cannot allocate memory */
 #define BIGNUM_TO_FOO(name,type,utype)					\
 	type factor_vm::bignum_to_##name(bignum * bignum)		\
 	{								\
@@ -380,7 +381,6 @@ FOO_TO_BIGNUM(ulong_long,u64,u64)
 		}							\
 	}
 
-/* all of the below allocate memory */
 BIGNUM_TO_FOO(cell,cell,cell);
 BIGNUM_TO_FOO(fixnum,fixnum,cell);
 BIGNUM_TO_FOO(long_long,s64,u64)
diff --git a/vm/bitwise_hacks.hpp b/vm/bitwise_hacks.hpp
old mode 100644
new mode 100755
index dc685bb28c..1927cd4736
--- a/vm/bitwise_hacks.hpp
+++ b/vm/bitwise_hacks.hpp
@@ -1,67 +1,62 @@
 namespace factor
 {
 
-/* These algorithms were snarfed from various places. I did not come up with them myself */
-
-inline cell popcount(u64 x)
+inline cell log2(cell x)
 {
-	u64 k1 = 0x5555555555555555ll;
-	u64 k2 = 0x3333333333333333ll;
-	u64 k4 = 0x0f0f0f0f0f0f0f0fll;
-	u64 kf = 0x0101010101010101ll;
-	x =  x       - ((x >> 1)  & k1); // put count of each 2 bits into those 2 bits
-	x = (x & k2) + ((x >> 2)  & k2); // put count of each 4 bits into those 4 bits
-	x = (x       +  (x >> 4)) & k4 ; // put count of each 8 bits into those 8 bits
-	x = (x * kf) >> 56; // returns 8 most significant bits of x + (x<<8) + (x<<16) + (x<<24) + ...
-
-	return (cell)x;
-}
-
-inline cell log2(u64 x)
-{
-#ifdef FACTOR_AMD64
 	cell n;
-	asm ("bsr %1, %0;":"=r"(n):"r"((cell)x));
+#if defined(FACTOR_X86)
+	#if defined(_MSC_VER)
+		_BitScanReverse(&n,x);
+	#else
+		asm ("bsr %1, %0;":"=r"(n):"r"(x));
+	#endif
+#elif defined(FACTOR_AMD64)
+	#if defined(_MSC_VER)
+		_BitScanReverse64(&n,x);
+	#else
+		asm ("bsr %1, %0;":"=r"(n):"r"(x));
+	#endif
+#elif defined(FACTOR_PPC)
+	asm ("cntlzw %1, %0;":"=r"(n):"r"(x));
+	n = (31 - n);
 #else
-	cell n = 0;
-	if (x >= (u64)1 << 32) { x >>= 32; n += 32; }
-	if (x >= (u64)1 << 16) { x >>= 16; n += 16; }
-	if (x >= (u64)1 <<  8) { x >>=  8; n +=  8; }
-	if (x >= (u64)1 <<  4) { x >>=  4; n +=  4; }
-	if (x >= (u64)1 <<  2) { x >>=  2; n +=  2; }
-	if (x >= (u64)1 <<  1) {           n +=  1; }
+	#error Unsupported CPU
 #endif
 	return n;
 }
 
-inline cell log2(u16 x)
-{
-#if defined(FACTOR_X86) || defined(FACTOR_AMD64)
-	cell n;
-	asm ("bsr %1, %0;":"=r"(n):"r"((cell)x));
-#else
-	cell n = 0;
-	if (x >= 1 << 8) { x >>=  8; n += 8; }
-	if (x >= 1 << 4) { x >>=  4; n += 4; }
-	if (x >= 1 << 2) { x >>=  2; n += 2; }
-	if (x >= 1 << 1) {           n += 1; }
-#endif
-	return n;
-}
-
-inline cell rightmost_clear_bit(u64 x)
+inline cell rightmost_clear_bit(cell x)
 {
 	return log2(~x & (x + 1));
 }
 
-inline cell rightmost_set_bit(u64 x)
+inline cell rightmost_set_bit(cell x)
 {
-	return log2(x & -x);
+	return log2(x & (~x + 1));
 }
 
-inline cell rightmost_set_bit(u16 x)
+inline cell popcount(cell x)
 {
-	return log2((u16)(x & -x));
+#ifdef FACTOR_64
+	u64 k1 = 0x5555555555555555ll;
+	u64 k2 = 0x3333333333333333ll;
+	u64 k4 = 0x0f0f0f0f0f0f0f0fll;
+	u64 kf = 0x0101010101010101ll;
+	cell ks = 56;
+#else
+	u32 k1 = 0x55555555;
+	u32 k2 = 0x33333333;
+	u32 k4 = 0xf0f0f0f;
+	u32 kf = 0x1010101;
+	cell ks = 24;
+#endif
+
+	x =  x       - ((x >> 1)  & k1); // put count of each 2 bits into those 2 bits
+	x = (x & k2) + ((x >> 2)  & k2); // put count of each 4 bits into those 4 bits
+	x = (x       +  (x >> 4)) & k4 ; // put count of each 8 bits into those 8 bits
+	x = (x * kf) >> ks; // returns 8 most significant bits of x + (x<<8) + (x<<16) + (x<<24) + ...
+
+	return x;
 }
 
 }
diff --git a/vm/booleans.cpp b/vm/booleans.cpp
index a7871dcbcb..dedb385f3d 100644
--- a/vm/booleans.cpp
+++ b/vm/booleans.cpp
@@ -3,19 +3,14 @@
 namespace factor
 {
 
-void factor_vm::box_boolean(bool value)
-{
-	dpush(tag_boolean(value));
-}
-
-VM_C_API void box_boolean(bool value, factor_vm *parent)
-{
-	return parent->box_boolean(value);
-}
-
 VM_C_API bool to_boolean(cell value, factor_vm *parent)
 {
-	return parent->to_boolean(value);
+	return to_boolean(value);
+}
+
+VM_C_API cell from_boolean(bool value, factor_vm *parent)
+{
+	return parent->tag_boolean(value);
 }
 
 }
diff --git a/vm/booleans.hpp b/vm/booleans.hpp
index 375c8e3756..a11103c5c6 100644
--- a/vm/booleans.hpp
+++ b/vm/booleans.hpp
@@ -1,15 +1,11 @@
 namespace factor
 {
 
-VM_C_API void box_boolean(bool value, factor_vm *vm);
 VM_C_API bool to_boolean(cell value, factor_vm *vm);
+VM_C_API cell from_boolean(bool value, factor_vm *vm);
 
-inline cell factor_vm::tag_boolean(cell untagged)
-{
-	return (untagged ? true_object : false_object);
-}
-
-inline bool factor_vm::to_boolean(cell value)
+/* Cannot allocate */
+inline static bool to_boolean(cell value)
 {
 	return value != false_object;
 }
diff --git a/vm/bump_allocator.hpp b/vm/bump_allocator.hpp
index 5488c65323..bbe4df8eec 100644
--- a/vm/bump_allocator.hpp
+++ b/vm/bump_allocator.hpp
@@ -32,6 +32,23 @@ template struct bump_allocator {
 	{
 		return end - here;
 	}
+
+	cell next_object_after(cell scan)
+	{
+		cell size = ((Block *)scan)->size();
+		if(scan + size < here)
+			return scan + size;
+		else
+			return 0;
+	}
+
+	cell first_object()
+	{
+		if(start != here)
+			return start;
+		else
+			return 0;
+	}
 };
 
 }
diff --git a/vm/byte_arrays.cpp b/vm/byte_arrays.cpp
index b317c39f62..1986b5d35c 100644
--- a/vm/byte_arrays.cpp
+++ b/vm/byte_arrays.cpp
@@ -13,20 +13,21 @@ byte_array *factor_vm::allot_byte_array(cell size)
 void factor_vm::primitive_byte_array()
 {
 	cell size = unbox_array_size();
-	dpush(tag(allot_byte_array(size)));
+	ctx->push(tag(allot_byte_array(size)));
 }
 
 void factor_vm::primitive_uninitialized_byte_array()
 {
 	cell size = unbox_array_size();
-	dpush(tag(allot_uninitialized_array(size)));
+	ctx->push(tag(allot_uninitialized_array(size)));
 }
 
 void factor_vm::primitive_resize_byte_array()
 {
-	byte_array *array = untag_check(dpop());
+	data_root array(ctx->pop(),this);
+	array.untag_check(this);
 	cell capacity = unbox_array_size();
-	dpush(tag(reallot_array(array,capacity)));
+	ctx->push(tag(reallot_array(array.untagged(),capacity)));
 }
 
 void growable_byte_array::append_bytes(void *elts, cell len)
diff --git a/vm/byte_arrays.hpp b/vm/byte_arrays.hpp
index a3d6fcf941..a96baff6ec 100755
--- a/vm/byte_arrays.hpp
+++ b/vm/byte_arrays.hpp
@@ -15,14 +15,8 @@ struct growable_byte_array {
 
 template byte_array *factor_vm::byte_array_from_value(Type *value)
 {
-	return byte_array_from_values(value,1);
-}
-
-template byte_array *factor_vm::byte_array_from_values(Type *values, cell len)
-{
-	cell size = sizeof(Type) * len;
-	byte_array *data = allot_uninitialized_array(size);
-	memcpy(data->data(),values,size);
+	byte_array *data = allot_uninitialized_array(sizeof(Type));
+	memcpy(data->data(),value,sizeof(Type));
 	return data;
 }
 
diff --git a/vm/callbacks.cpp b/vm/callbacks.cpp
index 4fe19c0bc0..416c1395d4 100644
--- a/vm/callbacks.cpp
+++ b/vm/callbacks.cpp
@@ -19,48 +19,87 @@ void factor_vm::init_callbacks(cell size)
 	callbacks = new callback_heap(size,this);
 }
 
-void callback_heap::update(callback *stub)
+void callback_heap::store_callback_operand(code_block *stub, cell index, cell value)
 {
 	tagged code_template(parent->special_objects[CALLBACK_STUB]);
 
-	cell rel_class = untag_fixnum(array_nth(code_template.untagged(),1));
-	cell offset = untag_fixnum(array_nth(code_template.untagged(),3));
+	cell rel_class = untag_fixnum(array_nth(code_template.untagged(),3 * index + 1));
+	cell rel_type  = untag_fixnum(array_nth(code_template.untagged(),3 * index + 2));
+	cell offset    = untag_fixnum(array_nth(code_template.untagged(),3 * index + 3));
 
-	parent->store_address_in_code_block(rel_class,
-		(cell)(stub + 1) + offset,
-		(cell)(stub->compiled + 1));
+	relocation_entry rel(
+		(relocation_type)rel_type,
+		(relocation_class)rel_class,
+		offset);
 
-	flush_icache((cell)stub,stub->size);
+	instruction_operand op(rel,stub,0);
+	op.store_value(value);
 }
 
-callback *callback_heap::add(code_block *compiled)
+void callback_heap::update(code_block *stub)
+{
+	store_callback_operand(stub,1,(cell)callback_entry_point(stub));
+	stub->flush_icache();
+}
+
+code_block *callback_heap::add(cell owner, cell return_rewind)
 {
 	tagged code_template(parent->special_objects[CALLBACK_STUB]);
 	tagged insns(array_nth(code_template.untagged(),0));
 	cell size = array_capacity(insns.untagged());
 
-	cell bump = align(size,sizeof(cell)) + sizeof(callback);
+	cell bump = align(size + sizeof(code_block),data_alignment);
 	if(here + bump > seg->end) fatal_error("Out of callback space",0);
 
-	callback *stub = (callback *)here;
-	stub->compiled = compiled;
-	memcpy(stub + 1,insns->data(),size);
-
-	stub->size = align(size,sizeof(cell));
+	free_heap_block *free_block = (free_heap_block *)here;
+	free_block->make_free(bump);
 	here += bump;
 
+	code_block *stub = (code_block *)free_block;
+	stub->owner = owner;
+	stub->parameters = false_object;
+	stub->relocation = false_object;
+
+	memcpy(stub->entry_point(),insns->data(),size);
+
+	/* Store VM pointer */
+	store_callback_operand(stub,0,(cell)parent);
+
+	/* On x86, the RET instruction takes an argument which depends on
+	the callback's calling convention */
+#if defined(FACTOR_X86) || defined(FACTOR_AMD64)
+	store_callback_operand(stub,2,return_rewind);
+#endif
+
 	update(stub);
 
 	return stub;
 }
 
+struct callback_updater {
+	callback_heap *callbacks;
+
+	explicit callback_updater(callback_heap *callbacks_) : callbacks(callbacks_) {}
+
+	void operator()(code_block *stub)
+	{
+		callbacks->update(stub);
+	}
+};
+
+void callback_heap::update()
+{
+	callback_updater updater(this);
+	each_callback(updater);
+}
+
 void factor_vm::primitive_callback()
 {
-	tagged w(dpop());
+	cell return_rewind = to_cell(ctx->pop());
+	tagged w(ctx->pop());
+
 	w.untag_check(this);
-
-	callback *stub = callbacks->add(w->code);
-	box_alien(stub + 1);
+	ctx->push(allot_alien(callbacks->add(w.value(),return_rewind)->entry_point()));
 }
 
 }
diff --git a/vm/callbacks.hpp b/vm/callbacks.hpp
index c499ad4719..607984ad23 100644
--- a/vm/callbacks.hpp
+++ b/vm/callbacks.hpp
@@ -1,11 +1,28 @@
 namespace factor
 {
 
-struct callback {
-	cell size;
-	code_block *compiled;
-	void *code() { return (void *)(this + 1); }
-};
+/* The callback heap is used to store the machine code that alien-callbacks
+actually jump to when C code invokes them.
+
+The callback heap has entries that look like code_blocks from the code heap, but
+callback heap entries are allocated contiguously, never deallocated, and all
+fields but the owner are set to false_object. The owner points to the callback
+bottom word, whose entry point is the callback body itself, generated by the
+optimizing compiler. The machine code that follows a callback stub consists of a
+single CALLBACK_STUB machine code template, which performs a jump to a "far"
+address (on PowerPC and x86-64, its loaded into a register first).
+
+GC updates the CALLBACK_STUB code if the code block of the callback bottom word
+is ever moved. The callback stub itself won't move, though, and is never
+deallocated. This means that the callback stub itself is a stable function
+pointer that C code can hold on to until the associated Factor VM exits.
+
+Since callback stubs are GC roots, and are never deallocated, the associated
+callback code in the code heap is also never deallocated.
+
+The callback heap is not saved in the image. Running GC in a new session after
+saving the image will deallocate any code heap entries that were only reachable
+from the callback heap in the previous session when the image was saved. */
 
 struct callback_heap {
 	segment *seg;
@@ -15,18 +32,29 @@ struct callback_heap {
 	explicit callback_heap(cell size, factor_vm *parent);
 	~callback_heap();
 
-	callback *add(code_block *compiled);
-	void update(callback *stub);
-
-	callback *next(callback *stub)
+	void *callback_entry_point(code_block *stub)
 	{
-		return (callback *)((cell)stub + stub->size + sizeof(callback));
+		word *w = (word *)UNTAG(stub->owner);
+		return w->entry_point;
 	}
 
-	template void iterate(Iterator &iter)
+	void store_callback_operand(code_block *stub, cell index, cell value);
+
+	void update(code_block *stub);
+
+	code_block *add(cell owner, cell return_rewind);
+
+	void update();
+
+	code_block *next(code_block *stub)
 	{
-		callback *scan = (callback *)seg->start;
-		callback *end = (callback *)here;
+		return (code_block *)((cell)stub + stub->size());
+	}
+
+	template void each_callback(Iterator &iter)
+	{
+		code_block *scan = (code_block *)seg->start;
+		code_block *end = (code_block *)here;
 		while(scan < end)
 		{
 			iter(scan);
diff --git a/vm/callstack.cpp b/vm/callstack.cpp
index 85f392af0e..4aa9321353 100755
--- a/vm/callstack.cpp
+++ b/vm/callstack.cpp
@@ -6,7 +6,7 @@ namespace factor
 void factor_vm::check_frame(stack_frame *frame)
 {
 #ifdef FACTOR_DEBUG
-	check_code_pointer((cell)frame->xt);
+	check_code_pointer((cell)frame->entry_point);
 	assert(frame->size != 0);
 #endif
 }
@@ -28,52 +28,42 @@ stack_frame *factor_vm::fix_callstack_top(stack_frame *top, stack_frame *bottom)
 	return frame + 1;
 }
 
-/* We ignore the topmost frame, the one calling 'callstack',
+/* We ignore the two topmost frames, the 'callstack' primitive
+frame itself, and the frame calling the 'callstack' primitive,
 so that set-callstack doesn't get stuck in an infinite loop.
 
 This means that if 'callstack' is called in tail position, we
 will have popped a necessary frame... however this word is only
 called by continuation implementation, and user code shouldn't
 be calling it at all, so we leave it as it is for now. */
-stack_frame *factor_vm::capture_start()
+stack_frame *factor_vm::second_from_top_stack_frame()
 {
 	stack_frame *frame = ctx->callstack_bottom - 1;
-	while(frame >= ctx->callstack_top && frame_successor(frame) >= ctx->callstack_top)
+	while(frame >= ctx->callstack_top
+		&& frame_successor(frame) >= ctx->callstack_top
+		&& frame_successor(frame_successor(frame)) >= ctx->callstack_top)
+	{
 		frame = frame_successor(frame);
+	}
 	return frame + 1;
 }
 
 void factor_vm::primitive_callstack()
 {
-	stack_frame *top = capture_start();
+	stack_frame *top = second_from_top_stack_frame();
 	stack_frame *bottom = ctx->callstack_bottom;
 
-	fixnum size = (cell)bottom - (cell)top;
-	if(size < 0)
-		size = 0;
+	fixnum size = std::max((fixnum)0,(fixnum)bottom - (fixnum)top);
 
 	callstack *stack = allot_callstack(size);
 	memcpy(stack->top(),top,size);
-	dpush(tag(stack));
-}
-
-void factor_vm::primitive_set_callstack()
-{
-	callstack *stack = untag_check(dpop());
-
-	set_callstack(ctx->callstack_bottom,
-		stack->top(),
-		untag_fixnum(stack->length),
-		memcpy);
-
-	/* We cannot return here ... */
-	critical_error("Bug in set_callstack()",0);
+	ctx->push(tag(stack));
 }
 
 code_block *factor_vm::frame_code(stack_frame *frame)
 {
 	check_frame(frame);
-	return (code_block *)frame->xt - 1;
+	return (code_block *)frame->entry_point - 1;
 }
 
 code_block_type factor_vm::frame_type(stack_frame *frame)
@@ -86,6 +76,15 @@ cell factor_vm::frame_executing(stack_frame *frame)
 	return frame_code(frame)->owner;
 }
 
+cell factor_vm::frame_executing_quot(stack_frame *frame)
+{
+	tagged executing(frame_executing(frame));
+	code_block *compiled = frame_code(frame);
+	if(!compiled->optimized_p() && executing->type() == WORD_TYPE)
+		executing = executing.as()->def;
+	return executing.value();
+}
+
 stack_frame *factor_vm::frame_successor(stack_frame *frame)
 {
 	check_frame(frame);
@@ -99,14 +98,17 @@ cell factor_vm::frame_scan(stack_frame *frame)
 	{
 	case code_block_unoptimized:
 		{
-			cell quot = frame_executing(frame);
-			if(to_boolean(quot))
+			tagged obj(frame_executing(frame));
+			if(obj.type_p(WORD_TYPE))
+				obj = obj.as()->def;
+
+			if(obj.type_p(QUOTATION_TYPE))
 			{
 				char *return_addr = (char *)FRAME_RETURN_ADDRESS(frame,this);
-				char *quot_xt = (char *)(frame_code(frame) + 1);
+				char *quot_entry_point = (char *)(frame_code(frame) + 1);
 
 				return tag_fixnum(quot_code_offset_to_scan(
-					quot,(cell)(return_addr - quot_xt)));
+					obj.value(),(cell)(return_addr - quot_entry_point)));
 			}    
 			else
 				return false_object;
@@ -130,7 +132,7 @@ struct stack_frame_accumulator {
 
 	void operator()(stack_frame *frame)
 	{
-		data_root executing(parent->frame_executing(frame),parent);
+		data_root executing(parent->frame_executing_quot(frame),parent);
 		data_root scan(parent->frame_scan(frame),parent);
 
 		frames.add(executing.value());
@@ -142,13 +144,13 @@ struct stack_frame_accumulator {
 
 void factor_vm::primitive_callstack_to_array()
 {
-	data_root callstack(dpop(),this);
+	data_root callstack(ctx->pop(),this);
 
 	stack_frame_accumulator accum(this);
 	iterate_callstack_object(callstack.untagged(),accum);
 	accum.frames.trim();
 
-	dpush(accum.frames.elements.value());
+	ctx->push(accum.frames.elements.value());
 }
 
 stack_frame *factor_vm::innermost_stack_frame(callstack *stack)
@@ -163,50 +165,34 @@ stack_frame *factor_vm::innermost_stack_frame(callstack *stack)
 	return frame;
 }
 
-stack_frame *factor_vm::innermost_stack_frame_quot(callstack *callstack)
-{
-	stack_frame *inner = innermost_stack_frame(callstack);
-	tagged(frame_executing(inner)).untag_check(this);
-	return inner;
-}
-
 /* Some primitives implementing a limited form of callstack mutation.
 Used by the single stepper. */
 void factor_vm::primitive_innermost_stack_frame_executing()
 {
-	dpush(frame_executing(innermost_stack_frame(untag_check(dpop()))));
+	stack_frame *frame = innermost_stack_frame(untag_check(ctx->pop()));
+	ctx->push(frame_executing_quot(frame));
 }
 
 void factor_vm::primitive_innermost_stack_frame_scan()
 {
-	dpush(frame_scan(innermost_stack_frame_quot(untag_check(dpop()))));
+	stack_frame *frame = innermost_stack_frame(untag_check(ctx->pop()));
+	ctx->push(frame_scan(frame));
 }
 
 void factor_vm::primitive_set_innermost_stack_frame_quot()
 {
-	data_root callstack(dpop(),this);
-	data_root quot(dpop(),this);
+	data_root callstack(ctx->pop(),this);
+	data_root quot(ctx->pop(),this);
 
 	callstack.untag_check(this);
 	quot.untag_check(this);
 
-	jit_compile(quot.value(),true);
+	jit_compile_quot(quot.value(),true);
 
-	stack_frame *inner = innermost_stack_frame_quot(callstack.untagged());
-	cell offset = (char *)FRAME_RETURN_ADDRESS(inner,this) - (char *)inner->xt;
-	inner->xt = quot->xt;
-	FRAME_RETURN_ADDRESS(inner,this) = (char *)quot->xt + offset;
-}
-
-/* called before entry into Factor code. */
-void factor_vm::save_callstack_bottom(stack_frame *callstack_bottom)
-{
-	ctx->callstack_bottom = callstack_bottom;
-}
-
-VM_ASM_API void save_callstack_bottom(stack_frame *callstack_bottom, factor_vm *parent)
-{
-	return parent->save_callstack_bottom(callstack_bottom);
+	stack_frame *inner = innermost_stack_frame(callstack.untagged());
+	cell offset = (char *)FRAME_RETURN_ADDRESS(inner,this) - (char *)inner->entry_point;
+	inner->entry_point = quot->entry_point;
+	FRAME_RETURN_ADDRESS(inner,this) = (char *)quot->entry_point + offset;
 }
 
 }
diff --git a/vm/callstack.hpp b/vm/callstack.hpp
index 76bf3ecea4..9f8867447c 100755
--- a/vm/callstack.hpp
+++ b/vm/callstack.hpp
@@ -6,8 +6,6 @@ inline static cell callstack_size(cell size)
 	return sizeof(callstack) + size;
 }
 
-VM_ASM_API void save_callstack_bottom(stack_frame *callstack_bottom, factor_vm *vm);
-
 /* This is a little tricky. The iterator may allocate memory, so we
 keep the callstack in a GC root and use relative offsets */
 template void factor_vm::iterate_callstack_object(callstack *stack_, Iterator &iterator)
@@ -25,12 +23,9 @@ template void factor_vm::iterate_callstack_object(callstack *
 
 template void factor_vm::iterate_callstack(context *ctx, Iterator &iterator)
 {
-	cell top = (cell)ctx->callstack_top;
-	cell bottom = (cell)ctx->callstack_bottom;
+	stack_frame *frame = ctx->callstack_bottom - 1;
 
-	stack_frame *frame = (stack_frame *)bottom - 1;
-
-	while((cell)frame >= top)
+	while(frame >= ctx->callstack_top)
 	{
 		iterator(frame);
 		frame = frame_successor(frame);
diff --git a/vm/code_block.cpp b/vm/code_block.cpp
deleted file mode 100755
index dc6a488e26..0000000000
--- a/vm/code_block.cpp
+++ /dev/null
@@ -1,506 +0,0 @@
-#include "master.hpp"
-
-namespace factor
-{
-
-relocation_type factor_vm::relocation_type_of(relocation_entry r)
-{
-	return (relocation_type)((r & 0xf0000000) >> 28);
-}
-
-relocation_class factor_vm::relocation_class_of(relocation_entry r)
-{
-	return (relocation_class)((r & 0x0f000000) >> 24);
-}
-
-cell factor_vm::relocation_offset_of(relocation_entry r)
-{
-	return (r & 0x00ffffff);
-}
-
-void factor_vm::flush_icache_for(code_block *block)
-{
-	flush_icache((cell)block,block->size());
-}
-
-int factor_vm::number_of_parameters(relocation_type type)
-{
-	switch(type)
-	{
-	case RT_PRIMITIVE:
-	case RT_XT:
-	case RT_XT_PIC:
-	case RT_XT_PIC_TAIL:
-	case RT_IMMEDIATE:
-	case RT_HERE:
-	case RT_UNTAGGED:
-	case RT_VM:
-		return 1;
-	case RT_DLSYM:
-		return 2;
-	case RT_THIS:
-	case RT_CONTEXT:
-	case RT_MEGAMORPHIC_CACHE_HITS:
-	case RT_CARDS_OFFSET:
-	case RT_DECKS_OFFSET:
-		return 0;
-	default:
-		critical_error("Bad rel type",type);
-		return -1; /* Can't happen */
-	}
-}
-
-void *factor_vm::object_xt(cell obj)
-{
-	switch(tagged(obj).type())
-	{
-	case WORD_TYPE:
-		return untag(obj)->xt;
-	case QUOTATION_TYPE:
-		return untag(obj)->xt;
-	default:
-		critical_error("Expected word or quotation",obj);
-		return NULL;
-	}
-}
-
-void *factor_vm::xt_pic(word *w, cell tagged_quot)
-{
-	if(!to_boolean(tagged_quot) || max_pic_size == 0)
-		return w->xt;
-	else
-	{
-		quotation *quot = untag(tagged_quot);
-		if(quot->code)
-			return quot->xt;
-		else
-			return w->xt;
-	}
-}
-
-void *factor_vm::word_xt_pic(word *w)
-{
-	return xt_pic(w,w->pic_def);
-}
-
-void *factor_vm::word_xt_pic_tail(word *w)
-{
-	return xt_pic(w,w->pic_tail_def);
-}
-
-/* References to undefined symbols are patched up to call this function on
-image load */
-void factor_vm::undefined_symbol()
-{
-	general_error(ERROR_UNDEFINED_SYMBOL,false_object,false_object,NULL);
-}
-
-void undefined_symbol()
-{
-	return tls_vm()->undefined_symbol();
-}
-
-/* Look up an external library symbol referenced by a compiled code block */
-void *factor_vm::get_rel_symbol(array *literals, cell index)
-{
-	cell symbol = array_nth(literals,index);
-	cell library = array_nth(literals,index + 1);
-
-	dll *d = (to_boolean(library) ? untag(library) : NULL);
-
-	if(d != NULL && !d->dll)
-		return (void *)factor::undefined_symbol;
-
-	switch(tagged(symbol).type())
-	{
-	case BYTE_ARRAY_TYPE:
-		{
-			symbol_char *name = alien_offset(symbol);
-			void *sym = ffi_dlsym(d,name);
-
-			if(sym)
-				return sym;
-			else
-			{
-				return (void *)factor::undefined_symbol;
-			}
-		}
-	case ARRAY_TYPE:
-		{
-			array *names = untag(symbol);
-			for(cell i = 0; i < array_capacity(names); i++)
-			{
-				symbol_char *name = alien_offset(array_nth(names,i));
-				void *sym = ffi_dlsym(d,name);
-
-				if(sym)
-					return sym;
-			}
-			return (void *)factor::undefined_symbol;
-		}
-	default:
-		critical_error("Bad symbol specifier",symbol);
-		return (void *)factor::undefined_symbol;
-	}
-}
-
-cell factor_vm::compute_relocation(relocation_entry rel, cell index, code_block *compiled)
-{
-	array *literals = (to_boolean(compiled->literals)
-		? untag(compiled->literals) : NULL);
-	cell offset = relocation_offset_of(rel) + (cell)compiled->xt();
-
-#define ARG array_nth(literals,index)
-
-	switch(relocation_type_of(rel))
-	{
-	case RT_PRIMITIVE:
-		return (cell)primitives[untag_fixnum(ARG)];
-	case RT_DLSYM:
-		return (cell)get_rel_symbol(literals,index);
-	case RT_IMMEDIATE:
-		return ARG;
-	case RT_XT:
-		return (cell)object_xt(ARG);
-	case RT_XT_PIC:
-		return (cell)word_xt_pic(untag(ARG));
-	case RT_XT_PIC_TAIL:
-		return (cell)word_xt_pic_tail(untag(ARG));
-	case RT_HERE:
-	{
-		fixnum arg = untag_fixnum(ARG);
-		return (arg >= 0 ? offset + arg : (cell)(compiled + 1) - arg);
-	}
-	case RT_THIS:
-		return (cell)(compiled + 1);
-	case RT_CONTEXT:
-		return (cell)&ctx;
-	case RT_UNTAGGED:
-		return untag_fixnum(ARG);
-	case RT_MEGAMORPHIC_CACHE_HITS:
-		return (cell)&dispatch_stats.megamorphic_cache_hits;
-	case RT_VM:
-		return (cell)this + untag_fixnum(ARG);
-	case RT_CARDS_OFFSET:
-		return cards_offset;
-	case RT_DECKS_OFFSET:
-		return decks_offset;
-	default:
-		critical_error("Bad rel type",rel);
-		return 0; /* Can't happen */
-	}
-
-#undef ARG
-}
-
-template void factor_vm::iterate_relocations(code_block *compiled, Iterator &iter)
-{
-	if(to_boolean(compiled->relocation))
-	{
-		byte_array *relocation = untag(compiled->relocation);
-
-		cell index = 0;
-		cell length = array_capacity(relocation) / sizeof(relocation_entry);
-
-		for(cell i = 0; i < length; i++)
-		{
-			relocation_entry rel = relocation->data()[i];
-			iter(rel,index,compiled);
-			index += number_of_parameters(relocation_type_of(rel));			
-		}
-	}
-}
-
-/* Store a 32-bit value into a PowerPC LIS/ORI sequence */
-void factor_vm::store_address_2_2(cell *ptr, cell value)
-{
-	ptr[-1] = ((ptr[-1] & ~0xffff) | ((value >> 16) & 0xffff));
-	ptr[ 0] = ((ptr[ 0] & ~0xffff) | (value & 0xffff));
-}
-
-/* Store a value into a bitfield of a PowerPC instruction */
-void factor_vm::store_address_masked(cell *ptr, fixnum value, cell mask, fixnum shift)
-{
-	/* This is unaccurate but good enough */
-	fixnum test = (fixnum)mask >> 1;
-	if(value <= -test || value >= test)
-		critical_error("Value does not fit inside relocation",0);
-
-	*ptr = ((*ptr & ~mask) | ((value >> shift) & mask));
-}
-
-/* Perform a fixup on a code block */
-void factor_vm::store_address_in_code_block(cell klass, cell offset, fixnum absolute_value)
-{
-	fixnum relative_value = absolute_value - offset;
-
-	switch(klass)
-	{
-	case RC_ABSOLUTE_CELL:
-		*(cell *)offset = absolute_value;
-		break;
-	case RC_ABSOLUTE:
-		*(u32*)offset = absolute_value;
-		break;
-	case RC_RELATIVE:
-		*(u32*)offset = relative_value - sizeof(u32);
-		break;
-	case RC_ABSOLUTE_PPC_2_2:
-		store_address_2_2((cell *)offset,absolute_value);
-		break;
-	case RC_ABSOLUTE_PPC_2:
-		store_address_masked((cell *)offset,absolute_value,rel_absolute_ppc_2_mask,0);
-		break;
-	case RC_RELATIVE_PPC_2:
-		store_address_masked((cell *)offset,relative_value,rel_relative_ppc_2_mask,0);
-		break;
-	case RC_RELATIVE_PPC_3:
-		store_address_masked((cell *)offset,relative_value,rel_relative_ppc_3_mask,0);
-		break;
-	case RC_RELATIVE_ARM_3:
-		store_address_masked((cell *)offset,relative_value - sizeof(cell) * 2,
-			rel_relative_arm_3_mask,2);
-		break;
-	case RC_INDIRECT_ARM:
-		store_address_masked((cell *)offset,relative_value - sizeof(cell),
-			rel_indirect_arm_mask,0);
-		break;
-	case RC_INDIRECT_ARM_PC:
-		store_address_masked((cell *)offset,relative_value - sizeof(cell) * 2,
-			rel_indirect_arm_mask,0);
-		break;
-	default:
-		critical_error("Bad rel class",klass);
-		break;
-	}
-}
-
-struct literal_references_updater {
-	factor_vm *parent;
-
-	explicit literal_references_updater(factor_vm *parent_) : parent(parent_) {}
-
-	void operator()(relocation_entry rel, cell index, code_block *compiled)
-	{
-		if(parent->relocation_type_of(rel) == RT_IMMEDIATE)
-		{
-			cell offset = parent->relocation_offset_of(rel) + (cell)(compiled + 1);
-			array *literals = untag(compiled->literals);
-			fixnum absolute_value = array_nth(literals,index);
-			parent->store_address_in_code_block(parent->relocation_class_of(rel),offset,absolute_value);
-		}
-	}
-};
-
-/* Update pointers to literals from compiled code. */
-void factor_vm::update_literal_references(code_block *compiled)
-{
-	if(!code->needs_fixup_p(compiled))
-	{
-		literal_references_updater updater(this);
-		iterate_relocations(compiled,updater);
-		flush_icache_for(compiled);
-	}
-}
-
-/* Compute an address to store at a relocation */
-void factor_vm::relocate_code_block_step(relocation_entry rel, cell index, code_block *compiled)
-{
-#ifdef FACTOR_DEBUG
-	if(to_boolean(compiled->literals))
-		tagged(compiled->literals).untag_check(this);
-	if(to_boolean(compiled->relocation))
-		tagged(compiled->relocation).untag_check(this);
-#endif
-
-	store_address_in_code_block(relocation_class_of(rel),
-		relocation_offset_of(rel) + (cell)compiled->xt(),
-		compute_relocation(rel,index,compiled));
-}
-
-struct word_references_updater {
-	factor_vm *parent;
-
-	explicit word_references_updater(factor_vm *parent_) : parent(parent_) {}
-	void operator()(relocation_entry rel, cell index, code_block *compiled)
-	{
-		relocation_type type = parent->relocation_type_of(rel);
-		if(type == RT_XT || type == RT_XT_PIC || type == RT_XT_PIC_TAIL)
-			parent->relocate_code_block_step(rel,index,compiled);
-	}
-};
-
-/* Relocate new code blocks completely; updating references to literals,
-dlsyms, and words. For all other words in the code heap, we only need
-to update references to other words, without worrying about literals
-or dlsyms. */
-void factor_vm::update_word_references(code_block *compiled)
-{
-	if(code->needs_fixup_p(compiled))
-		relocate_code_block(compiled);
-	/* update_word_references() is always applied to every block in
-	   the code heap. Since it resets all call sites to point to
-	   their canonical XT (cold entry point for non-tail calls,
-	   standard entry point for tail calls), it means that no PICs
-	   are referenced after this is done. So instead of polluting
-	   the code heap with dead PICs that will be freed on the next
-	   GC, we add them to the free list immediately. */
-	else if(compiled->pic_p())
-		code->code_heap_free(compiled);
-	else
-	{
-		word_references_updater updater(this);
-		iterate_relocations(compiled,updater);
-		flush_icache_for(compiled);
-	}
-}
-
-/* This runs after a full collection */
-struct literal_and_word_references_updater {
-	factor_vm *parent;
-
-	explicit literal_and_word_references_updater(factor_vm *parent_) : parent(parent_) {}
-
-	void operator()(relocation_entry rel, cell index, code_block *compiled)
-	{
-		relocation_type type = parent->relocation_type_of(rel);
-		switch(type)
-		{
-		case RT_IMMEDIATE:
-		case RT_XT:
-		case RT_XT_PIC:
-		case RT_XT_PIC_TAIL:
-			parent->relocate_code_block_step(rel,index,compiled);
-			break;
-		default:
-			break;
-		}
-	}
-};
-
-void factor_vm::update_code_block_words_and_literals(code_block *compiled)
-{
-	if(code->needs_fixup_p(compiled))
-		relocate_code_block(compiled);
-	else
-	{
-		literal_and_word_references_updater updater(this);
-		iterate_relocations(compiled,updater);
-		flush_icache_for(compiled);
-	}
-}
-
-void factor_vm::check_code_address(cell address)
-{
-#ifdef FACTOR_DEBUG
-	assert(address >= code->seg->start && address < code->seg->end);
-#endif
-}
-
-struct code_block_relocator {
-	factor_vm *parent;
-
-	explicit code_block_relocator(factor_vm *parent_) : parent(parent_) {}
-
-	void operator()(relocation_entry rel, cell index, code_block *compiled)
-	{
-		parent->relocate_code_block_step(rel,index,compiled);
-	}
-};
-
-/* Perform all fixups on a code block */
-void factor_vm::relocate_code_block(code_block *compiled)
-{
-	code->needs_fixup.erase(compiled);
-	code_block_relocator relocator(this);
-	iterate_relocations(compiled,relocator);
-	flush_icache_for(compiled);
-}
-
-/* Fixup labels. This is done at compile time, not image load time */
-void factor_vm::fixup_labels(array *labels, code_block *compiled)
-{
-	cell i;
-	cell size = array_capacity(labels);
-
-	for(i = 0; i < size; i += 3)
-	{
-		cell klass = untag_fixnum(array_nth(labels,i));
-		cell offset = untag_fixnum(array_nth(labels,i + 1));
-		cell target = untag_fixnum(array_nth(labels,i + 2));
-
-		store_address_in_code_block(klass,
-			offset + (cell)(compiled + 1),
-			target + (cell)(compiled + 1));
-	}
-}
-
-/* Might GC */
-code_block *factor_vm::allot_code_block(cell size, code_block_type type)
-{
-	code_block *block = code->allocator->allot(size + sizeof(code_block));
-
-	/* If allocation failed, do a full GC and compact the code heap.
-	A full GC that occurs as a result of the data heap filling up does not
-	trigger a compaction. This setup ensures that most GCs do not compact
-	the code heap, but if the code fills up, it probably means it will be
-	fragmented after GC anyway, so its best to compact. */
-	if(block == NULL)
-	{
-		primitive_compact_gc();
-		block = code->allocator->allot(size + sizeof(code_block));
-
-		/* Insufficient room even after code GC, give up */
-		if(block == NULL)
-		{
-			std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
-			std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
-			fatal_error("Out of memory in add-compiled-block",0);
-		}
-	}
-
-	block->set_type(type);
-	return block;
-}
-
-/* Might GC */
-code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_)
-{
-	data_root code(code_,this);
-	data_root labels(labels_,this);
-	data_root owner(owner_,this);
-	data_root relocation(relocation_,this);
-	data_root literals(literals_,this);
-
-	cell code_length = array_capacity(code.untagged());
-	code_block *compiled = allot_code_block(code_length,type);
-
-	compiled->owner = owner.value();
-
-	/* slight space optimization */
-	if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
-		compiled->relocation = false_object;
-	else
-		compiled->relocation = relocation.value();
-
-	if(literals.type() == ARRAY_TYPE && array_capacity(literals.untagged()) == 0)
-		compiled->literals = false_object;
-	else
-		compiled->literals = literals.value();
-
-	/* code */
-	memcpy(compiled + 1,code.untagged() + 1,code_length);
-
-	/* fixup labels */
-	if(to_boolean(labels.value()))
-		fixup_labels(labels.as().untagged(),compiled);
-
-	/* next time we do a minor GC, we have to scan the code heap for
-	literals */
-	this->code->write_barrier(compiled);
-	this->code->needs_fixup.insert(compiled);
-
-	return compiled;
-}
-
-}
diff --git a/vm/code_block.hpp b/vm/code_block.hpp
deleted file mode 100644
index d31a776c0e..0000000000
--- a/vm/code_block.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-namespace factor
-{
-
-enum relocation_type {
-	/* arg is a primitive number */
-	RT_PRIMITIVE,
-	/* arg is a literal table index, holding an array pair (symbol/dll) */
-	RT_DLSYM,
-	/* a pointer to a compiled word reference */
-	RT_DISPATCH,
-	/* a word or quotation's general entry point */
-	RT_XT,
-	/* a word's PIC entry point */
-	RT_XT_PIC,
-	/* a word's tail-call PIC entry point */
-	RT_XT_PIC_TAIL,
-	/* current offset */
-	RT_HERE,
-	/* current code block */
-	RT_THIS,
-	/* immediate literal */
-	RT_IMMEDIATE,
-	/* address of ctx var */
-	RT_CONTEXT,
-	/* untagged fixnum literal */
-	RT_UNTAGGED,
-	/* address of megamorphic_cache_hits var */
-	RT_MEGAMORPHIC_CACHE_HITS,
-	/* address of vm object */
-	RT_VM,
-	/* value of vm->cards_offset */
-	RT_CARDS_OFFSET,
-	/* value of vm->decks_offset */
-	RT_DECKS_OFFSET,
-};
-
-enum relocation_class {
-	/* absolute address in a 64-bit location */
-	RC_ABSOLUTE_CELL,
-	/* absolute address in a 32-bit location */
-	RC_ABSOLUTE,
-	/* relative address in a 32-bit location */
-	RC_RELATIVE,
-	/* absolute address in a PowerPC LIS/ORI sequence */
-	RC_ABSOLUTE_PPC_2_2,
-	/* absolute address in a PowerPC LWZ instruction */
-	RC_ABSOLUTE_PPC_2,
-	/* relative address in a PowerPC LWZ/STW/BC instruction */
-	RC_RELATIVE_PPC_2,
-	/* relative address in a PowerPC B/BL instruction */
-	RC_RELATIVE_PPC_3,
-	/* relative address in an ARM B/BL instruction */
-	RC_RELATIVE_ARM_3,
-	/* pointer to address in an ARM LDR/STR instruction */
-	RC_INDIRECT_ARM,
-	/* pointer to address in an ARM LDR/STR instruction offset by 8 bytes */
-	RC_INDIRECT_ARM_PC
-};
-
-static const cell rel_absolute_ppc_2_mask = 0xffff;
-static const cell rel_relative_ppc_2_mask = 0xfffc;
-static const cell rel_relative_ppc_3_mask = 0x3fffffc;
-static const cell rel_indirect_arm_mask = 0xfff;
-static const cell rel_relative_arm_3_mask = 0xffffff;
-
-/* code relocation table consists of a table of entries for each fixup */
-typedef u32 relocation_entry;
-
-}
diff --git a/vm/code_block_visitor.hpp b/vm/code_block_visitor.hpp
index 33e889c940..ac5d140783 100644
--- a/vm/code_block_visitor.hpp
+++ b/vm/code_block_visitor.hpp
@@ -1,7 +1,39 @@
 namespace factor
 {
 
-template struct call_frame_code_block_visitor {
+/* Code block visitors iterate over sets of code blocks, applying a functor to
+each one. The functor returns a new code_block pointer, which may or may not
+equal the old one. This is stored back to the original location.
+
+This is used by GC's sweep and compact phases, and the implementation of the
+modify-code-heap primitive.
+
+Iteration is driven by visit_*() methods. Some of them define GC roots:
+- visit_context_code_blocks()
+- visit_callback_code_blocks() */
+ 
+template struct code_block_visitor {
+	factor_vm *parent;
+	Visitor visitor;
+
+	explicit code_block_visitor(factor_vm *parent_, Visitor visitor_) :
+		parent(parent_), visitor(visitor_) {}
+
+	code_block *visit_code_block(code_block *compiled);
+	void visit_object_code_block(object *obj);
+	void visit_embedded_code_pointers(code_block *compiled);
+	void visit_context_code_blocks();
+	void visit_uninitialized_code_blocks();
+};
+
+template
+code_block *code_block_visitor::visit_code_block(code_block *compiled)
+{
+	return visitor(compiled);
+}
+
+template
+struct call_frame_code_block_visitor {
 	factor_vm *parent;
 	Visitor visitor;
 
@@ -10,80 +42,97 @@ template struct call_frame_code_block_visitor {
 
 	void operator()(stack_frame *frame)
 	{
-		cell offset = (cell)FRAME_RETURN_ADDRESS(frame,parent) - (cell)frame->xt;
+		cell offset = (cell)FRAME_RETURN_ADDRESS(frame,parent) - (cell)frame->entry_point;
 
 		code_block *new_block = visitor(parent->frame_code(frame));
-		frame->xt = new_block->xt();
+		frame->entry_point = new_block->entry_point();
 
-		FRAME_RETURN_ADDRESS(frame,parent) = (void *)((cell)frame->xt + offset);
+		FRAME_RETURN_ADDRESS(frame,parent) = (void *)((cell)frame->entry_point + offset);
 	}
 };
 
-template struct callback_code_block_visitor {
-	callback_heap *callbacks;
-	Visitor visitor;
-
-	explicit callback_code_block_visitor(callback_heap *callbacks_, Visitor visitor_) :
-		callbacks(callbacks_), visitor(visitor_) {}
-
-	void operator()(callback *stub)
+template
+void code_block_visitor::visit_object_code_block(object *obj)
+{
+	switch(obj->type())
 	{
-		stub->compiled = visitor(stub->compiled);
-		callbacks->update(stub);
-	}
-};
-
-template struct code_block_visitor {
-	factor_vm *parent;
-	Visitor visitor;
-
-	explicit code_block_visitor(factor_vm *parent_, Visitor visitor_) :
-		parent(parent_), visitor(visitor_) {}
-
-	void visit_object_code_block(object *obj)
-	{
-		switch(obj->h.hi_tag())
+	case WORD_TYPE:
 		{
-		case WORD_TYPE:
-			{
-				word *w = (word *)obj;
-				if(w->code)
-					w->code = visitor(w->code);
-				if(w->profiling)
-					w->code = visitor(w->profiling);
-	
-				parent->update_word_xt(w);
-				break;
-			}
-		case QUOTATION_TYPE:
-			{
-				quotation *q = (quotation *)obj;
-				if(q->code)
-					parent->set_quot_xt(q,visitor(q->code));
-				break;
-			}
-		case CALLSTACK_TYPE:
-			{
-				callstack *stack = (callstack *)obj;
-				call_frame_code_block_visitor call_frame_visitor(parent,visitor);
-				parent->iterate_callstack_object(stack,call_frame_visitor);
-				break;
-			}
+			word *w = (word *)obj;
+			if(w->code)
+				w->code = visitor(w->code);
+			if(w->profiling)
+				w->profiling = visitor(w->profiling);
+
+			parent->update_word_entry_point(w);
+			break;
+		}
+	case QUOTATION_TYPE:
+		{
+			quotation *q = (quotation *)obj;
+			if(q->code)
+				parent->set_quot_entry_point(q,visitor(q->code));
+			break;
+		}
+	case CALLSTACK_TYPE:
+		{
+			callstack *stack = (callstack *)obj;
+			call_frame_code_block_visitor call_frame_visitor(parent,visitor);
+			parent->iterate_callstack_object(stack,call_frame_visitor);
+			break;
 		}
 	}
+}
 
-	void visit_context_code_blocks()
+template
+struct embedded_code_pointers_visitor {
+	Visitor visitor;
+
+	explicit embedded_code_pointers_visitor(Visitor visitor_) : visitor(visitor_) {}
+
+	void operator()(instruction_operand op)
 	{
-		call_frame_code_block_visitor call_frame_visitor(parent,visitor);
-		parent->iterate_active_frames(call_frame_visitor);
+		relocation_type type = op.rel_type();
+		if(type == RT_ENTRY_POINT
+			|| type == RT_ENTRY_POINT_PIC
+			|| type == RT_ENTRY_POINT_PIC_TAIL)
+			op.store_code_block(visitor(op.load_code_block()));
 	}
-
-	void visit_callback_code_blocks()
-	{
-		callback_code_block_visitor callback_visitor(parent->callbacks,visitor);
-		parent->callbacks->iterate(callback_visitor);
-	}
-
 };
 
+template
+void code_block_visitor::visit_embedded_code_pointers(code_block *compiled)
+{
+	if(!parent->code->uninitialized_p(compiled))
+	{
+		embedded_code_pointers_visitor visitor(this->visitor);
+		compiled->each_instruction_operand(visitor);
+	}
+}
+
+template
+void code_block_visitor::visit_context_code_blocks()
+{
+	call_frame_code_block_visitor call_frame_visitor(parent,visitor);
+	parent->iterate_active_frames(call_frame_visitor);
+}
+
+template
+void code_block_visitor::visit_uninitialized_code_blocks()
+{
+	std::map *uninitialized_blocks = &parent->code->uninitialized_blocks;
+	std::map::const_iterator iter = uninitialized_blocks->begin();
+	std::map::const_iterator end = uninitialized_blocks->end();
+
+	std::map new_uninitialized_blocks;
+	for(; iter != end; iter++)
+	{
+		new_uninitialized_blocks.insert(std::make_pair(
+			visitor(iter->first),
+			iter->second));
+	}
+
+	parent->code->uninitialized_blocks = new_uninitialized_blocks;
+}
+
 }
diff --git a/vm/code_blocks.cpp b/vm/code_blocks.cpp
new file mode 100755
index 0000000000..89106499da
--- /dev/null
+++ b/vm/code_blocks.cpp
@@ -0,0 +1,390 @@
+#include "master.hpp"
+
+namespace factor
+{
+
+cell factor_vm::compute_entry_point_address(cell obj)
+{
+	switch(tagged(obj).type())
+	{
+	case WORD_TYPE:
+		return (cell)untag(obj)->entry_point;
+	case QUOTATION_TYPE:
+		return (cell)untag(obj)->entry_point;
+	default:
+		critical_error("Expected word or quotation",obj);
+		return 0;
+	}
+}
+
+cell factor_vm::compute_entry_point_pic_address(word *w, cell tagged_quot)
+{
+	if(!to_boolean(tagged_quot) || max_pic_size == 0)
+		return (cell)w->entry_point;
+	else
+	{
+		quotation *quot = untag(tagged_quot);
+		if(quot_compiled_p(quot))
+			return (cell)quot->entry_point;
+		else
+			return (cell)w->entry_point;
+	}
+}
+
+cell factor_vm::compute_entry_point_pic_address(cell w_)
+{
+	tagged w(w_);
+	return compute_entry_point_pic_address(w.untagged(),w->pic_def);
+}
+
+cell factor_vm::compute_entry_point_pic_tail_address(cell w_)
+{
+	tagged w(w_);
+	return compute_entry_point_pic_address(w.untagged(),w->pic_tail_def);
+}
+
+cell factor_vm::code_block_owner(code_block *compiled)
+{
+	tagged owner(compiled->owner);
+
+	/* Cold generic word call sites point to quotations that call the
+	inline-cache-miss and inline-cache-miss-tail primitives. */
+	if(owner.type_p(QUOTATION_TYPE))
+	{
+		tagged quot(owner.as());
+		tagged elements(quot->array);
+#ifdef FACTOR_DEBUG
+		assert(array_capacity(elements.untagged()) == 5);
+		assert(array_nth(elements.untagged(),4) == special_objects[PIC_MISS_WORD]
+			|| array_nth(elements.untagged(),4) == special_objects[PIC_MISS_TAIL_WORD]);
+#endif
+		tagged word_wrapper(array_nth(elements.untagged(),0));
+		return word_wrapper->object;
+	}
+	else
+		return compiled->owner;
+}
+
+struct update_word_references_relocation_visitor {
+	factor_vm *parent;
+
+	explicit update_word_references_relocation_visitor(factor_vm *parent_) : parent(parent_) {}
+
+	void operator()(instruction_operand op)
+	{
+		switch(op.rel_type())
+		{
+		case RT_ENTRY_POINT:
+			{
+				code_block *compiled = op.load_code_block();
+				cell owner = compiled->owner;
+				if(to_boolean(owner))
+					op.store_value(parent->compute_entry_point_address(owner));
+				break;
+			}
+		case RT_ENTRY_POINT_PIC:
+			{
+				code_block *compiled = op.load_code_block();
+				cell owner = parent->code_block_owner(compiled);
+				if(to_boolean(owner))
+					op.store_value(parent->compute_entry_point_pic_address(owner));
+				break;
+			}
+		case RT_ENTRY_POINT_PIC_TAIL:
+			{
+				code_block *compiled = op.load_code_block();
+				cell owner = parent->code_block_owner(compiled);
+				if(to_boolean(owner))
+					op.store_value(parent->compute_entry_point_pic_tail_address(owner));
+				break;
+			}
+		default:
+			break;
+		}
+	}
+};
+
+/* Relocate new code blocks completely; updating references to literals,
+dlsyms, and words. For all other words in the code heap, we only need
+to update references to other words, without worrying about literals
+or dlsyms. */
+void factor_vm::update_word_references(code_block *compiled)
+{
+	if(code->uninitialized_p(compiled))
+		initialize_code_block(compiled);
+	/* update_word_references() is always applied to every block in
+	   the code heap. Since it resets all call sites to point to
+	   their canonical entry point (cold entry point for non-tail calls,
+	   standard entry point for tail calls), it means that no PICs
+	   are referenced after this is done. So instead of polluting
+	   the code heap with dead PICs that will be freed on the next
+	   GC, we add them to the free list immediately. */
+	else if(compiled->pic_p())
+		code->free(compiled);
+	else
+	{
+		update_word_references_relocation_visitor visitor(this);
+		compiled->each_instruction_operand(visitor);
+		compiled->flush_icache();
+	}
+}
+
+void factor_vm::check_code_address(cell address)
+{
+#ifdef FACTOR_DEBUG
+	assert(address >= code->seg->start && address < code->seg->end);
+#endif
+}
+
+/* References to undefined symbols are patched up to call this function on
+image load */
+void factor_vm::undefined_symbol()
+{
+	general_error(ERROR_UNDEFINED_SYMBOL,false_object,false_object,NULL);
+}
+
+void undefined_symbol()
+{
+	return tls_vm()->undefined_symbol();
+}
+
+/* Look up an external library symbol referenced by a compiled code block */
+cell factor_vm::compute_dlsym_address(array *literals, cell index)
+{
+	cell symbol = array_nth(literals,index);
+	cell library = array_nth(literals,index + 1);
+
+	dll *d = (to_boolean(library) ? untag(library) : NULL);
+
+	if(d != NULL && !d->handle)
+		return (cell)factor::undefined_symbol;
+
+	switch(tagged(symbol).type())
+	{
+	case BYTE_ARRAY_TYPE:
+		{
+			symbol_char *name = alien_offset(symbol);
+			void *sym = ffi_dlsym(d,name);
+
+			if(sym)
+				return (cell)sym;
+			else
+				return (cell)factor::undefined_symbol;
+		}
+	case ARRAY_TYPE:
+		{
+			array *names = untag(symbol);
+			for(cell i = 0; i < array_capacity(names); i++)
+			{
+				symbol_char *name = alien_offset(array_nth(names,i));
+				void *sym = ffi_dlsym(d,name);
+
+				if(sym)
+					return (cell)sym;
+			}
+			return (cell)factor::undefined_symbol;
+		}
+	default:
+		critical_error("Bad symbol specifier",symbol);
+		return (cell)factor::undefined_symbol;
+	}
+}
+
+cell factor_vm::compute_vm_address(cell arg)
+{
+	return (cell)this + untag_fixnum(arg);
+}
+
+void factor_vm::store_external_address(instruction_operand op)
+{
+	code_block *compiled = op.parent_code_block();
+	array *parameters = (to_boolean(compiled->parameters) ? untag(compiled->parameters) : NULL);
+	cell index = op.parameter_index();
+
+	switch(op.rel_type())
+	{
+	case RT_DLSYM:
+		op.store_value(compute_dlsym_address(parameters,index));
+		break;
+	case RT_THIS:
+		op.store_value((cell)compiled->entry_point());
+		break;
+	case RT_MEGAMORPHIC_CACHE_HITS:
+		op.store_value((cell)&dispatch_stats.megamorphic_cache_hits);
+		break;
+	case RT_VM:
+		op.store_value(compute_vm_address(array_nth(parameters,index)));
+		break;
+	case RT_CARDS_OFFSET:
+		op.store_value(cards_offset);
+		break;
+	case RT_DECKS_OFFSET:
+		op.store_value(decks_offset);
+		break;
+	default:
+		critical_error("Bad rel type",op.rel_type());
+		break;
+	}
+}
+
+cell factor_vm::compute_here_address(cell arg, cell offset, code_block *compiled)
+{
+	fixnum n = untag_fixnum(arg);
+	if(n >= 0)
+		return (cell)compiled->entry_point() + offset + n;
+	else
+		return (cell)compiled->entry_point() - n;
+}
+
+struct initial_code_block_visitor {
+	factor_vm *parent;
+	cell literals;
+	cell literal_index;
+
+	explicit initial_code_block_visitor(factor_vm *parent_, cell literals_)
+		: parent(parent_), literals(literals_), literal_index(0) {}
+
+	cell next_literal()
+	{
+		return array_nth(untag(literals),literal_index++);
+	}
+
+	void operator()(instruction_operand op)
+	{
+		switch(op.rel_type())
+		{
+		case RT_LITERAL:
+			op.store_value(next_literal());
+			break;
+		case RT_ENTRY_POINT:
+			op.store_value(parent->compute_entry_point_address(next_literal()));
+			break;
+		case RT_ENTRY_POINT_PIC:
+			op.store_value(parent->compute_entry_point_pic_address(next_literal()));
+			break;
+		case RT_ENTRY_POINT_PIC_TAIL:
+			op.store_value(parent->compute_entry_point_pic_tail_address(next_literal()));
+			break;
+		case RT_HERE:
+			op.store_value(parent->compute_here_address(next_literal(),op.rel_offset(),op.parent_code_block()));
+			break;
+		case RT_UNTAGGED:
+			op.store_value(untag_fixnum(next_literal()));
+			break;
+		default:
+			parent->store_external_address(op);
+			break;
+		}
+	}
+};
+
+/* Perform all fixups on a code block */
+void factor_vm::initialize_code_block(code_block *compiled)
+{
+	std::map::iterator iter = code->uninitialized_blocks.find(compiled);
+
+	initial_code_block_visitor visitor(this,iter->second);
+	compiled->each_instruction_operand(visitor);
+	compiled->flush_icache();
+
+	code->uninitialized_blocks.erase(iter);
+
+	/* next time we do a minor GC, we have to trace this code block, since
+	the newly-installed instruction operands might point to literals in
+	nursery or aging */
+	code->write_barrier(compiled);
+}
+
+/* Fixup labels. This is done at compile time, not image load time */
+void factor_vm::fixup_labels(array *labels, code_block *compiled)
+{
+	cell size = array_capacity(labels);
+
+	for(cell i = 0; i < size; i += 3)
+	{
+		relocation_class rel_class = (relocation_class)untag_fixnum(array_nth(labels,i));
+		cell offset = untag_fixnum(array_nth(labels,i + 1));
+		cell target = untag_fixnum(array_nth(labels,i + 2));
+
+		relocation_entry new_entry(RT_HERE,rel_class,offset);
+
+		instruction_operand op(new_entry,compiled,0);
+		op.store_value(target + (cell)compiled->entry_point());
+	}
+}
+
+/* Might GC */
+code_block *factor_vm::allot_code_block(cell size, code_block_type type)
+{
+	code_block *block = code->allocator->allot(size + sizeof(code_block));
+
+	/* If allocation failed, do a full GC and compact the code heap.
+	A full GC that occurs as a result of the data heap filling up does not
+	trigger a compaction. This setup ensures that most GCs do not compact
+	the code heap, but if the code fills up, it probably means it will be
+	fragmented after GC anyway, so its best to compact. */
+	if(block == NULL)
+	{
+		primitive_compact_gc();
+		block = code->allocator->allot(size + sizeof(code_block));
+
+		/* Insufficient room even after code GC, give up */
+		if(block == NULL)
+		{
+			std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
+			std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
+			fatal_error("Out of memory in add-compiled-block",0);
+		}
+	}
+
+	block->set_type(type);
+	return block;
+}
+
+/* Might GC */
+code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell parameters_, cell literals_)
+{
+	data_root code(code_,this);
+	data_root labels(labels_,this);
+	data_root owner(owner_,this);
+	data_root relocation(relocation_,this);
+	data_root parameters(parameters_,this);
+	data_root literals(literals_,this);
+
+	cell code_length = array_capacity(code.untagged());
+	code_block *compiled = allot_code_block(code_length,type);
+
+	compiled->owner = owner.value();
+
+	/* slight space optimization */
+	if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
+		compiled->relocation = false_object;
+	else
+		compiled->relocation = relocation.value();
+
+	if(parameters.type() == ARRAY_TYPE && array_capacity(parameters.untagged()) == 0)
+		compiled->parameters = false_object;
+	else
+		compiled->parameters = parameters.value();
+
+	/* code */
+	memcpy(compiled + 1,code.untagged() + 1,code_length);
+
+	/* fixup labels */
+	if(to_boolean(labels.value()))
+		fixup_labels(labels.as().untagged(),compiled);
+
+	/* Once we are ready, fill in literal and word references in this code
+	block's instruction operands. In most cases this is done right after this
+	method returns, except when compiling words with the non-optimizing
+	compiler at the beginning of bootstrap */
+	this->code->uninitialized_blocks.insert(std::make_pair(compiled,literals.value()));
+
+	/* next time we do a minor GC, we have to trace this code block, since
+	the fields of the code_block struct might point into nursery or aging */
+	this->code->write_barrier(compiled);
+
+	return compiled;
+}
+
+}
diff --git a/vm/code_blocks.hpp b/vm/code_blocks.hpp
new file mode 100644
index 0000000000..baf763357c
--- /dev/null
+++ b/vm/code_blocks.hpp
@@ -0,0 +1,75 @@
+namespace factor
+{
+
+/* The compiled code heap is structured into blocks. */
+struct code_block
+{
+	cell header;
+	cell owner; /* tagged pointer to word, quotation or f */
+	cell parameters; /* tagged pointer to array or f */
+	cell relocation; /* tagged pointer to byte-array or f */
+
+	bool free_p() const
+	{
+		return (header & 1) == 1;
+	}
+
+	code_block_type type() const
+	{
+		return (code_block_type)((header >> 1) & 0x3);
+	}
+
+	void set_type(code_block_type type)
+	{
+		header = ((header & ~0x7) | (type << 1));
+	}
+
+	bool pic_p() const
+	{
+		return type() == code_block_pic;
+	}
+
+	bool optimized_p() const
+	{
+		return type() == code_block_optimized;
+	}
+
+	cell size() const
+	{
+		cell size = header & ~7;
+#ifdef FACTOR_DEBUG
+		assert(size > 0);
+#endif
+		return size;
+	}
+
+	void *entry_point() const
+	{
+		return (void *)(this + 1);
+	}
+
+	void flush_icache()
+	{
+		factor::flush_icache((cell)this,size());
+	}
+
+	template void each_instruction_operand(Iterator &iter)
+	{
+		if(to_boolean(relocation))
+		{
+			byte_array *rels = (byte_array *)UNTAG(relocation);
+
+			cell index = 0;
+			cell length = (rels->capacity >> TAG_BITS) / sizeof(relocation_entry);
+
+			for(cell i = 0; i < length; i++)
+			{
+				relocation_entry rel = rels->data()[i];
+				iter(instruction_operand(rel,this,index));
+				index += rel.number_of_parameters();
+			}
+		}
+	}
+};
+
+}
diff --git a/vm/code_heap.cpp b/vm/code_heap.cpp
index b4e071d644..b0435bb11f 100755
--- a/vm/code_heap.cpp
+++ b/vm/code_heap.cpp
@@ -5,7 +5,7 @@ namespace factor
 
 code_heap::code_heap(cell size)
 {
-	if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
+	if(size > ((u64)1 << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
 	seg = new segment(align_page(size),true);
 	if(!seg) fatal_error("Out of memory in heap allocator",size);
 	allocator = new free_list_allocator(size,seg->start);
@@ -31,9 +31,9 @@ void code_heap::clear_remembered_set()
 	points_to_aging.clear();
 }
 
-bool code_heap::needs_fixup_p(code_block *compiled)
+bool code_heap::uninitialized_p(code_block *compiled)
 {
-	return needs_fixup.count(compiled) > 0;
+	return uninitialized_blocks.count(compiled) > 0;
 }
 
 bool code_heap::marked_p(code_block *compiled)
@@ -51,14 +51,19 @@ void code_heap::clear_mark_bits()
 	allocator->state.clear_mark_bits();
 }
 
-void code_heap::code_heap_free(code_block *compiled)
+void code_heap::free(code_block *compiled)
 {
+	assert(!uninitialized_p(compiled));
 	points_to_nursery.erase(compiled);
 	points_to_aging.erase(compiled);
-	needs_fixup.erase(compiled);
 	allocator->free(compiled);
 }
 
+void code_heap::flush_icache()
+{
+	factor::flush_icache(seg->start,seg->size);
+}
+
 /* Allocate a code heap during startup */
 void factor_vm::init_code_heap(cell size)
 {
@@ -70,20 +75,6 @@ bool factor_vm::in_code_heap_p(cell ptr)
 	return (ptr >= code->seg->start && ptr <= code->seg->end);
 }
 
-/* Compile a word definition with the non-optimizing compiler. Allocates memory */
-void factor_vm::jit_compile_word(cell word_, cell def_, bool relocate)
-{
-	data_root word(word_,this);
-	data_root def(def_,this);
-
-	jit_compile(def.value(),relocate);
-
-	word->code = def->code;
-
-	if(to_boolean(word->pic_def)) jit_compile(word->pic_def,relocate);
-	if(to_boolean(word->pic_tail_def)) jit_compile(word->pic_tail_def,relocate);
-}
-
 struct word_updater {
 	factor_vm *parent;
 
@@ -100,60 +91,19 @@ defining a new word. */
 void factor_vm::update_code_heap_words()
 {
 	word_updater updater(this);
-	iterate_code_heap(updater);
-}
-
-/* After a full GC that did not grow the heap, we have to update references
-to literals and other words. */
-struct word_and_literal_code_heap_updater {
-	factor_vm *parent;
-
-	explicit word_and_literal_code_heap_updater(factor_vm *parent_) : parent(parent_) {}
-
-	void operator()(code_block *block, cell size)
-	{
-		parent->update_code_block_words_and_literals(block);
-	}
-};
-
-void factor_vm::update_code_heap_words_and_literals()
-{
-	current_gc->event->started_code_sweep();
-	word_and_literal_code_heap_updater updater(this);
-	code->allocator->sweep(updater);
-	current_gc->event->ended_code_sweep();
-}
-
-/* After growing the heap, we have to perform a full relocation to update
-references to card and deck arrays. */
-struct code_heap_relocator {
-	factor_vm *parent;
-
-	explicit code_heap_relocator(factor_vm *parent_) : parent(parent_) {}
-
-	void operator()(code_block *block, cell size)
-	{
-		parent->relocate_code_block(block);
-	}
-};
-
-void factor_vm::relocate_code_heap()
-{
-	code_heap_relocator relocator(this);
-	code->allocator->sweep(relocator);
+	each_code_block(updater);
 }
 
 void factor_vm::primitive_modify_code_heap()
 {
-	data_root alist(dpop(),this);
+	data_root alist(ctx->pop(),this);
 
 	cell count = array_capacity(alist.untagged());
 
 	if(count == 0)
 		return;
 
-	cell i;
-	for(i = 0; i < count; i++)
+	for(cell i = 0; i < count; i++)
 	{
 		data_root pair(array_nth(alist.untagged(),i),this);
 
@@ -168,7 +118,7 @@ void factor_vm::primitive_modify_code_heap()
 		case ARRAY_TYPE:
 			{
 				array *compiled_data = data.as().untagged();
-				cell owner = array_nth(compiled_data,0);
+				cell parameters = array_nth(compiled_data,0);
 				cell literals = array_nth(compiled_data,1);
 				cell relocation = array_nth(compiled_data,2);
 				cell labels = array_nth(compiled_data,3);
@@ -178,8 +128,9 @@ void factor_vm::primitive_modify_code_heap()
 					code_block_optimized,
 					code,
 					labels,
-					owner,
+					word.value(),
 					relocation,
+					parameters,
 					literals);
 
 				word->code = compiled;
@@ -190,7 +141,7 @@ void factor_vm::primitive_modify_code_heap()
 			break;
 		}
 
-		update_word_xt(word.untagged());
+		update_word_entry_point(word.untagged());
 	}
 
 	update_code_heap_words();
@@ -212,7 +163,7 @@ code_heap_room factor_vm::code_room()
 void factor_vm::primitive_code_room()
 {
 	code_heap_room room = code_room();
-	dpush(tag(byte_array_from_value(&room)));
+	ctx->push(tag(byte_array_from_value(&room)));
 }
 
 struct stack_trace_stripper {
@@ -227,7 +178,7 @@ struct stack_trace_stripper {
 void factor_vm::primitive_strip_stack_traces()
 {
 	stack_trace_stripper stripper;
-	iterate_code_heap(stripper);
+	each_code_block(stripper);
 }
 
 }
diff --git a/vm/code_heap.hpp b/vm/code_heap.hpp
index 8f4790d2f9..78ffa6c76a 100755
--- a/vm/code_heap.hpp
+++ b/vm/code_heap.hpp
@@ -8,8 +8,10 @@ struct code_heap {
 	/* Memory allocator */
 	free_list_allocator *allocator;
 
-	/* Set of blocks which need full relocation. */
-	std::set needs_fixup;
+	/* Keys are blocks which need to be initialized by initialize_code_block().
+	Values are literal tables. Literal table arrays are GC roots until the
+	time the block is initialized, after which point they are discarded. */
+	std::map uninitialized_blocks;
 
 	/* Code blocks which may reference objects in the nursery */
 	std::set points_to_nursery;
@@ -21,11 +23,12 @@ struct code_heap {
 	~code_heap();
 	void write_barrier(code_block *compiled);
 	void clear_remembered_set();
-	bool needs_fixup_p(code_block *compiled);
+	bool uninitialized_p(code_block *compiled);
 	bool marked_p(code_block *compiled);
 	void set_marked_p(code_block *compiled);
 	void clear_mark_bits();
-	void code_heap_free(code_block *compiled);
+	void free(code_block *compiled);
+	void flush_icache();
 };
 
 struct code_heap_room {
diff --git a/vm/collector.hpp b/vm/collector.hpp
index 29711aeb9c..ece4926c28 100644
--- a/vm/collector.hpp
+++ b/vm/collector.hpp
@@ -1,12 +1,12 @@
 namespace factor
 {
 
-template struct collector_workhorse {
+template struct data_workhorse {
 	factor_vm *parent;
 	TargetGeneration *target;
 	Policy policy;
 
-	explicit collector_workhorse(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
+	explicit data_workhorse(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
 		parent(parent_),
 		target(target_),
 		policy(policy_) {}
@@ -16,11 +16,10 @@ template struct collector_workhorse
 		parent->check_data_pointer(untagged);
 
 		/* is there another forwarding pointer? */
-		while(untagged->h.forwarding_pointer_p())
-			untagged = untagged->h.forwarding_pointer();
+		while(untagged->forwarding_pointer_p())
+			untagged = untagged->forwarding_pointer();
 
 		/* we've found the destination */
-		untagged->h.check_header();
 		return untagged;
 	}
 
@@ -32,7 +31,7 @@ template struct collector_workhorse
 		if(!newpointer) longjmp(parent->current_gc->gc_unwind,1);
 
 		memcpy(newpointer,untagged,size);
-		untagged->h.forward_to(newpointer);
+		untagged->forward_to(newpointer);
 
 		policy.promoted_object(newpointer);
 
@@ -62,13 +61,13 @@ template struct collector_workhorse
 };
 
 template
-inline static slot_visitor > make_collector_workhorse(
+inline static slot_visitor > make_data_visitor(
 	factor_vm *parent,
 	TargetGeneration *target,
 	Policy policy)
 {
-	return slot_visitor >(parent,
-		collector_workhorse(parent,target,policy));
+	return slot_visitor >(parent,
+		data_workhorse(parent,target,policy));
 }
 
 struct dummy_unmarker {
@@ -86,12 +85,13 @@ struct full_unmarker {
 	void operator()(card *ptr) { *ptr = 0; }
 };
 
-template struct collector {
+template
+struct collector {
 	factor_vm *parent;
 	data_heap *data;
 	code_heap *code;
 	TargetGeneration *target;
-	slot_visitor > workhorse;
+	slot_visitor > data_visitor;
 	cell cards_scanned;
 	cell decks_scanned;
 	cell code_blocks_scanned;
@@ -101,37 +101,41 @@ template struct collector {
 		data(parent_->data),
 		code(parent_->code),
 		target(target_),
-		workhorse(make_collector_workhorse(parent_,target_,policy_)),
+		data_visitor(make_data_visitor(parent_,target_,policy_)),
 		cards_scanned(0),
 		decks_scanned(0),
 		code_blocks_scanned(0) {}
 
 	void trace_handle(cell *handle)
 	{
-		workhorse.visit_handle(handle);
+		data_visitor.visit_handle(handle);
 	}
 
 	void trace_object(object *ptr)
 	{
-		workhorse.visit_slots(ptr);
-		if(ptr->h.hi_tag() == ALIEN_TYPE)
+		data_visitor.visit_slots(ptr);
+		if(ptr->type() == ALIEN_TYPE)
 			((alien *)ptr)->update_address();
 	}
 
 	void trace_roots()
 	{
-		workhorse.visit_roots();
+		data_visitor.visit_roots();
 	}
 
 	void trace_contexts()
 	{
-		workhorse.visit_contexts();
+		data_visitor.visit_contexts();
 	}
 
-	/* Trace all literals referenced from a code block. Only for aging and nursery collections */
-	void trace_literal_references(code_block *compiled)
+	void trace_code_block_objects(code_block *compiled)
 	{
-		workhorse.visit_literal_references(compiled);
+		data_visitor.visit_code_block_objects(compiled);
+	}
+
+	void trace_embedded_literals(code_block *compiled)
+	{
+		data_visitor.visit_embedded_literals(compiled);
 	}
 
 	void trace_code_heap_roots(std::set *remembered_set)
@@ -141,7 +145,10 @@ template struct collector {
 
 		for(; iter != end; iter++)
 		{
-			trace_literal_references(*iter);
+			code_block *compiled = *iter;
+			trace_code_block_objects(compiled);
+			trace_embedded_literals(compiled);
+			compiled->flush_icache();
 			code_blocks_scanned++;
 		}
 	}
@@ -183,11 +190,8 @@ template struct collector {
 			cell *slot_ptr = (cell *)start;
 			cell *end_ptr = (cell *)end;
 
-			if(slot_ptr != end_ptr)
-			{
-				for(; slot_ptr < end_ptr; slot_ptr++)
-					workhorse.visit_handle(slot_ptr);
-			}
+			for(; slot_ptr < end_ptr; slot_ptr++)
+				data_visitor.visit_handle(slot_ptr);
 		}
 	}
 
@@ -196,14 +200,14 @@ template struct collector {
 	{
 		card_deck *decks = data->decks;
 		card_deck *cards = data->cards;
-	
+
 		cell gen_start_card = addr_to_card(gen->start - data->start);
 
 		cell first_deck = card_deck_for_address(gen->start);
 		cell last_deck = card_deck_for_address(gen->end);
-	
+
 		cell start = 0, binary_start = 0, end = 0;
-	
+
 		for(cell deck_index = first_deck; deck_index < last_deck; deck_index++)
 		{
 			if(decks[deck_index] & mask)
@@ -212,7 +216,7 @@ template struct collector {
 
 				cell first_card = first_card_in_deck(deck_index);
 				cell last_card = last_card_in_deck(deck_index);
-	
+
 				for(cell card_index = first_card; card_index < last_card; card_index++)
 				{
 					if(cards[card_index] & mask)
@@ -225,13 +229,9 @@ template struct collector {
 							binary_start = start + ((object *)start)->binary_payload_start();
 							end = start + ((object *)start)->size();
 						}
-	
-#ifdef FACTOR_DEBUG
-						assert(addr_to_card(start - data->start) <= card_index);
-						assert(start < card_end_address(card_index));
-#endif
 
-scan_next_object:				{
+scan_next_object:				if(start < card_end_address(card_index))
+						{
 							trace_partial_objects(
 								start,
 								binary_start,
@@ -248,13 +248,13 @@ scan_next_object:				{
 								}
 							}
 						}
-	
+
 						unmarker(&cards[card_index]);
-	
+
 						if(!start) return;
 					}
 				}
-	
+
 				unmarker(&decks[deck_index]);
 			}
 		}
diff --git a/vm/compaction.cpp b/vm/compaction.cpp
index 10e37db263..5e52c70b0c 100644
--- a/vm/compaction.cpp
+++ b/vm/compaction.cpp
@@ -45,7 +45,7 @@ struct compaction_sizer {
 	{
 		if(!forwarding_map->marked_p(obj))
 			return forwarding_map->unmarked_block_size(obj);
-		else if(obj->h.hi_tag() == TUPLE_TYPE)
+		else if(obj->type() == TUPLE_TYPE)
 			return align(tuple_size_with_forwarding(forwarding_map,obj),data_alignment);
 		else
 			return obj->size();
@@ -54,52 +54,135 @@ struct compaction_sizer {
 
 struct object_compaction_updater {
 	factor_vm *parent;
-	slot_visitor > slot_forwarder;
-	code_block_visitor > code_forwarder;
+	mark_bits *code_forwarding_map;
 	mark_bits *data_forwarding_map;
 	object_start_map *starts;
 
 	explicit object_compaction_updater(factor_vm *parent_,
-		slot_visitor > slot_forwarder_,
-		code_block_visitor > code_forwarder_,
-		mark_bits *data_forwarding_map_) :
+		mark_bits *data_forwarding_map_,
+		mark_bits *code_forwarding_map_) :
 		parent(parent_),
-		slot_forwarder(slot_forwarder_),
-		code_forwarder(code_forwarder_),
+		code_forwarding_map(code_forwarding_map_),
 		data_forwarding_map(data_forwarding_map_),
 		starts(&parent->data->tenured->starts) {}
 
 	void operator()(object *old_address, object *new_address, cell size)
 	{
 		cell payload_start;
-		if(old_address->h.hi_tag() == TUPLE_TYPE)
+		if(old_address->type() == TUPLE_TYPE)
 			payload_start = tuple_size_with_forwarding(data_forwarding_map,old_address);
 		else
 			payload_start = old_address->binary_payload_start();
 
 		memmove(new_address,old_address,size);
 
+		slot_visitor > slot_forwarder(parent,forwarder(data_forwarding_map));
 		slot_forwarder.visit_slots(new_address,payload_start);
+
+		code_block_visitor > code_forwarder(parent,forwarder(code_forwarding_map));
 		code_forwarder.visit_object_code_block(new_address);
+
 		starts->record_object_start_offset(new_address);
 	}
 };
 
-template struct code_block_compaction_updater {
+template
+struct code_block_compaction_relocation_visitor {
 	factor_vm *parent;
-	SlotForwarder slot_forwarder;
+	code_block *old_address;
+	slot_visitor slot_forwarder;
+	code_block_visitor > code_forwarder;
 
-	explicit code_block_compaction_updater(factor_vm *parent_, SlotForwarder slot_forwarder_) :
-		parent(parent_), slot_forwarder(slot_forwarder_) {}
+	explicit code_block_compaction_relocation_visitor(factor_vm *parent_,
+		code_block *old_address_,
+		slot_visitor slot_forwarder_,
+		code_block_visitor > code_forwarder_) :
+		parent(parent_),
+		old_address(old_address_),
+		slot_forwarder(slot_forwarder_),
+		code_forwarder(code_forwarder_) {}
+
+	void operator()(instruction_operand op)
+	{
+		cell old_offset = op.rel_offset() + (cell)old_address->entry_point();
+
+		switch(op.rel_type())
+		{
+		case RT_LITERAL:
+			op.store_value(slot_forwarder.visit_pointer(op.load_value(old_offset)));
+			break;
+		case RT_ENTRY_POINT:
+		case RT_ENTRY_POINT_PIC:
+		case RT_ENTRY_POINT_PIC_TAIL:
+			op.store_code_block(code_forwarder.visit_code_block(op.load_code_block(old_offset)));
+			break;
+		case RT_HERE:
+			op.store_value(op.load_value(old_offset) - (cell)old_address + (cell)op.parent_code_block());
+			break;
+		case RT_THIS:
+		case RT_CARDS_OFFSET:
+		case RT_DECKS_OFFSET:
+			parent->store_external_address(op);
+			break;
+		default:
+			op.store_value(op.load_value(old_offset));
+			break;
+		}
+	}
+};
+
+template
+struct code_block_compaction_updater {
+	factor_vm *parent;
+	slot_visitor slot_forwarder;
+	code_block_visitor > code_forwarder;
+
+	explicit code_block_compaction_updater(factor_vm *parent_,
+		slot_visitor slot_forwarder_,
+		code_block_visitor > code_forwarder_) :
+		parent(parent_),
+		slot_forwarder(slot_forwarder_),
+		code_forwarder(code_forwarder_) {}
 
 	void operator()(code_block *old_address, code_block *new_address, cell size)
 	{
 		memmove(new_address,old_address,size);
-		slot_forwarder.visit_literal_references(new_address);
-		parent->relocate_code_block(new_address);
+
+		slot_forwarder.visit_code_block_objects(new_address);
+
+		code_block_compaction_relocation_visitor visitor(parent,old_address,slot_forwarder,code_forwarder);
+		new_address->each_instruction_operand(visitor);
 	}
 };
 
+/* After a compaction, invalidate any code heap roots which are not
+marked, and also slide the valid roots up so that call sites can be updated
+correctly in case an inline cache compilation triggered compaction. */
+void factor_vm::update_code_roots_for_compaction()
+{
+	std::vector::const_iterator iter = code_roots.begin();
+	std::vector::const_iterator end = code_roots.end();
+
+	mark_bits *state = &code->allocator->state;
+
+	for(; iter < end; iter++)
+	{
+		code_root *root = *iter;
+		code_block *block = (code_block *)(root->value & (~data_alignment + 1));
+
+		/* Offset of return address within 16-byte allocation line */
+		cell offset = root->value - (cell)block;
+
+		if(root->valid && state->marked_p(block))
+		{
+			block = state->forward_block(block);
+			root->value = (cell)block + offset;
+		}
+		else
+			root->valid = false;
+	}
+}
+
 /* Compact data and code heaps */
 void factor_vm::collect_compact_impl(bool trace_contexts_p)
 {
@@ -116,18 +199,20 @@ void factor_vm::collect_compact_impl(bool trace_contexts_p)
 	slot_visitor > slot_forwarder(this,forwarder(data_forwarding_map));
 	code_block_visitor > code_forwarder(this,forwarder(code_forwarding_map));
 
+	code_forwarder.visit_uninitialized_code_blocks();
+
 	/* Object start offsets get recomputed by the object_compaction_updater */
 	data->tenured->starts.clear_object_start_offsets();
 
 	/* Slide everything in tenured space up, and update data and code heap
 	pointers inside objects. */
-	object_compaction_updater object_updater(this,slot_forwarder,code_forwarder,data_forwarding_map);
+	object_compaction_updater object_updater(this,data_forwarding_map,code_forwarding_map);
 	compaction_sizer object_sizer(data_forwarding_map);
 	tenured->compact(object_updater,object_sizer);
 
 	/* Slide everything in the code heap up, and update data and code heap
 	pointers inside code blocks. */
-	code_block_compaction_updater > > code_block_updater(this,slot_forwarder);
+	code_block_compaction_updater > code_block_updater(this,slot_forwarder,code_forwarder);
 	standard_sizer code_block_sizer;
 	code->allocator->compact(code_block_updater,code_block_sizer);
 
@@ -136,56 +221,75 @@ void factor_vm::collect_compact_impl(bool trace_contexts_p)
 	{
 		slot_forwarder.visit_contexts();
 		code_forwarder.visit_context_code_blocks();
-		code_forwarder.visit_callback_code_blocks();
 	}
 
 	update_code_roots_for_compaction();
+	callbacks->update();
 
 	current_gc->event->ended_compaction();
 }
 
-struct object_code_block_updater {
-	code_block_visitor > *visitor;
+struct object_grow_heap_updater {
+	code_block_visitor > code_forwarder;
 
-	explicit object_code_block_updater(code_block_visitor > *visitor_) :
-		visitor(visitor_) {}
+	explicit object_grow_heap_updater(code_block_visitor > code_forwarder_) :
+		code_forwarder(code_forwarder_) {}
 
-	void operator()(cell obj)
+	void operator()(object *obj)
 	{
-		visitor->visit_object_code_block(tagged(obj).untagged());
+		code_forwarder.visit_object_code_block(obj);
 	}
 };
 
 struct dummy_slot_forwarder {
-	void visit_literal_references(code_block *compiled) {}
+	object *operator()(object *obj) { return obj; }
 };
 
-/* Compact just the code heap */
+/* Compact just the code heap, after growing the data heap */
 void factor_vm::collect_compact_code_impl(bool trace_contexts_p)
 {
 	/* Figure out where blocks are going to go */
 	mark_bits *code_forwarding_map = &code->allocator->state;
 	code_forwarding_map->compute_forwarding();
+
+	slot_visitor slot_forwarder(this,dummy_slot_forwarder());
 	code_block_visitor > code_forwarder(this,forwarder(code_forwarding_map));
 
+	code_forwarder.visit_uninitialized_code_blocks();
+
 	if(trace_contexts_p)
-	{
 		code_forwarder.visit_context_code_blocks();
-		code_forwarder.visit_callback_code_blocks();
-	}
 
 	/* Update code heap references in data heap */
-	object_code_block_updater updater(&code_forwarder);
+	object_grow_heap_updater updater(code_forwarder);
 	each_object(updater);
 
 	/* Slide everything in the code heap up, and update code heap
 	pointers inside code blocks. */
-	dummy_slot_forwarder slot_forwarder;
-	code_block_compaction_updater code_block_updater(this,slot_forwarder);
+	code_block_compaction_updater code_block_updater(this,slot_forwarder,code_forwarder);
 	standard_sizer code_block_sizer;
 	code->allocator->compact(code_block_updater,code_block_sizer);
 
 	update_code_roots_for_compaction();
+	callbacks->update();
+}
+
+void factor_vm::collect_compact(bool trace_contexts_p)
+{
+	collect_mark_impl(trace_contexts_p);
+	collect_compact_impl(trace_contexts_p);
+	code->flush_icache();
+}
+
+void factor_vm::collect_growing_heap(cell requested_bytes, bool trace_contexts_p)
+{
+	/* Grow the data heap and copy all live objects to the new heap. */
+	data_heap *old = data;
+	set_data_heap(data->grow(requested_bytes));
+	collect_mark_impl(trace_contexts_p);
+	collect_compact_code_impl(trace_contexts_p);
+	code->flush_icache();
+	delete old;
 }
 
 }
diff --git a/vm/contexts.cpp b/vm/contexts.cpp
index 7af7fdaa57..394d14e55d 100644
--- a/vm/contexts.cpp
+++ b/vm/contexts.cpp
@@ -3,33 +3,19 @@
 namespace factor
 {
 
-void factor_vm::reset_datastack()
+context::context(cell ds_size, cell rs_size) :
+	callstack_top(NULL),
+	callstack_bottom(NULL),
+	datastack(0),
+	retainstack(0),
+	datastack_region(new segment(ds_size,false)),
+	retainstack_region(new segment(rs_size,false)),
+	catchstack_save(0),
+	current_callback_save(0),
+	next(NULL)
 {
-	ds = ds_bot - sizeof(cell);
-}
-
-void factor_vm::reset_retainstack()
-{
-	rs = rs_bot - sizeof(cell);
-}
-
-static const cell stack_reserved = (64 * sizeof(cell));
-
-void factor_vm::fix_stacks()
-{
-	if(ds + sizeof(cell) < ds_bot || ds + stack_reserved >= ds_top) reset_datastack();
-	if(rs + sizeof(cell) < rs_bot || rs + stack_reserved >= rs_top) reset_retainstack();
-}
-
-/* called before entry into foreign C code. Note that ds and rs might
-be stored in registers, so callbacks must save and restore the correct values */
-void factor_vm::save_stacks()
-{
-	if(ctx)
-	{
-		ctx->datastack = ds;
-		ctx->retainstack = rs;
-	}
+	reset_datastack();
+	reset_retainstack();
 }
 
 context *factor_vm::alloc_context()
@@ -42,11 +28,7 @@ context *factor_vm::alloc_context()
 		unused_contexts = unused_contexts->next;
 	}
 	else
-	{
-		new_context = new context;
-		new_context->datastack_region = new segment(ds_size,false);
-		new_context->retainstack_region = new segment(rs_size,false);
-	}
+		new_context = new context(ds_size,rs_size);
 
 	return new_context;
 }
@@ -58,50 +40,32 @@ void factor_vm::dealloc_context(context *old_context)
 }
 
 /* called on entry into a compiled callback */
-void factor_vm::nest_stacks(stack_frame *magic_frame)
+void factor_vm::nest_stacks()
 {
 	context *new_ctx = alloc_context();
 
 	new_ctx->callstack_bottom = (stack_frame *)-1;
 	new_ctx->callstack_top = (stack_frame *)-1;
 
-	/* note that these register values are not necessarily valid stack
-	pointers. they are merely saved non-volatile registers, and are
-	restored in unnest_stacks(). consider this scenario:
-	- factor code calls C function
-	- C function saves ds/cs registers (since they're non-volatile)
-	- C function clobbers them
-	- C function calls Factor callback
-	- Factor callback returns
-	- C function restores registers
-	- C function returns to Factor code */
-	new_ctx->datastack_save = ds;
-	new_ctx->retainstack_save = rs;
-
-	new_ctx->magic_frame = magic_frame;
-
 	/* save per-callback special_objects */
 	new_ctx->current_callback_save = special_objects[OBJ_CURRENT_CALLBACK];
 	new_ctx->catchstack_save = special_objects[OBJ_CATCHSTACK];
 
+	new_ctx->reset_datastack();
+	new_ctx->reset_retainstack();
+
 	new_ctx->next = ctx;
 	ctx = new_ctx;
-
-	reset_datastack();
-	reset_retainstack();
 }
 
-void nest_stacks(stack_frame *magic_frame, factor_vm *parent)
+void nest_stacks(factor_vm *parent)
 {
-	return parent->nest_stacks(magic_frame);
+	return parent->nest_stacks();
 }
 
 /* called when leaving a compiled callback */
 void factor_vm::unnest_stacks()
 {
-	ds = ctx->datastack_save;
-	rs = ctx->retainstack_save;
-
 	/* restore per-callback special_objects */
 	special_objects[OBJ_CURRENT_CALLBACK] = ctx->current_callback_save;
 	special_objects[OBJ_CATCHSTACK] = ctx->catchstack_save;
@@ -135,20 +99,20 @@ bool factor_vm::stack_to_array(cell bottom, cell top)
 	{
 		array *a = allot_uninitialized_array(depth / sizeof(cell));
 		memcpy(a + 1,(void*)bottom,depth);
-		dpush(tag(a));
+		ctx->push(tag(a));
 		return true;
 	}
 }
 
 void factor_vm::primitive_datastack()
 {
-	if(!stack_to_array(ds_bot,ds))
+	if(!stack_to_array(ctx->datastack_region->start,ctx->datastack))
 		general_error(ERROR_DS_UNDERFLOW,false_object,false_object,NULL);
 }
 
 void factor_vm::primitive_retainstack()
 {
-	if(!stack_to_array(rs_bot,rs))
+	if(!stack_to_array(ctx->retainstack_region->start,ctx->retainstack))
 		general_error(ERROR_RS_UNDERFLOW,false_object,false_object,NULL);
 }
 
@@ -162,38 +126,48 @@ cell factor_vm::array_to_stack(array *array, cell bottom)
 
 void factor_vm::primitive_set_datastack()
 {
-	ds = array_to_stack(untag_check(dpop()),ds_bot);
+	ctx->datastack = array_to_stack(untag_check(ctx->pop()),ctx->datastack_region->start);
 }
 
 void factor_vm::primitive_set_retainstack()
 {
-	rs = array_to_stack(untag_check(dpop()),rs_bot);
+	ctx->retainstack = array_to_stack(untag_check(ctx->pop()),ctx->retainstack_region->start);
 }
 
 /* Used to implement call( */
 void factor_vm::primitive_check_datastack()
 {
-	fixnum out = to_fixnum(dpop());
-	fixnum in = to_fixnum(dpop());
+	fixnum out = to_fixnum(ctx->pop());
+	fixnum in = to_fixnum(ctx->pop());
 	fixnum height = out - in;
-	array *saved_datastack = untag_check(dpop());
+	array *saved_datastack = untag_check(ctx->pop());
 	fixnum saved_height = array_capacity(saved_datastack);
-	fixnum current_height = (ds - ds_bot + sizeof(cell)) / sizeof(cell);
+	fixnum current_height = (ctx->datastack - ctx->datastack_region->start + sizeof(cell)) / sizeof(cell);
 	if(current_height - height != saved_height)
-		dpush(false_object);
+		ctx->push(false_object);
 	else
 	{
-		fixnum i;
-		for(i = 0; i < saved_height - in; i++)
+		cell *ds_bot = (cell *)ctx->datastack_region->start;
+		for(fixnum i = 0; i < saved_height - in; i++)
 		{
-			if(((cell *)ds_bot)[i] != array_nth(saved_datastack,i))
+			if(ds_bot[i] != array_nth(saved_datastack,i))
 			{
-				dpush(false_object);
+				ctx->push(false_object);
 				return;
 			}
 		}
-		dpush(true_object);
+		ctx->push(true_object);
 	}
 }
 
+void factor_vm::primitive_load_locals()
+{
+	fixnum count = untag_fixnum(ctx->pop());
+	memcpy((cell *)(ctx->retainstack + sizeof(cell)),
+		(cell *)(ctx->datastack - sizeof(cell) * (count - 1)),
+		sizeof(cell) * count);
+	ctx->datastack -= sizeof(cell) * count;
+	ctx->retainstack += sizeof(cell) * count;
+}
+
 }
diff --git a/vm/contexts.hpp b/vm/contexts.hpp
index aa6f9ec8ce..9ba9bb313c 100644
--- a/vm/contexts.hpp
+++ b/vm/contexts.hpp
@@ -1,11 +1,7 @@
 namespace factor
 {
 
-/* Assembly code makes assumptions about the layout of this struct:
-   - callstack_top field is 0
-   - callstack_bottom field is 1
-   - datastack field is 2
-   - retainstack field is 3 */
+/* Assembly code makes assumptions about the layout of this struct */
 struct context {
 	/* C stack pointer on entry */
 	stack_frame *callstack_top;
@@ -17,24 +13,6 @@ struct context {
 	/* current retain stack top pointer */
 	cell retainstack;
 
-	/* saved contents of ds register on entry to callback */
-	cell datastack_save;
-
-	/* saved contents of rs register on entry to callback */
-	cell retainstack_save;
-
-	/* callback-bottom stack frame, or NULL for top-level context.
-	When nest_stacks() is called, callstack layout with callbacks
-	is as follows:
-	
-	[ C function ]
-	[ callback stub in code heap ] <-- this is the magic frame
-	[ native frame: c_to_factor() ]
-	[ callback quotation frame ] <-- first call frame in call stack
-	
-	magic frame is retained so that it's XT can be traced and forwarded. */
-	stack_frame *magic_frame;
-
 	/* memory region holding current datastack */
 	segment *datastack_region;
 
@@ -46,18 +24,57 @@ struct context {
 	cell current_callback_save;
 
 	context *next;
+
+	context(cell ds_size, cell rs_size);
+
+	cell peek()
+	{
+		return *(cell *)datastack;
+	}
+
+	void replace(cell tagged)
+	{
+		*(cell *)datastack = tagged;
+	}
+
+	cell pop()
+	{
+		cell value = peek();
+		datastack -= sizeof(cell);
+		return value;
+	}
+
+	void push(cell tagged)
+	{
+		datastack += sizeof(cell);
+		replace(tagged);
+	}
+
+	void reset_datastack()
+	{
+		datastack = datastack_region->start - sizeof(cell);
+	}
+
+	void reset_retainstack()
+	{
+		retainstack = retainstack_region->start - sizeof(cell);
+	}
+
+	static const cell stack_reserved = (64 * sizeof(cell));
+
+	void fix_stacks()
+	{
+		if(datastack + sizeof(cell) < datastack_region->start
+			|| datastack + stack_reserved >= datastack_region->end)
+			reset_datastack();
+
+		if(retainstack + sizeof(cell) < retainstack_region->start
+			|| retainstack + stack_reserved >= retainstack_region->end)
+			reset_retainstack();
+	}
 };
 
-#define ds_bot (ctx->datastack_region->start)
-#define ds_top (ctx->datastack_region->end)
-#define rs_bot (ctx->retainstack_region->start)
-#define rs_top (ctx->retainstack_region->end)
-
-DEFPUSHPOP(d,ds)
-DEFPUSHPOP(r,rs)
-
-VM_C_API void nest_stacks(stack_frame *magic_frame, factor_vm *vm);
+VM_C_API void nest_stacks(factor_vm *vm);
 VM_C_API void unnest_stacks(factor_vm *vm);
 
 }
-
diff --git a/vm/cpu-arm.S b/vm/cpu-arm.S
deleted file mode 100644
index 09e3331b99..0000000000
--- a/vm/cpu-arm.S
+++ /dev/null
@@ -1,127 +0,0 @@
-#include "asm.h"
-
-/* Note that the XT is passed to the quotation in r12 */
-#define CALL_QUOT \
-        ldr r12,[r0, #9]     /* load quotation-xt slot */ ; \
-	mov lr,pc ; \
-        mov pc,r12
-
-#define JUMP_QUOT \
-        ldr r12,[r0, #9]     /* load quotation-xt slot */ ; \
-	mov pc,r12
-
-#define SAVED_REGS_SIZE 32
-
-#define FRAME (RESERVED_SIZE + SAVED_REGS_SIZE + 8)
-
-#define LR_SAVE [sp, #-4]
-#define RESERVED_SIZE 8
-
-#define SAVE_LR str lr,LR_SAVE
-
-#define LOAD_LR ldr lr,LR_SAVE
-
-#define SAVE_AT(offset) (RESERVED_SIZE + 4 * offset)
-
-#define SAVE(register,offset) str register,[sp, #SAVE_AT(offset)]
-
-#define RESTORE(register,offset) ldr register,[sp, #SAVE_AT(offset)]
-
-#define PROLOGUE \
-	SAVE_LR ; \
-	sub sp,sp,#FRAME
-
-#define EPILOGUE \
-	add sp,sp,#FRAME ; \
-	LOAD_LR
-
-DEF(void,c_to_factor,(CELL quot)):
-        PROLOGUE
-
-	SAVE(r4,0)           /* save GPRs */
-                             /* don't save ds pointer */
-                             /* don't save rs pointer */
-        SAVE(r7,3)
-        SAVE(r8,4)
-        SAVE(r9,5)
-        SAVE(r10,6)
-        SAVE(r11,7)
-	SAVE(r0,8)           /* save quotation since we're about to mangle it */
-
-        sub r0,sp,#4         /* pass call stack pointer as an argument */
-	bl MANGLE(save_callstack_bottom)
-
-	RESTORE(r0,8)        /* restore quotation */
-        CALL_QUOT
-
-        RESTORE(r11,7)       /* restore GPRs */
-        RESTORE(r10,6)
-        RESTORE(r9,5)
-        RESTORE(r8,4)
-        RESTORE(r7,3)
-                             /* don't restore rs pointer */
-                             /* don't restore ds pointer */
-        RESTORE(r4,0)
-
-        EPILOGUE
-        mov pc,lr
-
-/* The JIT compiles an 'mov r1',sp in front of every primitive call, since a
-word which was defined as a primitive will not change its definition for the
-lifetime of the image -- adding new primitives requires a bootstrap. However,
-an undefined word can certainly become defined,
-
-DEFER: foo
-...
-: foo ... ;
-
-And calls to non-primitives do not have this one-instruction prologue, so we
-set the XT of undefined words to this symbol. */
-DEF(void,undefined,(CELL word)):
-	sub r1,sp,#4
-	b MANGLE(undefined_error)
-
-/* Here we have two entry points. The first one is taken when profiling is
-enabled */
-DEF(void,docol_profiling,(CELL word)):
-        ldr r1,[r0, #25]     /* load profile-count slot */
-        add r1,r1,#8         /* increment count */
-        str r1,[r0, #25]     /* store profile-count slot */
-DEF(void,docol,(CELL word)):
-        ldr r0,[r0, #13]     /* load word-def slot */
-        JUMP_QUOT
-
-/* We must pass the XT to the quotation in r12. */
-DEF(void,primitive_call,(void)):
-        ldr r0,[r5], #-4     /* load quotation from data stack */
-        JUMP_QUOT
-
-/* We must preserve r1 here in case we're calling a primitive */
-DEF(void,primitive_execute,(void)):
-        ldr r0,[r5], #-4     /* load word from data stack */
-        ldr pc,[r0, #29]     /* jump to word-xt */
-
-DEF(void,set_callstack,(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length)):
-        sub sp,r0,r2         /* compute new stack pointer */
-        mov r0,sp            /* start of destination of memcpy() */
-	sub sp,sp,#12        /* alignment */
-        bl MANGLE(memcpy)    /* go */
-	add sp,sp,#16        /* point SP at innermost frame */
-        ldr pc,LR_SAVE       /* return */
-
-DEF(void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to)):
-	add sp,r1,#4         /* compute new stack pointer */
-	ldr lr,LR_SAVE       /* we have rewound the stack; load return address */
-	JUMP_QUOT            /* call the quotation */
-
-DEF(void,lazy_jit_compile,(CELL quot)):
-	mov r1,sp            /* save stack pointer */
-	PROLOGUE
-	bl MANGLE(lazy_jit_compile_impl)
-	EPILOGUE
-        JUMP_QUOT            /* call the quotation */
-
-#ifdef WINCE
-	.section .drectve
-	.ascii " -export:c_to_factor"
-#endif
diff --git a/vm/cpu-arm.hpp b/vm/cpu-arm.hpp
index b08e76382c..e725c6d596 100644
--- a/vm/cpu-arm.hpp
+++ b/vm/cpu-arm.hpp
@@ -3,14 +3,6 @@ namespace factor
 
 #define FACTOR_CPU_STRING "arm"
 
-register cell ds asm("r5");
-register cell rs asm("r6");
-
 #define FRAME_RETURN_ADDRESS(frame,vm) *(XT *)(vm->frame_successor(frame) + 1)
 
-void c_to_factor(cell quot);
-void set_callstack(stack_frame *to, stack_frame *from, cell length, void *memcpy);
-void throw_impl(cell quot, stack_frame *rewind);
-void lazy_jit_compile(cell quot);
-
 }
diff --git a/vm/cpu-ppc.S b/vm/cpu-ppc.S
index 40f2521e50..835ed14cc2 100644
--- a/vm/cpu-ppc.S
+++ b/vm/cpu-ppc.S
@@ -1,344 +1,73 @@
-/* Parts of this file were snarfed from SBCL src/runtime/ppc-assem.S, which is
-in the public domain. */
-#include "asm.h"
-
-#define DS_REG r13
-
-DEF(void,primitive_fixnum_add,(void *vm)):
-	mr r5,r3  /* save vm ptr for overflow */
-	lwz r3,0(DS_REG)
-	lwz r4,-4(DS_REG)
-	subi DS_REG,DS_REG,4
-	li r0,0
-	mtxer r0
-	addo. r6,r3,r4
-	bso add_overflow
-	stw r6,0(DS_REG)
-	blr
-add_overflow:
-	b MANGLE(overflow_fixnum_add)
-
-DEF(void,primitive_fixnum_subtract,(void *vm)):
-	mr r5,r3  /* save vm ptr for overflow */
-	lwz r3,-4(DS_REG)
-	lwz r4,0(DS_REG)
-	subi DS_REG,DS_REG,4
-	li r0,0
-	mtxer r0
-	subfo. r6,r4,r3
-	bso sub_overflow
-	stw r6,0(DS_REG)
-	blr
-sub_overflow:
-	b MANGLE(overflow_fixnum_subtract)
-
-DEF(void,primitive_fixnum_multiply,(void *vm)):
-	mr r5,r3  /* save vm ptr for overflow */
-	lwz r3,0(DS_REG)
-	lwz r4,-4(DS_REG)
-	subi DS_REG,DS_REG,4
-	srawi r3,r3,4
-	mullwo. r6,r3,r4
-	bso multiply_overflow
-	stw r6,0(DS_REG)
-	blr
-multiply_overflow:
-	srawi r4,r4,4
-	b MANGLE(overflow_fixnum_multiply)
-	
-/* Note that the XT is passed to the quotation in r11 */
-#define CALL_OR_JUMP_QUOT \
-	lwz r11,12(r3)	   /* load quotation-xt slot */ XX \
-
-#define CALL_QUOT \
-	CALL_OR_JUMP_QUOT XX \
-	mtlr r11	   /* prepare to call XT with quotation in r3 */ XX \
-	blrl		   /* go */
-
-#define JUMP_QUOT \
-	CALL_OR_JUMP_QUOT XX \
-	mtctr r11	   /* prepare to call XT with quotation in r3 */ XX \
-	bctr		   /* go */
-
-#define PARAM_SIZE 32
-
-#define SAVED_INT_REGS_SIZE 96
-
-#define SAVED_FP_REGS_SIZE 144
-
-#define SAVED_V_REGS_SIZE 208
-
-#define FRAME (RESERVED_SIZE + PARAM_SIZE + SAVED_INT_REGS_SIZE + SAVED_FP_REGS_SIZE + SAVED_V_REGS_SIZE + 8)
-   
-#if defined( __APPLE__)
-	#define LR_SAVE 8
-	#define RESERVED_SIZE 24
+#if defined(__APPLE__)
+    #define MANGLE(sym) _##sym
+    #define XX @
 #else
-	#define LR_SAVE 4
-	#define RESERVED_SIZE 8
+    #define MANGLE(sym) sym
+    #define XX ;
 #endif
 
-#define SAVE_LR(reg) stw reg,(LR_SAVE + FRAME)(r1)
-
-#define LOAD_LR(reg) lwz reg,(LR_SAVE + FRAME)(r1)
-
-#define SAVE_AT(offset) (RESERVED_SIZE + PARAM_SIZE + 4 * offset)
-
-#define SAVE_INT(register,offset) stw register,SAVE_AT(offset)(r1)
-#define RESTORE_INT(register,offset) lwz register,SAVE_AT(offset)(r1)
-
-#define SAVE_FP(register,offset) stfd register,SAVE_AT(offset)(r1)
-#define RESTORE_FP(register,offset) lfd register,SAVE_AT(offset)(r1)
-
-#define SAVE_V(register,offset) \
-	li r2,SAVE_AT(offset) XX \
-	stvxl register,r2,r1
-
-#define RESTORE_V(register,offset) \
-	li r2,SAVE_AT(offset) XX \
-	lvxl register,r2,r1
-
-#define PROLOGUE \
-	mflr r0 XX	   /* get caller's return address */ \
-	stwu r1,-FRAME(r1) XX /* create a stack frame to hold non-volatile registers */ \
-	SAVE_LR(r0)
-
-#define EPILOGUE \
-	LOAD_LR(r0) XX \
-	lwz r1,0(r1) XX	   /* destroy the stack frame */ \
-	mtlr r0		   /* get ready to return */
-
-/* We have to save and restore nonvolatile registers because
-the Factor compiler treats the entire register file as volatile. */
-DEF(void,c_to_factor,(cell quot, void *vm)):
-	PROLOGUE
-
-	SAVE_INT(r15,0)	   /* save GPRs */
-	SAVE_INT(r16,1)
-	SAVE_INT(r17,2)
-	SAVE_INT(r18,3)
-	SAVE_INT(r19,4)
-	SAVE_INT(r20,5)
-	SAVE_INT(r21,6)
-	SAVE_INT(r22,7)
-	SAVE_INT(r23,8)
-	SAVE_INT(r24,9)
-	SAVE_INT(r25,10)
-	SAVE_INT(r26,11)
-	SAVE_INT(r27,12)
-	SAVE_INT(r28,13)
-	SAVE_INT(r29,14)
-	SAVE_INT(r30,15)
-	SAVE_INT(r31,16)
-
-	SAVE_FP(f14,20)	/* save FPRs */
-	SAVE_FP(f15,22)
-	SAVE_FP(f16,24)
-	SAVE_FP(f17,26)
-	SAVE_FP(f18,28)
-	SAVE_FP(f19,30)
-	SAVE_FP(f20,32)
-	SAVE_FP(f21,34)
-	SAVE_FP(f22,36)
-	SAVE_FP(f23,38)
-	SAVE_FP(f24,40)
-	SAVE_FP(f25,42)
-	SAVE_FP(f26,44)
-	SAVE_FP(f27,46)
-	SAVE_FP(f28,48)
-	SAVE_FP(f29,50)
-	SAVE_FP(f30,52)
-	SAVE_FP(f31,54)
-
-        SAVE_V(v20,56)
-        SAVE_V(v21,60)
-        SAVE_V(v22,64)
-        SAVE_V(v23,68)
-        SAVE_V(v24,72)
-        SAVE_V(v25,76)
-        SAVE_V(v26,80)
-        SAVE_V(v27,84)
-        SAVE_V(v28,88)
-        SAVE_V(v29,92)
-        SAVE_V(v30,96)
-        SAVE_V(v31,100)
-
-	/* r4 vm ptr preserved */
-        mfvscr v0
-        li r2,SAVE_AT(104)
-        stvxl v0,r2,r1
-        addi r2,r2,0xc
-        lwzx r5,r2,r1
-        lis r6,0x1
-        andc r5,r5,r6
-        stwx r5,r2,r1
-        subi r2,r2,0xc
-        lvxl v0,r2,r1
-        mtvscr v0
-
-        /* save args in non-volatile regs */
-        mr r15,r3
-        mr r16,r4
-
-	/* pass call stack pointer as an argument */
-	mr r3,r1
-	bl MANGLE(save_callstack_bottom)
-
-	/* restore quotation args */
-	mr r3,r15
-	mr r4,r16
-	CALL_QUOT
-
-        RESTORE_V(v0,104)
-        mtvscr v0
-
-        RESTORE_V(v31,100)
-        RESTORE_V(v30,96)
-        RESTORE_V(v29,92)
-        RESTORE_V(v28,88)
-        RESTORE_V(v27,84)
-        RESTORE_V(v26,80)
-        RESTORE_V(v25,76)
-        RESTORE_V(v24,72)
-        RESTORE_V(v23,68)
-        RESTORE_V(v22,64)
-        RESTORE_V(v21,60)
-        RESTORE_V(v20,56)
-
-        /* Restore FPRs */
-	RESTORE_FP(f31,54)
-	RESTORE_FP(f30,52)
-	RESTORE_FP(f29,50)
-	RESTORE_FP(f28,48)
-	RESTORE_FP(f27,46)
-	RESTORE_FP(f26,44)
-	RESTORE_FP(f25,42)
-	RESTORE_FP(f24,40)
-	RESTORE_FP(f23,38)
-	RESTORE_FP(f22,36)
-	RESTORE_FP(f21,34)
-	RESTORE_FP(f20,32)
-	RESTORE_FP(f19,30)
-	RESTORE_FP(f18,28)
-	RESTORE_FP(f17,26)
-	RESTORE_FP(f16,24)
-	RESTORE_FP(f15,22)
-	RESTORE_FP(f14,20)
-
-	/* restore GPRs */
-	RESTORE_INT(r31,16)   
-	RESTORE_INT(r30,15)
-	RESTORE_INT(r29,14)
-	RESTORE_INT(r28,13)
-	RESTORE_INT(r27,12)
-	RESTORE_INT(r26,11)
-	RESTORE_INT(r25,10)
-	RESTORE_INT(r24,9)
-	RESTORE_INT(r23,8)
-	RESTORE_INT(r22,7)
-	RESTORE_INT(r21,6)
-	RESTORE_INT(r20,5)
-	RESTORE_INT(r19,4)
-	RESTORE_INT(r18,3)
-	RESTORE_INT(r17,2)
-	RESTORE_INT(r16,1)
-	RESTORE_INT(r15,0)
-
-	EPILOGUE
-	blr
-
-/* We pass a function pointer to memcpy in r6 to work around a Mac OS X ABI
-limitation which would otherwise require us to do a bizzaro PC-relative
-trampoline to retrieve the function address */
-DEF(void,set_callstack,(F_STACK_FRAME *to, F_STACK_FRAME *from, cell length, void *memcpy)):
-	sub r1,r3,r5	   /* compute new stack pointer */
-	mr r3,r1	   /* start of destination of memcpy() */
-	stwu r1,-64(r1)	   /* setup fake stack frame for memcpy() */
-	mtlr r6		   /* prepare to call memcpy() */
-	blrl		   /* go */
-	lwz r1,0(r1)	   /* tear down fake stack frame */
-	lwz r0,LR_SAVE(r1) /* we have restored the stack; load return address */
-	mtlr r0		   /* prepare to return to restored callstack */
-	blr		   /* go */
-
-DEF(void,throw_impl,(cell quot, F_STACK_FRAME *rewind_to, void *vm)):
-	mr r1,r4	   /* compute new stack pointer */
-	mr r4,r5	   /* make vm ptr 2nd arg in case quot_xt = lazy_jit_compile */
-	lwz r0,LR_SAVE(r1) /* we have rewound the stack; load return address */
-	mtlr r0
-	JUMP_QUOT	   /* call the quotation */
-
-DEF(void,lazy_jit_compile,(cell quot, void *vm)):
-	mr r5,r4	   /* vm ptr is 3rd arg */
-	mr r4,r1	   /* save stack pointer */
-	PROLOGUE
-	bl MANGLE(lazy_jit_compile_impl)
-	EPILOGUE
-	JUMP_QUOT	   /* call the quotation */
+/* The returns and args are just for documentation */
+#define DEF(returns,symbol,args) .globl MANGLE(symbol) XX \
+MANGLE(symbol)
 
 /* Thanks to Joshua Grams for this code.
 
 On PowerPC processors, we must flush the instruction cache manually
 after writing to the code heap. */
 
-DEF(void,flush_icache,(void *start, int len)):
-	/* compute number of cache lines to flush */
-	add r4,r4,r3
-	clrrwi r3,r3,5	   /* align addr to next lower cache line boundary */
-	sub r4,r4,r3	   /* then n_lines = (len + 0x1f) / 0x20 */
-	addi r4,r4,0x1f
-	srwi. r4,r4,5	   /* note '.' suffix */
-	beqlr		   /* if n_lines == 0, just return. */
-	mtctr r4	   /* flush cache lines */
-0:	dcbf 0,r3	   /* for each line... */
-	sync
-	icbi 0,r3
-	addi r3,r3,0x20
-	bdnz 0b
-	sync		   /* finish up */
-	isync
-	blr
-
-DEF(void,primitive_inline_cache_miss,(void *vm)):
-	mflr r6
-DEF(void,primitive_inline_cache_miss_tail,(void *vm)):
-	PROLOGUE
-	mr r4,r3          /* vm ptr in 2nd arg */
-	mr r3,r6
-	bl MANGLE(inline_cache_miss)
-	EPILOGUE
-	mtctr r3
-	bctr
+DEF(void,flush_icache,(void*, int)):
+    /* compute number of cache lines to flush */
+    add r4,r4,r3
+    /* align addr to next lower cache line boundary */
+    clrrwi r3,r3,5
+    /* then n_lines = (len + 0x1f) / 0x20 */
+    sub r4,r4,r3
+    addi r4,r4,0x1f
+    /* note '.' suffix */
+    srwi. r4,r4,5
+    /* if n_lines == 0, just return. */
+    beqlr
+    /* flush cache lines */
+    mtctr r4
+    /* for each line... */
+0:  dcbf 0,r3
+    sync
+    icbi 0,r3
+    addi r3,r3,0x20
+    bdnz 0b
+    /* finish up */
+    sync
+    isync
+    blr
 
 DEF(void,get_ppc_fpu_env,(void*)):
-	mffs f0
-	stfd f0,0(r3)
-	blr
+    mffs f0
+    stfd f0,0(r3)
+    blr
 
 DEF(void,set_ppc_fpu_env,(const void*)):
-	lfd f0,0(r3)
-	mtfsf 0xff,f0
-	blr
+    lfd f0,0(r3)
+    mtfsf 0xff,f0
+    blr
 
 DEF(void,get_ppc_vmx_env,(void*)):
-	mfvscr v0
-	subi r4,r1,16
-	li r5,0xf
-	andc r4,r4,r5
-	stvxl v0,0,r4
-	li r5,0xc
-	lwzx r6,r5,r4
-	stw r6,0(r3)
-	blr
+    mfvscr v0
+    subi r4,r1,16
+    li r5,0xf
+    andc r4,r4,r5
+    stvxl v0,0,r4
+    li r5,0xc
+    lwzx r6,r5,r4
+    stw r6,0(r3)
+    blr
 
 DEF(void,set_ppc_vmx_env,(const void*)):
-	subi r4,r1,16
-	li r5,0xf
-	andc r4,r4,r5
-	li r5,0xc
-	lwz r6,0(r3)
-	stwx r6,r5,r4
-	lvxl v0,0,r4
-	mtvscr v0
-	blr
-
+    subi r4,r1,16
+    li r5,0xf
+    andc r4,r4,r5
+    li r5,0xc
+    lwz r6,0(r3)
+    stwx r6,r5,r4
+    lvxl v0,0,r4
+    mtvscr v0
+    blr
diff --git a/vm/cpu-ppc.hpp b/vm/cpu-ppc.hpp
index 495eb375ec..cd98d6a6ab 100644
--- a/vm/cpu-ppc.hpp
+++ b/vm/cpu-ppc.hpp
@@ -2,10 +2,6 @@ namespace factor
 {
 
 #define FACTOR_CPU_STRING "ppc"
-#define VM_ASM_API VM_C_API
-
-register cell ds asm("r13");
-register cell rs asm("r14");
 
 /* In the instruction sequence:
 
@@ -13,8 +9,8 @@ register cell rs asm("r14");
    B blah
 
    the offset from the immediate operand to LOAD32 to the instruction after
-   the branch is two instructions. */
-static const fixnum xt_tail_pic_offset = 4 * 2;
+   the branch is one instruction. */
+static const fixnum xt_tail_pic_offset = 4;
 
 inline static void check_call_site(cell return_address)
 {
@@ -81,14 +77,6 @@ inline static unsigned int fpu_status(unsigned int status)
 }
 
 /* Defined in assembly */
-VM_ASM_API void c_to_factor(cell quot, void *vm);
-VM_ASM_API void throw_impl(cell quot, stack_frame *rewind, void *vm);
-VM_ASM_API void lazy_jit_compile(cell quot, void *vm);
-VM_ASM_API void flush_icache(cell start, cell len);
-
-VM_ASM_API void set_callstack(stack_frame *to,
-			       stack_frame *from,
-			       cell length,
-			       void *(*memcpy)(void*,const void*, size_t));
+VM_C_API void flush_icache(cell start, cell len);
 
 }
diff --git a/vm/cpu-x86.32.S b/vm/cpu-x86.32.S
deleted file mode 100644
index c0532f0ece..0000000000
--- a/vm/cpu-x86.32.S
+++ /dev/null
@@ -1,114 +0,0 @@
-#include "asm.h"
-
-#define ARG0 %eax
-#define ARG1 %edx
-#define ARG2 %ecx
-#define STACK_REG %esp
-#define DS_REG %esi
-#define RETURN_REG %eax
-
-#define NV0 %ebx
-#define NV1 %ebp
-
-#define ARITH_TEMP_1 %ebp
-#define ARITH_TEMP_2 %ebx
-#define DIV_RESULT %eax
-
-#define CELL_SIZE 4
-#define STACK_PADDING 12
-
-#define PUSH_NONVOLATILE \
-	push %ebx ; \
-	push %ebp
-
-#define POP_NONVOLATILE \
-	pop %ebp ; \
-	pop %ebx
-
-#define QUOT_XT_OFFSET 12
-
-/* We pass a function pointer to memcpy to work around a Mac OS X
-ABI limitation which would otherwise require us to do a bizzaro PC-relative
-trampoline to retrieve the function address */
-DEF(void,set_callstack,(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length, void *memcpy)):
-	mov 4(%esp),%ebp                   /* to */
-	mov 8(%esp),%edx                   /* from */
-	mov 12(%esp),%ecx                  /* length */
-	mov 16(%esp),%eax                  /* memcpy */
-	sub %ecx,%ebp                      /* compute new stack pointer */
-	mov %ebp,%esp
-	push %ecx                          /* pass length */
-	push %edx                          /* pass src */
-	push %ebp                          /* pass dst */
-	call *%eax                         /* call memcpy */
-	add $12,%esp                       /* pop args from the stack */
-	ret                                /* return _with new stack_ */
-
-DEF(long long,read_timestamp_counter,(void)):
-	rdtsc
-	ret
-
-DEF(void,primitive_inline_cache_miss,(void *vm)):
-	mov (%esp),%ebx
-DEF(void,primitive_inline_cache_miss_tail,(void *vm)):
-	sub $4,%esp
-	push ARG0   /* push vm ptr */
-	push %ebx
-	call MANGLE(inline_cache_miss)
-	add $12,%esp
-	jmp *%eax
-
-DEF(void,get_sse_env,(void*)):
-	movl 4(%esp), %eax
-	stmxcsr (%eax)
-	ret
-
-DEF(void,set_sse_env,(const void*)):
-	movl 4(%esp), %eax
-	ldmxcsr (%eax)
-	ret
-
-DEF(void,get_x87_env,(void*)):
-	movl 4(%esp), %eax
-	fnstsw (%eax)
-	fnstcw 2(%eax)
-	ret
-
-DEF(void,set_x87_env,(const void*)):
-	movl 4(%esp), %eax
-	fnclex
-	fldcw 2(%eax)
-	ret
-
-DEF(F_FASTCALL void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to, void *vm)):
-	mov ARG2,NV0  /* remember vm ptr in case quot_xt = lazy_jit_compile */		
-	/* clear x87 stack, but preserve rounding mode and exception flags */
-	sub $2,STACK_REG
-	fnstcw (STACK_REG)
-	fninit
-	fldcw (STACK_REG)
-	/* rewind_to */
-	mov ARG1,STACK_REG
-	mov NV0,ARG1
-	jmp *QUOT_XT_OFFSET(ARG0)
-
-DEF(F_FASTCALL void,lazy_jit_compile,(CELL quot, void *vm)):
-	mov ARG1,ARG2
-	mov STACK_REG,ARG1           /* Save stack pointer */
-	sub $STACK_PADDING,STACK_REG
-	call MANGLE(lazy_jit_compile_impl)
-	mov RETURN_REG,ARG0          /* No-op on 32-bit */
-	add $STACK_PADDING,STACK_REG
-    jmp *QUOT_XT_OFFSET(ARG0)    /* Call the quotation */
-
-	
-#include "cpu-x86.S"
-
-#ifdef WINDOWS
-	.section .drectve
-	.ascii " -export:read_timestamp_counter"
-	.ascii " -export:get_sse_env"
-	.ascii " -export:set_sse_env"
-	.ascii " -export:get_x87_env"
-	.ascii " -export:set_x87_env"
-#endif
diff --git a/vm/cpu-x86.32.hpp b/vm/cpu-x86.32.hpp
index e740771470..6143631abc 100644
--- a/vm/cpu-x86.32.hpp
+++ b/vm/cpu-x86.32.hpp
@@ -3,8 +3,4 @@ namespace factor
 
 #define FACTOR_CPU_STRING "x86.32"
 
-register cell ds asm("esi");
-register cell rs asm("edi");
-
-#define VM_ASM_API VM_C_API __attribute__ ((regparm (3)))
 }
diff --git a/vm/cpu-x86.64.S b/vm/cpu-x86.64.S
deleted file mode 100644
index 8ccd703bfe..0000000000
--- a/vm/cpu-x86.64.S
+++ /dev/null
@@ -1,128 +0,0 @@
-#include "asm.h"
-
-#define STACK_REG %rsp
-#define DS_REG %r14
-#define RETURN_REG %rax
-
-#define CELL_SIZE 8
-#define STACK_PADDING 56
-
-#define NV0 %rbp
-#define NV1 %r12
-
-#define ARITH_TEMP_1 %r8
-#define ARITH_TEMP_2 %r9
-#define DIV_RESULT %rax
-
-#ifdef WINDOWS
-
-	#define ARG0 %rcx
-	#define ARG1 %rdx
-	#define ARG2 %r8
-	#define ARG3 %r9
-
-	#define PUSH_NONVOLATILE \
-		push %r12 ; \
-		push %r13 ; \
-		push %rdi ; \
-		push %rsi ; \
-		push %rbx ; \
-		push %rbp
-
-	#define POP_NONVOLATILE \
-		pop %rbp ; \
-		pop %rbx ; \
-		pop %rsi ; \
-		pop %rdi ; \
-		pop %r13 ; \
-		pop %r12
-
-#else
-
-	#define ARG0 %rdi
-	#define ARG1 %rsi
-	#define ARG2 %rdx
-	#define ARG3 %rcx
-
-	#define PUSH_NONVOLATILE \
-		push %rbx ; \
-		push %rbp ; \
-		push %r12 ; \
-		push %r13
-
-	#define POP_NONVOLATILE \
-		pop %r13 ; \
-		pop %r12 ; \
-		pop %rbp ; \
-		pop %rbx
-
-#endif
-
-#define QUOT_XT_OFFSET 28
-
-/* We pass a function pointer to memcpy to work around a Mac OS X
-ABI limitation which would otherwise require us to do a bizzaro PC-relative
-trampoline to retrieve the function address */
-DEF(void,set_callstack,(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length, void *memcpy)):
-	sub ARG2,ARG0                      /* compute new stack pointer */
-	mov ARG0,%rsp
-	call *ARG3                         /* call memcpy */
-	ret                                /* return _with new stack_ */
-
-DEF(long long,read_timestamp_counter,(void)):
-	mov $0,%rax
-	rdtsc
-	shl $32,%rdx
-	or %rdx,%rax
-	ret
-
-DEF(void,primitive_inline_cache_miss,(void *vm)):
-	mov (%rsp),%rbx
-DEF(void,primitive_inline_cache_miss_tail,(void *vm)):
-	sub $STACK_PADDING,%rsp
-	mov ARG0,ARG1
-	mov %rbx,ARG0
-	call MANGLE(inline_cache_miss)
-	add $STACK_PADDING,%rsp
-	jmp *%rax
-
-DEF(void,get_sse_env,(void*)):
-	stmxcsr (%rdi)
-	ret
-
-DEF(void,set_sse_env,(const void*)):
-	ldmxcsr (%rdi)
-	ret
-
-DEF(void,get_x87_env,(void*)):
-	fnstsw (%rdi)
-	fnstcw 2(%rdi)
-	ret
-
-DEF(void,set_x87_env,(const void*)):
-	fnclex
-	fldcw 2(%rdi)
-	ret
-
-DEF(F_FASTCALL void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to, void *vm)):
-	/* clear x87 stack, but preserve rounding mode and exception flags */
-	sub $2,STACK_REG
-	fnstcw (STACK_REG)
-	fninit
-	fldcw (STACK_REG)
-	/* rewind_to */
-	mov ARG1,STACK_REG
-	mov ARG2,ARG1  /* make vm ptr 2nd arg in case quot_xt = lazy_jit_compile */
-	jmp *QUOT_XT_OFFSET(ARG0)
-
-DEF(F_FASTCALL void,lazy_jit_compile,(CELL quot, void *vm)):
-	mov ARG1,ARG2                /* vm is 3rd arg */
-	mov STACK_REG,ARG1           /* Save stack pointer */
-	sub $STACK_PADDING,STACK_REG
-	call MANGLE(lazy_jit_compile_impl)
-	mov RETURN_REG,ARG0          /* No-op on 32-bit */
-	add $STACK_PADDING,STACK_REG
-        jmp *QUOT_XT_OFFSET(ARG0)    /* Call the quotation */
-
-	
-#include "cpu-x86.S"
diff --git a/vm/cpu-x86.64.hpp b/vm/cpu-x86.64.hpp
index 75d432ee13..e6a759d006 100644
--- a/vm/cpu-x86.64.hpp
+++ b/vm/cpu-x86.64.hpp
@@ -3,8 +3,4 @@ namespace factor
 
 #define FACTOR_CPU_STRING "x86.64"
 
-register cell ds asm("r14");
-register cell rs asm("r15");
-
-#define VM_ASM_API VM_C_API
 }
diff --git a/vm/cpu-x86.S b/vm/cpu-x86.S
deleted file mode 100644
index 411a0cdaa6..0000000000
--- a/vm/cpu-x86.S
+++ /dev/null
@@ -1,115 +0,0 @@
-DEF(void,primitive_fixnum_add,(void *myvm)):
-	mov ARG0, ARG2  /* save vm ptr for overflow */
-	mov (DS_REG),ARG0
-	mov -CELL_SIZE(DS_REG),ARG1
-	sub $CELL_SIZE,DS_REG
-	mov ARG1,ARITH_TEMP_1
-	add ARG0,ARITH_TEMP_1
-	jo MANGLE(overflow_fixnum_add)
-	mov ARITH_TEMP_1,(DS_REG)
-	ret
-
-DEF(void,primitive_fixnum_subtract,(void *myvm)):
-	mov ARG0, ARG2  /* save vm ptr for overflow */
-	mov (DS_REG),ARG1
-	mov -CELL_SIZE(DS_REG),ARG0
-	sub $CELL_SIZE,DS_REG
-	mov ARG0,ARITH_TEMP_1
-	sub ARG1,ARITH_TEMP_1
-	jo MANGLE(overflow_fixnum_subtract)
-	mov ARITH_TEMP_1,(DS_REG)
-	ret
-
-DEF(void,primitive_fixnum_multiply,(void *myvm)):
-	push ARG0  /* save vm ptr for overflow */
-	mov (DS_REG),ARITH_TEMP_1
-	mov ARITH_TEMP_1,DIV_RESULT
-	mov -CELL_SIZE(DS_REG),ARITH_TEMP_2
-	sar $4,ARITH_TEMP_2
-	sub $CELL_SIZE,DS_REG
-	imul ARITH_TEMP_2
-	jo multiply_overflow
-	mov DIV_RESULT,(DS_REG)
-	pop ARG2
-	ret
-multiply_overflow:
-	sar $4,ARITH_TEMP_1
-	mov ARITH_TEMP_1,ARG0
-	mov ARITH_TEMP_2,ARG1
-	pop ARG2
-	jmp MANGLE(overflow_fixnum_multiply)
-
-DEF(F_FASTCALL void,c_to_factor,(CELL quot, void *vm)):
-	PUSH_NONVOLATILE
-	mov ARG0,NV0
-	mov ARG1,NV1
-
-    /* Save old stack pointer and align */
-    mov STACK_REG,ARG0
-    and $-16,STACK_REG
-    add $CELL_SIZE,STACK_REG
-    push ARG0
-
-	/* Create register shadow area for Win64 */
-	sub $32,STACK_REG
-
-	/* Save stack pointer */
-	lea -CELL_SIZE(STACK_REG),ARG0
-	call MANGLE(save_callstack_bottom)
-
-	/* Call quot-xt */
-	mov NV0,ARG0
-	mov NV1,ARG1
-	call *QUOT_XT_OFFSET(ARG0)
-
-	/* Tear down register shadow area */
-	add $32,STACK_REG
-
-    /* Undo stack alignment */
-    mov (STACK_REG),STACK_REG
-
-	POP_NONVOLATILE
-	ret
-
-/* cpu.x86.features calls this */
-DEF(bool,sse_version,(void)):
-	mov $0x1,RETURN_REG
-	cpuid
-	test $0x100000,%ecx
-	jnz sse_42
-	test $0x80000,%ecx
-	jnz sse_41
-	test $0x200,%ecx
-	jnz ssse_3
-	test $0x1,%ecx
-	jnz sse_3
-	test $0x4000000,%edx
-	jnz sse_2
-	test $0x2000000,%edx
-	jnz sse_1
-	mov $0,%eax
-	ret
-sse_42:
-	mov $42,RETURN_REG
-	ret
-sse_41:
-	mov $41,RETURN_REG
-	ret
-ssse_3:
-	mov $33,RETURN_REG
-	ret
-sse_3:
-	mov $30,RETURN_REG
-	ret
-sse_2:
-	mov $20,RETURN_REG
-	ret
-sse_1:
-	mov $10,RETURN_REG
-	ret
-
-#ifdef WINDOWS
-	.section .drectve
-	.ascii " -export:sse_version"
-	.ascii " -export:c_to_factor"
-#endif
diff --git a/vm/cpu-x86.hpp b/vm/cpu-x86.hpp
index 85585aeda6..c96291b0d7 100644
--- a/vm/cpu-x86.hpp
+++ b/vm/cpu-x86.hpp
@@ -15,7 +15,7 @@ inline static void flush_icache(cell start, cell len) {}
    the offset from the immediate operand to MOV to the instruction after
    the jump is a cell for the immediate operand, 4 bytes for the JMP
    destination, and one byte for the JMP opcode. */
-static const fixnum xt_tail_pic_offset = sizeof(cell) + 4 + 1;
+static const fixnum xt_tail_pic_offset = 4 + 1;
 
 static const unsigned char call_opcode = 0xe8;
 static const unsigned char jmp_opcode = 0xe9;
@@ -47,7 +47,12 @@ inline static void set_call_target(cell return_address, void *target)
 
 inline static bool tail_call_site_p(cell return_address)
 {
-	return call_site_opcode(return_address) == jmp_opcode;
+	switch(call_site_opcode(return_address))
+	{
+	case jmp_opcode: return true;
+	case call_opcode: return false;
+	default: abort(); return false;
+	}
 }
 
 inline static unsigned int fpu_status(unsigned int status)
@@ -68,14 +73,4 @@ inline static unsigned int fpu_status(unsigned int status)
         return r;
 }
 
-/* Defined in assembly */
-VM_ASM_API void c_to_factor(cell quot, void *vm);
-VM_ASM_API void throw_impl(cell quot, stack_frame *rewind_to, void *vm);
-VM_ASM_API void lazy_jit_compile(cell quot, void *vm);
-
-VM_C_API void set_callstack(stack_frame *to,
-			      stack_frame *from,
-			      cell length,
-			      void *(*memcpy)(void*,const void*, size_t));
-
 }
diff --git a/vm/data_heap.cpp b/vm/data_heap.cpp
index bb705e276c..f5946d648b 100755
--- a/vm/data_heap.cpp
+++ b/vm/data_heap.cpp
@@ -98,11 +98,22 @@ void data_heap::reset_generation(tenured_space *gen)
 	clear_decks(gen);
 }
 
+bool data_heap::high_fragmentation_p()
+{
+	return (tenured->largest_free_block() <= nursery->size + aging->size);
+}
+
 bool data_heap::low_memory_p()
 {
 	return (tenured->free_space() <= nursery->size + aging->size);
 }
 
+void data_heap::mark_all_cards()
+{
+	memset(cards,-1,cards_end - cards);
+	memset(decks,-1,decks_end - decks);
+}
+
 void factor_vm::set_data_heap(data_heap *data_)
 {
 	data = data_;
@@ -115,21 +126,12 @@ void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_si
 	set_data_heap(new data_heap(young_size,aging_size,tenured_size));
 }
 
-/* Size of the object pointed to by a tagged pointer */
-cell factor_vm::object_size(cell tagged)
-{
-	if(immediate_p(tagged))
-		return 0;
-	else
-		return untag(tagged)->size();
-}
-
 /* Size of the object pointed to by an untagged pointer */
 cell object::size() const
 {
 	if(free_p()) return ((free_heap_block *)this)->size();
 
-	switch(h.hi_tag())
+	switch(type())
 	{
 	case ARRAY_TYPE:
 		return align(array_size((array*)this),data_alignment);
@@ -169,7 +171,9 @@ the GC. Some types have a binary payload at the end (string, word, DLL) which
 we ignore. */
 cell object::binary_payload_start() const
 {
-	switch(h.hi_tag())
+	if(free_p()) return 0;
+
+	switch(type())
 	{
 	/* these objects do not refer to other objects at all */
 	case FLOAT_TYPE:
@@ -201,11 +205,6 @@ cell object::binary_payload_start() const
 	}
 }
 
-void factor_vm::primitive_size()
-{
-	box_unsigned_cell(object_size(dpop()));
-}
-
 data_heap_room factor_vm::data_room()
 {
 	data_heap_room room;
@@ -223,7 +222,7 @@ data_heap_room factor_vm::data_room()
 	room.tenured_free_block_count = data->tenured->free_block_count();
 	room.cards                    = data->cards_end - data->cards;
 	room.decks                    = data->decks_end - data->decks;
-	room.mark_stack               = data->tenured->mark_stack.capacity();
+	room.mark_stack               = mark_stack.capacity() * sizeof(cell);
 
 	return room;
 }
@@ -231,85 +230,42 @@ data_heap_room factor_vm::data_room()
 void factor_vm::primitive_data_room()
 {
 	data_heap_room room = data_room();
-	dpush(tag(byte_array_from_value(&room)));
+	ctx->push(tag(byte_array_from_value(&room)));
 }
 
-/* Disables GC and activates next-object ( -- obj ) primitive */
-void factor_vm::begin_scan()
-{
-	heap_scan_ptr = data->tenured->first_object();
-	gc_off = true;
-}
+struct object_accumulator {
+	cell type;
+	std::vector objects;
 
-void factor_vm::end_scan()
-{
-	gc_off = false;
-}
+	explicit object_accumulator(cell type_) : type(type_) {}
 
-void factor_vm::primitive_begin_scan()
-{
-	begin_scan();
-}
-
-cell factor_vm::next_object()
-{
-	if(!gc_off)
-		general_error(ERROR_HEAP_SCAN,false_object,false_object,NULL);
-
-	if(heap_scan_ptr)
+	void operator()(object *obj)
 	{
-		cell current = heap_scan_ptr;
-		heap_scan_ptr = data->tenured->next_object_after(heap_scan_ptr);
-		return tag_dynamic((object *)current);
-	}
-	else
-		return false_object;
-}
-
-/* Push object at heap scan cursor and advance; pushes f when done */
-void factor_vm::primitive_next_object()
-{
-	dpush(next_object());
-}
-
-/* Re-enables GC */
-void factor_vm::primitive_end_scan()
-{
-	gc_off = false;
-}
-
-struct word_counter {
-	cell count;
-
-	explicit word_counter() : count(0) {}
-
-	void operator()(cell obj)
-	{
-		if(tagged(obj).type_p(WORD_TYPE))
-			count++;
+		if(type == TYPE_COUNT || obj->type() == type)
+			objects.push_back(tag_dynamic(obj));
 	}
 };
 
-struct word_accumulator {
-	growable_array words;
-
-	explicit word_accumulator(int count,factor_vm *vm) : words(vm,count) {}
-
-	void operator()(cell obj)
-	{
-		if(tagged(obj).type_p(WORD_TYPE))
-			words.add(obj);
-	}
-};
-
-cell factor_vm::find_all_words()
+cell factor_vm::instances(cell type)
 {
-	word_counter counter;
-	each_object(counter);
-	word_accumulator accum(counter.count,this);
+	object_accumulator accum(type);
 	each_object(accum);
-	accum.words.trim();
-	return accum.words.elements.value();
+	cell object_count = accum.objects.size();
+
+	data_roots.push_back(data_root_range(&accum.objects[0],object_count));
+
+	array *objects = allot_array(object_count,false_object);
+	memcpy(objects->data(),&accum.objects[0],object_count * sizeof(cell));
+
+	data_roots.pop_back();
+
+	return tag(objects);
+}
+
+void factor_vm::primitive_all_instances()
+{
+	primitive_full_gc();
+	ctx->push(instances(TYPE_COUNT));
 }
 
 }
diff --git a/vm/data_heap.hpp b/vm/data_heap.hpp
index 760a10942e..cef43ef5fe 100755
--- a/vm/data_heap.hpp
+++ b/vm/data_heap.hpp
@@ -29,7 +29,9 @@ struct data_heap {
 	void reset_generation(nursery_space *gen);
 	void reset_generation(aging_space *gen);
 	void reset_generation(tenured_space *gen);
+	bool high_fragmentation_p();
 	bool low_memory_p();
+	void mark_all_cards();
 };
 
 struct data_heap_room {
diff --git a/vm/data_heap_checker.cpp b/vm/data_heap_checker.cpp
new file mode 100644
index 0000000000..0d79abc15b
--- /dev/null
+++ b/vm/data_heap_checker.cpp
@@ -0,0 +1,101 @@
+#include "master.hpp"
+
+/* A tool to debug write barriers. Call check_data_heap() to ensure that all
+cards that should be marked are actually marked. */
+
+namespace factor
+{
+
+enum generation {
+	nursery_generation,
+	aging_generation,
+	tenured_generation
+};
+
+inline generation generation_of(factor_vm *parent, object *obj)
+{
+	if(parent->data->nursery->contains_p(obj))
+		return nursery_generation;
+	else if(parent->data->aging->contains_p(obj))
+		return aging_generation;
+	else if(parent->data->tenured->contains_p(obj))
+		return tenured_generation;
+	else
+	{
+		critical_error("Bad object",(cell)obj);
+		return (generation)-1;
+	}
+}
+
+struct slot_checker {
+	factor_vm *parent;
+	object *obj;
+	generation gen;
+
+	explicit slot_checker(factor_vm *parent_, object *obj_, generation gen_) :
+		parent(parent_), obj(obj_), gen(gen_) {}
+
+	void check_write_barrier(cell *slot_ptr, generation target, char mask)
+	{
+		cell object_card_pointer = parent->cards_offset + ((cell)obj >> card_bits);
+		cell slot_card_pointer = parent->cards_offset + ((cell)slot_ptr >> card_bits);
+		char slot_card_value = *(char *)slot_card_pointer;
+		if((slot_card_value & mask) != mask)
+		{
+			std::cout << "card not marked" << std::endl;
+			std::cout << "source generation: " << gen << std::endl;
+			std::cout << "target generation: " << target << std::endl;
+			std::cout << "object: 0x" << std::hex << (cell)obj << std::dec << std::endl;
+			std::cout << "object type: " << obj->type() << std::endl;
+			std::cout << "slot pointer: 0x" << std::hex << (cell)slot_ptr << std::dec << std::endl;
+			std::cout << "slot value: 0x" << std::hex << *slot_ptr << std::dec << std::endl;
+			std::cout << "card of object: 0x" << std::hex << object_card_pointer << std::dec << std::endl;
+			std::cout << "card of slot: 0x" << std::hex << slot_card_pointer << std::dec << std::endl;
+			std::cout << std::endl;
+			parent->factorbug();
+		}
+	}
+
+	void operator()(cell *slot_ptr)
+	{
+		if(!immediate_p(*slot_ptr))
+		{
+			generation target = generation_of(parent,untag(*slot_ptr));
+			switch(gen)
+			{
+			case nursery_generation:
+				break;
+			case aging_generation:
+				if(target == nursery_generation)
+					check_write_barrier(slot_ptr,target,card_points_to_nursery);
+				break;
+			case tenured_generation:
+				if(target == nursery_generation)
+					check_write_barrier(slot_ptr,target,card_points_to_nursery);
+				else if(target == aging_generation)
+					check_write_barrier(slot_ptr,target,card_points_to_aging);
+				break;
+			}
+		}
+	}
+};
+
+struct object_checker {
+	factor_vm *parent;
+
+	explicit object_checker(factor_vm *parent_) : parent(parent_) {}
+
+	void operator()(object *obj)
+	{
+		slot_checker checker(parent,obj,generation_of(parent,obj));
+		obj->each_slot(checker);
+	}
+};
+
+void factor_vm::check_data_heap()
+{
+	object_checker checker(this);
+	each_object(checker);
+}
+
+}
diff --git a/vm/data_roots.hpp b/vm/data_roots.hpp
index 52654c49f0..8e366a7cfd 100644
--- a/vm/data_roots.hpp
+++ b/vm/data_roots.hpp
@@ -7,7 +7,7 @@ struct data_root : public tagged {
 
 	void push()
 	{
-		parent->data_roots.push_back((cell)this);
+		parent->data_roots.push_back(data_root_range(&this->value_,1));
 	}
 
 	explicit data_root(cell value_, factor_vm *parent_)
@@ -27,9 +27,6 @@ struct data_root : public tagged {
 
 	~data_root()
 	{
-#ifdef FACTOR_DEBUG
-		assert(parent->data_roots.back() == (cell)this);
-#endif
 		parent->data_roots.pop_back();
 	}
 };
diff --git a/vm/debug.cpp b/vm/debug.cpp
index fee3e6a257..419eb690ff 100755
--- a/vm/debug.cpp
+++ b/vm/debug.cpp
@@ -10,7 +10,7 @@ std::ostream &operator<<(std::ostream &out, const string *str)
 	return out;
 }
 
-void factor_vm::print_word(word* word, cell nesting)
+void factor_vm::print_word(word *word, cell nesting)
 {
 	if(tagged(word->vocabulary).type_p(STRING_TYPE))
 		std::cout << untag(word->vocabulary) << ":";
@@ -30,7 +30,7 @@ void factor_vm::print_factor_string(string *str)
 	std::cout << '"' << str << '"';
 }
 
-void factor_vm::print_array(array* array, cell nesting)
+void factor_vm::print_array(array *array, cell nesting)
 {
 	cell length = array_capacity(array);
 	cell i;
@@ -145,13 +145,13 @@ void factor_vm::print_objects(cell *start, cell *end)
 void factor_vm::print_datastack()
 {
 	std::cout << "==== DATA STACK:\n";
-	print_objects((cell *)ds_bot,(cell *)ds);
+	print_objects((cell *)ctx->datastack_region->start,(cell *)ctx->datastack);
 }
 
 void factor_vm::print_retainstack()
 {
 	std::cout << "==== RETAIN STACK:\n";
-	print_objects((cell *)rs_bot,(cell *)rs);
+	print_objects((cell *)ctx->retainstack_region->start,(cell *)ctx->retainstack);
 }
 
 struct stack_frame_printer {
@@ -160,15 +160,18 @@ struct stack_frame_printer {
 	explicit stack_frame_printer(factor_vm *parent_) : parent(parent_) {}
 	void operator()(stack_frame *frame)
 	{
+		std::cout << "frame: " << std::hex << (cell)frame << std::dec << std::endl;
+		std::cout << "executing: ";
 		parent->print_obj(parent->frame_executing(frame));
 		std::cout << std::endl;
+		std::cout << "scan: ";
 		parent->print_obj(parent->frame_scan(frame));
 		std::cout << std::endl;
 		std::cout << "word/quot addr: ";
 		std::cout << std::hex << (cell)parent->frame_executing(frame) << std::dec;
 		std::cout << std::endl;
 		std::cout << "word/quot xt: ";
-		std::cout << std::hex << (cell)frame->xt << std::dec;
+		std::cout << std::hex << (cell)frame->entry_point << std::dec;
 		std::cout << std::endl;
 		std::cout << "return address: ";
 		std::cout << std::hex << (cell)FRAME_RETURN_ADDRESS(frame,parent) << std::dec;
@@ -241,12 +244,12 @@ struct object_dumper {
 	explicit object_dumper(factor_vm *parent_, cell type_) :
 		parent(parent_), type(type_) {}
 
-	void operator()(cell obj)
+	void operator()(object *obj)
 	{
-		if(type == TYPE_COUNT || tagged(obj).type_p(type))
+		if(type == TYPE_COUNT || obj->type() == type)
 		{
-			std::cout << padded_address(obj) << " ";
-			parent->print_nested_obj(obj,2);
+			std::cout << padded_address((cell)obj) << " ";
+			parent->print_nested_obj(tag_dynamic(obj),2);
 			std::cout << std::endl;
 		}
 	}
@@ -260,18 +263,19 @@ void factor_vm::dump_objects(cell type)
 }
 
 struct data_reference_slot_visitor {
-	cell look_for, obj;
+	cell look_for;
+	object *obj;
 	factor_vm *parent;
 
-	explicit data_reference_slot_visitor(cell look_for_, cell obj_, factor_vm *parent_) :
+	explicit data_reference_slot_visitor(cell look_for_, object *obj_, factor_vm *parent_) :
 		look_for(look_for_), obj(obj_), parent(parent_) { }
 
 	void operator()(cell *scan)
 	{
 		if(look_for == *scan)
 		{
-			std::cout << padded_address(obj) << " ";
-			parent->print_nested_obj(obj,2);
+			std::cout << padded_address((cell)obj) << " ";
+			parent->print_nested_obj(tag_dynamic(obj),2);
 			std::cout << std::endl;
 		}
 	}
@@ -284,10 +288,10 @@ struct data_reference_object_visitor {
 	explicit data_reference_object_visitor(cell look_for_, factor_vm *parent_) :
 		look_for(look_for_), parent(parent_) {}
 
-	void operator()(cell obj)
+	void operator()(object *obj)
 	{
 		data_reference_slot_visitor visitor(look_for,obj,parent);
-		parent->do_slots(UNTAG(obj),visitor);
+		obj->each_slot(visitor);
 	}
 };
 
@@ -299,32 +303,30 @@ void factor_vm::find_data_references(cell look_for)
 
 struct code_block_printer {
 	factor_vm *parent;
-	cell reloc_size, literal_size;
+	cell reloc_size, parameter_size;
 
 	explicit code_block_printer(factor_vm *parent_) :
-		parent(parent_), reloc_size(0), literal_size(0) {}
+		parent(parent_), reloc_size(0), parameter_size(0) {}
 
 	void operator()(code_block *scan, cell size)
 	{
 		const char *status;
 		if(scan->free_p())
 			status = "free";
-		else if(parent->code->marked_p(scan))
-		{
-			reloc_size += parent->object_size(scan->relocation);
-			literal_size += parent->object_size(scan->literals);
-			status = "marked";
-		}
 		else
 		{
 			reloc_size += parent->object_size(scan->relocation);
-			literal_size += parent->object_size(scan->literals);
-			status = "allocated";
-		}
+			parameter_size += parent->object_size(scan->parameters);
 
-		std::cout << std::hex << (cell)scan << std::dec << " ";
-		std::cout << std::hex << size << std::dec << " ";
-		std::cout << status << std::endl;
+			if(parent->code->marked_p(scan))
+				status = "marked";
+			else
+				status = "allocated";
+
+			std::cout << std::hex << (cell)scan << std::dec << " ";
+			std::cout << std::hex << size << std::dec << " ";
+			std::cout << status << std::endl;
+		}
 	}
 };
 
@@ -333,8 +335,8 @@ void factor_vm::dump_code_heap()
 {
 	code_block_printer printer(this);
 	code->allocator->iterate(printer);
-	std::cout << printer.reloc_size << " bytes of relocation data\n";
-	std::cout << printer.literal_size << " bytes of literal data\n";
+	std::cout << printer.reloc_size << " bytes used by relocation tables\n";
+	std::cout << printer.parameter_size << " bytes used by parameter tables\n";
 }
 
 void factor_vm::factorbug()
@@ -419,9 +421,9 @@ void factor_vm::factorbug()
 		else if(strcmp(cmd,"t") == 0)
 			full_output = !full_output;
 		else if(strcmp(cmd,"s") == 0)
-			dump_memory(ds_bot,ds);
+			dump_memory(ctx->datastack_region->start,ctx->datastack);
 		else if(strcmp(cmd,"r") == 0)
-			dump_memory(rs_bot,rs);
+			dump_memory(ctx->retainstack_region->start,ctx->retainstack);
 		else if(strcmp(cmd,".s") == 0)
 			print_datastack();
 		else if(strcmp(cmd,".r") == 0)
@@ -457,7 +459,7 @@ void factor_vm::factorbug()
 		else if(strcmp(cmd,"push") == 0)
 		{
 			cell addr = read_cell_hex();
-			dpush(addr);
+			ctx->push(addr);
 		}
 		else if(strcmp(cmd,"code") == 0)
 			dump_code_heap();
diff --git a/vm/dispatch.cpp b/vm/dispatch.cpp
index 3eba483fe6..b0f9159da7 100755
--- a/vm/dispatch.cpp
+++ b/vm/dispatch.cpp
@@ -88,9 +88,9 @@ cell factor_vm::lookup_method(cell obj, cell methods)
 
 void factor_vm::primitive_lookup_method()
 {
-	cell methods = dpop();
-	cell obj = dpop();
-	dpush(lookup_method(obj,methods));
+	cell methods = ctx->pop();
+	cell obj = ctx->pop();
+	ctx->push(lookup_method(obj,methods));
 }
 
 cell factor_vm::object_class(cell obj)
@@ -120,17 +120,17 @@ void factor_vm::primitive_mega_cache_miss()
 {
 	dispatch_stats.megamorphic_cache_misses++;
 
-	cell cache = dpop();
-	fixnum index = untag_fixnum(dpop());
-	cell methods = dpop();
+	cell cache = ctx->pop();
+	fixnum index = untag_fixnum(ctx->pop());
+	cell methods = ctx->pop();
 
-	cell object = ((cell *)ds)[-index];
+	cell object = ((cell *)ctx->datastack)[-index];
 	cell klass = object_class(object);
 	cell method = lookup_method(object,methods);
 
 	update_method_cache(cache,klass,method);
 
-	dpush(method);
+	ctx->push(method);
 }
 
 void factor_vm::primitive_reset_dispatch_stats()
@@ -140,7 +140,7 @@ void factor_vm::primitive_reset_dispatch_stats()
 
 void factor_vm::primitive_dispatch_stats()
 {
-	dpush(tag(byte_array_from_value(&dispatch_stats)));
+	ctx->push(tag(byte_array_from_value(&dispatch_stats)));
 }
 
 void quotation_jit::emit_mega_cache_lookup(cell methods_, fixnum index, cell cache_)
@@ -152,7 +152,7 @@ void quotation_jit::emit_mega_cache_lookup(cell methods_, fixnum index, cell cac
 	emit_class_lookup(index,PIC_TUPLE);
 
 	/* Do a cache lookup. */
-	emit_with(parent->special_objects[MEGA_LOOKUP],cache.value());
+	emit_with_literal(parent->special_objects[MEGA_LOOKUP],cache.value());
 	
 	/* If we end up here, the cache missed. */
 	emit(parent->special_objects[JIT_PROLOG]);
@@ -166,7 +166,7 @@ void quotation_jit::emit_mega_cache_lookup(cell methods_, fixnum index, cell cac
 	/* Now the new method has been stored into the cache, and its on
 	   the stack. */
 	emit(parent->special_objects[JIT_EPILOG]);
-	emit(parent->special_objects[JIT_EXECUTE_JUMP]);
+	emit(parent->special_objects[JIT_EXECUTE]);
 }
 
 }
diff --git a/vm/entry_points.cpp b/vm/entry_points.cpp
new file mode 100644
index 0000000000..e07e343a96
--- /dev/null
+++ b/vm/entry_points.cpp
@@ -0,0 +1,29 @@
+#include "master.hpp"
+
+namespace factor
+{
+
+void factor_vm::c_to_factor(cell quot)
+{
+	/* First time this is called, wrap the c-to-factor sub-primitive inside
+	of a callback stub, which saves and restores non-volatile registers
+	as per platform ABI conventions, so that the Factor compiler can treat
+	all registers as volatile */
+	if(!c_to_factor_func)
+	{
+		tagged c_to_factor_word(special_objects[C_TO_FACTOR_WORD]);
+		code_block *c_to_factor_block = callbacks->add(c_to_factor_word.value(),0);
+		c_to_factor_func = (c_to_factor_func_type)c_to_factor_block->entry_point();
+	}
+
+	c_to_factor_func(quot);
+}
+
+void factor_vm::unwind_native_frames(cell quot, stack_frame *to)
+{
+	tagged unwind_native_frames_word(special_objects[UNWIND_NATIVE_FRAMES_WORD]);
+	unwind_native_frames_func_type unwind_native_frames_func = (unwind_native_frames_func_type)unwind_native_frames_word->entry_point;
+	unwind_native_frames_func(quot,to);
+}
+
+}
diff --git a/vm/entry_points.hpp b/vm/entry_points.hpp
new file mode 100644
index 0000000000..873501f235
--- /dev/null
+++ b/vm/entry_points.hpp
@@ -0,0 +1,7 @@
+namespace factor
+{
+
+typedef void (* c_to_factor_func_type)(cell quot);
+typedef void (* unwind_native_frames_func_type)(cell quot, stack_frame *to);
+
+}
diff --git a/vm/errors.cpp b/vm/errors.cpp
index 7d7b1f0080..2dcb773dd1 100755
--- a/vm/errors.cpp
+++ b/vm/errors.cpp
@@ -31,7 +31,7 @@ void factor_vm::throw_error(cell error, stack_frame *callstack_top)
 {
 	/* If the error handler is set, we rewind any C stack frames and
 	pass the error to user-space. */
-	if(!current_gc && to_boolean(special_objects[OBJ_BREAK]))
+	if(!current_gc && to_boolean(special_objects[ERROR_HANDLER_QUOT]))
 	{
 		/* If error was thrown during heap scan, we re-enable the GC */
 		gc_off = false;
@@ -43,9 +43,9 @@ void factor_vm::throw_error(cell error, stack_frame *callstack_top)
 
 		/* If we had an underflow or overflow, stack pointers might be
 		out of bounds */
-		fix_stacks();
+		ctx->fix_stacks();
 
-		dpush(error);
+		ctx->push(error);
 
 		/* Errors thrown from C code pass NULL for this parameter.
 		Errors thrown from Factor code, or signal handlers, pass the
@@ -56,7 +56,7 @@ void factor_vm::throw_error(cell error, stack_frame *callstack_top)
 		else
 			callstack_top = ctx->callstack_top;
 
-		throw_impl(special_objects[OBJ_BREAK],callstack_top,this);
+		unwind_native_frames(special_objects[ERROR_HANDLER_QUOT],callstack_top);
 	}
 	/* Error was thrown in early startup before error handler is set, just
 	crash. */
@@ -99,13 +99,13 @@ bool factor_vm::in_page(cell fault, cell area, cell area_size, int offset)
 
 void factor_vm::memory_protection_error(cell addr, stack_frame *native_stack)
 {
-	if(in_page(addr, ds_bot, 0, -1))
+	if(in_page(addr, ctx->datastack_region->start, 0, -1))
 		general_error(ERROR_DS_UNDERFLOW,false_object,false_object,native_stack);
-	else if(in_page(addr, ds_bot, ds_size, 0))
+	else if(in_page(addr, ctx->datastack_region->start, ds_size, 0))
 		general_error(ERROR_DS_OVERFLOW,false_object,false_object,native_stack);
-	else if(in_page(addr, rs_bot, 0, -1))
+	else if(in_page(addr, ctx->retainstack_region->start, 0, -1))
 		general_error(ERROR_RS_UNDERFLOW,false_object,false_object,native_stack);
-	else if(in_page(addr, rs_bot, rs_size, 0))
+	else if(in_page(addr, ctx->retainstack_region->start, rs_size, 0))
 		general_error(ERROR_RS_OVERFLOW,false_object,false_object,native_stack);
 	else if(in_page(addr, nursery.end, 0, 0))
 		critical_error("allot_object() missed GC check",0);
@@ -130,7 +130,7 @@ void factor_vm::fp_trap_error(unsigned int fpu_status, stack_frame *signal_calls
 
 void factor_vm::primitive_call_clear()
 {
-	throw_impl(dpop(),ctx->callstack_bottom,this);
+	unwind_native_frames(ctx->pop(),ctx->callstack_bottom);
 }
 
 /* For testing purposes */
diff --git a/vm/errors.hpp b/vm/errors.hpp
index c1ea2e1907..4b237e03a0 100755
--- a/vm/errors.hpp
+++ b/vm/errors.hpp
@@ -13,7 +13,6 @@ enum vm_error_type
 	ERROR_ARRAY_SIZE,
 	ERROR_C_STRING,
 	ERROR_FFI,
-	ERROR_HEAP_SCAN,
 	ERROR_UNDEFINED_SYMBOL,
 	ERROR_DS_UNDERFLOW,
 	ERROR_DS_OVERFLOW,
diff --git a/vm/factor.cpp b/vm/factor.cpp
index d382745da8..d5a1d2f30e 100755
--- a/vm/factor.cpp
+++ b/vm/factor.cpp
@@ -3,7 +3,6 @@
 namespace factor
 {
 
-factor_vm *vm;
 std::map thread_vms;
 
 void init_globals()
@@ -31,11 +30,7 @@ void factor_vm::default_parameters(vm_parameters *p)
 #ifdef WINDOWS
 	p->console = false;
 #else
-	if (this == vm)
-		p->console = true;
-	else		
-		p->console = false;
-	
+	p->console = true;
 #endif
 
 	p->callback_size = 256;
@@ -79,13 +74,15 @@ void factor_vm::init_parameters_from_args(vm_parameters *p, int argc, vm_char **
 	}
 }
 
-/* Do some initialization that we do once only */
-void factor_vm::do_stage1_init()
+/* Compile code in boot image so that we can execute the startup quotation */
+void factor_vm::prepare_boot_image()
 {
 	std::cout << "*** Stage 2 early init... ";
 	fflush(stdout);
 
 	compile_all_words();
+	update_code_heap_words();
+	initialize_all_quotations();
 	special_objects[OBJ_STAGE2] = true_object;
 
 	std::cout << "done\n";
@@ -118,7 +115,7 @@ void factor_vm::init_factor(vm_parameters *p)
 	if(p->image_path == NULL)
 		p->image_path = default_image_path();
 
-	srand(current_micros());
+	srand((unsigned int)system_micros());
 	init_ffi();
 	init_stacks(p->ds_size,p->rs_size);
 	init_callbacks(p->callback_size);
@@ -144,18 +141,16 @@ void factor_vm::init_factor(vm_parameters *p)
 	gc_off = false;
 
 	if(!to_boolean(special_objects[OBJ_STAGE2]))
-		do_stage1_init();
+		prepare_boot_image();
 }
 
 /* May allocate memory */
 void factor_vm::pass_args_to_factor(int argc, vm_char **argv)
 {
 	growable_array args(this);
-	int i;
 
-	for(i = 1; i < argc; i++){
+	for(fixnum i = 1; i < argc; i++)
 		args.add(allot_alien(false_object,(cell)argv[i]));
-	}
 
 	args.trim();
 	special_objects[OBJ_ARGS] = args.elements.value();
@@ -165,8 +160,15 @@ void factor_vm::start_factor(vm_parameters *p)
 {
 	if(p->fep) factorbug();
 
-	nest_stacks(NULL);
-	c_to_factor_toplevel(special_objects[OBJ_BOOT]);
+	nest_stacks();
+	c_to_factor_toplevel(special_objects[OBJ_STARTUP_QUOT]);
+	unnest_stacks();
+}
+
+void factor_vm::stop_factor()
+{
+	nest_stacks();
+	c_to_factor_toplevel(special_objects[OBJ_SHUTDOWN_QUOT]);
 	unnest_stacks();
 }
 
@@ -218,7 +220,7 @@ factor_vm *new_factor_vm()
 }
 
 // arg must be new'ed because we're going to delete it!
-void* start_standalone_factor_thread(void *arg) 
+void *start_standalone_factor_thread(void *arg) 
 {
 	factor_vm *newvm = new_factor_vm();
 	startargs *args = (startargs*) arg;
@@ -231,7 +233,6 @@ void* start_standalone_factor_thread(void *arg)
 VM_C_API void start_standalone_factor(int argc, vm_char **argv)
 {
 	factor_vm *newvm = new_factor_vm();
-	vm = newvm;
 	return newvm->start_standalone_factor(argc,argv);
 }
 
diff --git a/vm/factor.hpp b/vm/factor.hpp
old mode 100644
new mode 100755
index 5f41c952e1..cec59bcc5c
--- a/vm/factor.hpp
+++ b/vm/factor.hpp
@@ -2,7 +2,7 @@ namespace factor
 {
 
 VM_C_API void init_globals();
-
 VM_C_API void start_standalone_factor(int argc, vm_char **argv);
 VM_C_API THREADHANDLE start_standalone_factor_in_new_thread(int argc, vm_char **argv);
+
 }
diff --git a/vm/free_list.cpp b/vm/free_list.cpp
index cde6a2d781..9b4b06683d 100644
--- a/vm/free_list.cpp
+++ b/vm/free_list.cpp
@@ -30,8 +30,8 @@ void free_list::add_to_free_list(free_heap_block *block)
 	free_block_count++;
 	free_space += size;
 
-	if(size < free_list_count * block_granularity)
-		small_blocks[size / block_granularity].push_back(block);
+	if(size < free_list_count * data_alignment)
+		small_blocks[size / data_alignment].push_back(block);
 	else
 		large_blocks.insert(block);
 }
@@ -39,39 +39,59 @@ void free_list::add_to_free_list(free_heap_block *block)
 free_heap_block *free_list::find_free_block(cell size)
 {
 	/* Check small free lists */
-	for(cell i = size / block_granularity; i < free_list_count; i++)
+	if(size / data_alignment < free_list_count)
 	{
-		std::vector &blocks = small_blocks[i];
-		if(blocks.size())
+		std::vector &blocks = small_blocks[size / data_alignment];
+		if(blocks.size() == 0)
 		{
-			free_heap_block *block = blocks.back();
-			blocks.pop_back();
+			/* Round up to a multiple of 'size' */
+			cell large_block_size = ((allocation_page_size + size - 1) / size) * size;
 
-			free_block_count--;
-			free_space -= block->size();
+			/* Allocate a block this big */
+			free_heap_block *large_block = find_free_block(large_block_size);
+			if(!large_block) return NULL;
 
-			return block;
+			large_block = split_free_block(large_block,large_block_size);
+
+			/* Split it up into pieces and add each piece back to the free list */
+			for(cell offset = 0; offset < large_block_size; offset += size)
+			{
+				free_heap_block *small_block = large_block;
+				large_block = (free_heap_block *)((cell)large_block + size);
+				small_block->make_free(size);
+				add_to_free_list(small_block);
+			}
 		}
-	}
 
-	/* Check large free lists */
-	free_heap_block key;
-	key.make_free(size);
-	large_block_set::iterator iter = large_blocks.lower_bound(&key);
-	large_block_set::iterator end = large_blocks.end();
-
-	if(iter != end)
-	{
-		free_heap_block *block = *iter;
-		large_blocks.erase(iter);
+		free_heap_block *block = blocks.back();
+		blocks.pop_back();
 
 		free_block_count--;
 		free_space -= block->size();
 
 		return block;
 	}
+	else
+	{
+		/* Check large free list */
+		free_heap_block key;
+		key.make_free(size);
+		large_block_set::iterator iter = large_blocks.lower_bound(&key);
+		large_block_set::iterator end = large_blocks.end();
 
-	return NULL;
+		if(iter != end)
+		{
+			free_heap_block *block = *iter;
+			large_blocks.erase(iter);
+
+			free_block_count--;
+			free_space -= block->size();
+
+			return block;
+		}
+
+		return NULL;
+	}
 }
 
 free_heap_block *free_list::split_free_block(free_heap_block *block, cell size)
@@ -90,22 +110,7 @@ free_heap_block *free_list::split_free_block(free_heap_block *block, cell size)
 
 bool free_list::can_allot_p(cell size)
 {
-	/* Check small free lists */
-	for(cell i = size / block_granularity; i < free_list_count; i++)
-	{
-		if(small_blocks[i].size()) return true;
-	}
-
-	/* Check large free lists */
-	large_block_set::const_iterator iter = large_blocks.begin();
-	large_block_set::const_iterator end = large_blocks.end();
-
-	for(; iter != end; iter++)
-	{
-		if((*iter)->size() >= size) return true;
-	}
-
-	return false;
+	return largest_free_block() >= std::max(size,allocation_page_size);
 }
 
 cell free_list::largest_free_block()
diff --git a/vm/free_list.hpp b/vm/free_list.hpp
old mode 100644
new mode 100755
index 305de0ac58..3fb06babc9
--- a/vm/free_list.hpp
+++ b/vm/free_list.hpp
@@ -2,6 +2,7 @@ namespace factor
 {
 
 static const cell free_list_count = 32;
+static const cell allocation_page_size = 1024;
 
 struct free_heap_block
 {
@@ -9,22 +10,29 @@ struct free_heap_block
 
 	bool free_p() const
 	{
-		return header & 1 == 1;
+		return (header & 1) == 1;
 	}
 
 	cell size() const
 	{
-		return header >> 3;
+		cell size = header & ~7;
+#ifdef FACTOR_DEBUG
+		assert(size > 0);
+#endif
+		return size;
 	}
 
 	void make_free(cell size)
 	{
-		header = (size << 3) | 1;
+#ifdef FACTOR_DEBUG
+		assert(size > 0);
+#endif
+		header = size | 1;
 	}
 };
 
 struct block_size_compare {
-	bool operator()(free_heap_block *a, free_heap_block *b)
+	bool operator()(free_heap_block *a, free_heap_block *b) const
 	{
 		return a->size() < b->size();
 	}
diff --git a/vm/free_list_allocator.hpp b/vm/free_list_allocator.hpp
index a4801daa72..4c725bcf4f 100644
--- a/vm/free_list_allocator.hpp
+++ b/vm/free_list_allocator.hpp
@@ -23,7 +23,6 @@ template struct free_list_allocator {
 	cell largest_free_block();
 	cell free_block_count();
 	void sweep();
-	template void sweep(Iterator &iter);
 	template void compact(Iterator &iter, Sizer &sizer);
 	template void iterate(Iterator &iter, Sizer &sizer);
 	template void iterate(Iterator &iter);
@@ -85,7 +84,7 @@ template bool free_list_allocator::can_allot_p(cell size)
 
 template Block *free_list_allocator::allot(cell size)
 {
-	size = align(size,block_granularity);
+	size = align(size,data_alignment);
 
 	free_heap_block *block = free_blocks.find_free_block(size);
 	if(block)
@@ -152,59 +151,6 @@ void free_list_allocator::sweep()
 	}
 }
 
-template
-template
-void free_list_allocator::sweep(Iterator &iter)
-{
-	free_blocks.clear_free_list();
-
-	Block *prev = NULL;
-	Block *scan = this->first_block();
-	Block *end = this->last_block();
-
-	while(scan != end)
-	{
-		cell size = scan->size();
-
-		if(scan->free_p())
-		{
-			if(prev && prev->free_p())
-			{
-				free_heap_block *free_prev = (free_heap_block *)prev;
-				free_prev->make_free(free_prev->size() + size);
-			}
-			else
-				prev = scan;
-		}
-		else if(this->state.marked_p(scan))
-		{
-			if(prev && prev->free_p())
-				free_blocks.add_to_free_list((free_heap_block *)prev);
-			prev = scan;
-			iter(scan,size);
-		}
-		else
-		{
-			if(prev && prev->free_p())
-			{
-				free_heap_block *free_prev = (free_heap_block *)prev;
-				free_prev->make_free(free_prev->size() + size);
-			}
-			else
-			{
-				free_heap_block *free_block = (free_heap_block *)scan;
-				free_block->make_free(size);
-				prev = scan;
-			}
-		}
-
-		scan = (Block *)((cell)scan + size);
-	}
-
-	if(prev && prev->free_p())
-		free_blocks.add_to_free_list((free_heap_block *)prev);
-}
-
 template struct heap_compactor {
 	mark_bits *state;
 	char *address;
diff --git a/vm/full_collector.cpp b/vm/full_collector.cpp
index 3b92e2574e..4de2814f1d 100644
--- a/vm/full_collector.cpp
+++ b/vm/full_collector.cpp
@@ -3,11 +3,39 @@
 namespace factor
 {
 
+inline static code_block_visitor make_code_visitor(factor_vm *parent)
+{
+	return code_block_visitor(parent,code_workhorse(parent));
+}
+
 full_collector::full_collector(factor_vm *parent_) :
 	collector(
 		parent_,
 		parent_->data->tenured,
-		full_policy(parent_)) {}
+		full_policy(parent_)),
+	code_visitor(make_code_visitor(parent_)) {}
+
+void full_collector::trace_code_block(code_block *compiled)
+{
+	data_visitor.visit_code_block_objects(compiled);
+	data_visitor.visit_embedded_literals(compiled);
+	code_visitor.visit_embedded_code_pointers(compiled);
+}
+
+void full_collector::trace_context_code_blocks()
+{
+	code_visitor.visit_context_code_blocks();
+}
+
+void full_collector::trace_uninitialized_code_blocks()
+{
+	code_visitor.visit_uninitialized_code_blocks();
+}
+
+void full_collector::trace_object_code_block(object *obj)
+{
+	code_visitor.visit_object_code_block(obj);
+}
 
 /* After a sweep, invalidate any code heap roots which are not marked,
 so that if a block makes a tail call to a generic word, and the PIC
@@ -23,85 +51,45 @@ void factor_vm::update_code_roots_for_sweep()
 	for(; iter < end; iter++)
 	{
 		code_root *root = *iter;
-		code_block *block = (code_block *)(root->value & -block_granularity);
+		code_block *block = (code_block *)(root->value & -data_alignment);
 		if(root->valid && !state->marked_p(block))
 			root->valid = false;
 	}
 }
 
-/* After a compaction, invalidate any code heap roots which are not
-marked as above, and also slide the valid roots up so that call sites
-can be updated correctly. */
-void factor_vm::update_code_roots_for_compaction()
-{
-	std::vector::const_iterator iter = code_roots.begin();
-	std::vector::const_iterator end = code_roots.end();
-
-	mark_bits *state = &code->allocator->state;
-
-	for(; iter < end; iter++)
-	{
-		code_root *root = *iter;
-		code_block *block = (code_block *)(root->value & -block_granularity);
-
-		/* Offset of return address within 16-byte allocation line */
-		cell offset = root->value - (cell)block;
-
-		if(root->valid && state->marked_p((code_block *)root->value))
-		{
-			block = state->forward_block(block);
-			root->value = (cell)block + offset;
-		}
-		else
-			root->valid = false;
-	}
-}
-
-struct code_block_marker {
-	code_heap *code;
-	full_collector *collector;
-
-	explicit code_block_marker(code_heap *code_, full_collector *collector_) :
-		code(code_), collector(collector_) {}
-
-	code_block *operator()(code_block *compiled)
-	{
-		if(!code->marked_p(compiled))
-		{
-			code->set_marked_p(compiled);
-			collector->trace_literal_references(compiled);
-		}
-
-		return compiled;
-	}
-};
-
 void factor_vm::collect_mark_impl(bool trace_contexts_p)
 {
 	full_collector collector(this);
 
+	mark_stack.clear();
+
 	code->clear_mark_bits();
 	data->tenured->clear_mark_bits();
-	data->tenured->clear_mark_stack();
-
-	code_block_visitor code_marker(this,code_block_marker(code,&collector));
 
 	collector.trace_roots();
         if(trace_contexts_p)
 	{
 		collector.trace_contexts();
-		code_marker.visit_context_code_blocks();
-		code_marker.visit_callback_code_blocks();
+		collector.trace_context_code_blocks();
+		collector.trace_uninitialized_code_blocks();
 	}
 
-	std::vector *mark_stack = &data->tenured->mark_stack;
-
-	while(!mark_stack->empty())
+	while(!mark_stack.empty())
 	{
-		object *obj = mark_stack->back();
-		mark_stack->pop_back();
-		collector.trace_object(obj);
-		code_marker.visit_object_code_block(obj);
+		cell ptr = mark_stack.back();
+		mark_stack.pop_back();
+
+		if(ptr & 1)
+		{
+			code_block *compiled = (code_block *)(ptr - 1);
+			collector.trace_code_block(compiled);
+		}
+		else
+		{
+			object *obj = (object *)ptr;
+			collector.trace_object(obj);
+			collector.trace_object_code_block(obj);
+		}
 	}
 
 	data->reset_generation(data->tenured);
@@ -114,34 +102,34 @@ void factor_vm::collect_sweep_impl()
 {
 	current_gc->event->started_data_sweep();
 	data->tenured->sweep();
-	update_code_roots_for_sweep();
 	current_gc->event->ended_data_sweep();
+
+	update_code_roots_for_sweep();
+
+	current_gc->event->started_code_sweep();
+	code->allocator->sweep();
+	current_gc->event->ended_code_sweep();
 }
 
 void factor_vm::collect_full(bool trace_contexts_p)
 {
 	collect_mark_impl(trace_contexts_p);
 	collect_sweep_impl();
-	if(data->tenured->largest_free_block() <= data->nursery->size + data->aging->size)
+
+	if(data->low_memory_p())
+	{
+		current_gc->op = collect_growing_heap_op;
+		current_gc->event->op = collect_growing_heap_op;
+		collect_growing_heap(0,trace_contexts_p);
+	}
+	else if(data->high_fragmentation_p())
+	{
+		current_gc->op = collect_compact_op;
+		current_gc->event->op = collect_compact_op;
 		collect_compact_impl(trace_contexts_p);
-	else
-		update_code_heap_words_and_literals();
-}
+	}
 
-void factor_vm::collect_compact(bool trace_contexts_p)
-{
-	collect_mark_impl(trace_contexts_p);
-	collect_compact_impl(trace_contexts_p);
-}
-
-void factor_vm::collect_growing_heap(cell requested_bytes, bool trace_contexts_p)
-{
-	/* Grow the data heap and copy all live objects to the new heap. */
-	data_heap *old = data;
-	set_data_heap(data->grow(requested_bytes));
-	collect_mark_impl(trace_contexts_p);
-	collect_compact_code_impl(trace_contexts_p);
-	delete old;
+	code->flush_icache();
 }
 
 }
diff --git a/vm/full_collector.hpp b/vm/full_collector.hpp
index eb125b7429..ba859e28c9 100644
--- a/vm/full_collector.hpp
+++ b/vm/full_collector.hpp
@@ -14,20 +14,43 @@ struct full_policy {
 
 	void promoted_object(object *obj)
 	{
-		tenured->mark_and_push(obj);
+		tenured->set_marked_p(obj);
+		parent->mark_stack.push_back((cell)obj);
 	}
 
 	void visited_object(object *obj)
 	{
 		if(!tenured->marked_p(obj))
-			tenured->mark_and_push(obj);
+			promoted_object(obj);
+	}
+};
+
+struct code_workhorse {
+	factor_vm *parent;
+	code_heap *code;
+
+	explicit code_workhorse(factor_vm *parent_) : parent(parent_), code(parent->code) {}
+
+	code_block *operator()(code_block *compiled)
+	{
+		if(!code->marked_p(compiled))
+		{
+			code->set_marked_p(compiled);
+			parent->mark_stack.push_back((cell)compiled + 1);
+		}
+
+		return compiled;
 	}
 };
 
 struct full_collector : collector {
-	bool trace_contexts_p;
+	code_block_visitor code_visitor;
 
 	explicit full_collector(factor_vm *parent_);
+	void trace_code_block(code_block *compiled);
+	void trace_context_code_blocks();
+	void trace_uninitialized_code_blocks();
+	void trace_object_code_block(object *obj);
 };
 
 }
diff --git a/vm/gc.cpp b/vm/gc.cpp
index de8a2886f7..a57f338c44 100755
--- a/vm/gc.cpp
+++ b/vm/gc.cpp
@@ -8,7 +8,7 @@ gc_event::gc_event(gc_op op_, factor_vm *parent) :
 	cards_scanned(0),
 	decks_scanned(0),
 	code_blocks_scanned(0),
-	start_time(current_micros()),
+	start_time(nano_count()),
 	card_scan_time(0),
 	code_scan_time(0),
 	data_sweep_time(0),
@@ -17,70 +17,70 @@ gc_event::gc_event(gc_op op_, factor_vm *parent) :
 {
 	data_heap_before = parent->data_room();
 	code_heap_before = parent->code_room();
-	start_time = current_micros();
+	start_time = nano_count();
 }
 
 void gc_event::started_card_scan()
 {
-	temp_time = current_micros();
+	temp_time = nano_count();
 }
 
 void gc_event::ended_card_scan(cell cards_scanned_, cell decks_scanned_)
 {
 	cards_scanned += cards_scanned_;
 	decks_scanned += decks_scanned_;
-	card_scan_time = (current_micros() - temp_time);
+	card_scan_time = (cell)(nano_count() - temp_time);
 }
 
 void gc_event::started_code_scan()
 {
-	temp_time = current_micros();
+	temp_time = nano_count();
 }
 
 void gc_event::ended_code_scan(cell code_blocks_scanned_)
 {
 	code_blocks_scanned += code_blocks_scanned_;
-	code_scan_time = (current_micros() - temp_time);
+	code_scan_time = (cell)(nano_count() - temp_time);
 }
 
 void gc_event::started_data_sweep()
 {
-	temp_time = current_micros();
+	temp_time = nano_count();
 }
 
 void gc_event::ended_data_sweep()
 {
-	data_sweep_time = (current_micros() - temp_time);
+	data_sweep_time = (cell)(nano_count() - temp_time);
 }
 
 void gc_event::started_code_sweep()
 {
-	temp_time = current_micros();
+	temp_time = nano_count();
 }
 
 void gc_event::ended_code_sweep()
 {
-	code_sweep_time = (current_micros() - temp_time);
+	code_sweep_time = (cell)(nano_count() - temp_time);
 }
 
 void gc_event::started_compaction()
 {
-	temp_time = current_micros();
+	temp_time = nano_count();
 }
 
 void gc_event::ended_compaction()
 {
-	compaction_time = (current_micros() - temp_time);
+	compaction_time = (cell)(nano_count() - temp_time);
 }
 
 void gc_event::ended_gc(factor_vm *parent)
 {
 	data_heap_after = parent->data_room();
 	code_heap_after = parent->code_room();
-	total_time = current_micros() - start_time;
+	total_time = (cell)(nano_count() - start_time);
 }
 
-gc_state::gc_state(gc_op op_, factor_vm *parent) : op(op_), start_time(current_micros())
+gc_state::gc_state(gc_op op_, factor_vm *parent) : op(op_), start_time(nano_count())
 {
 	event = new gc_event(op,parent);
 }
@@ -126,22 +126,11 @@ void factor_vm::start_gc_again()
 	current_gc->event = new gc_event(current_gc->op,this);
 }
 
-void factor_vm::update_code_heap_for_minor_gc(std::set *remembered_set)
-{
-	/* The youngest generation that any code block can now reference */
-	std::set::const_iterator iter = remembered_set->begin();
-	std::set::const_iterator end = remembered_set->end();
-
-	for(; iter != end; iter++) update_literal_references(*iter);
-}
-
 void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
 {
 	assert(!gc_off);
 	assert(!current_gc);
 
-	save_stacks();
-
 	current_gc = new gc_state(op,this);
 
 	/* Keep trying to GC higher and higher generations until we don't run out
@@ -161,7 +150,7 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
 		break;
 	case collect_aging_op:
 		collect_aging();
-		if(data->low_memory_p())
+		if(data->high_fragmentation_p())
 		{
 			current_gc->op = collect_full_op;
 			current_gc->event->op = collect_full_op;
@@ -170,7 +159,7 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
 		break;
 	case collect_to_tenured_op:
 		collect_to_tenured();
-		if(data->low_memory_p())
+		if(data->high_fragmentation_p())
 		{
 			current_gc->op = collect_full_op;
 			current_gc->event->op = collect_full_op;
@@ -187,7 +176,7 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
 		collect_growing_heap(requested_bytes,trace_contexts_p);
 		break;
 	default:
-		critical_error("Bad GC op\n",current_gc->op);
+		critical_error("Bad GC op",current_gc->op);
 		break;
 	}
 
@@ -218,46 +207,11 @@ void factor_vm::primitive_compact_gc()
 		true /* trace contexts? */);
 }
 
-/* classes.tuple uses this to reshape tuples; tools.deploy.shaker uses this
-   to coalesce equal but distinct quotations and wrappers. */
-void factor_vm::primitive_become()
-{
-	array *new_objects = untag_check(dpop());
-	array *old_objects = untag_check(dpop());
-
-	cell capacity = array_capacity(new_objects);
-	if(capacity != array_capacity(old_objects))
-		critical_error("bad parameters to become",0);
-
-	cell i;
-
-	for(i = 0; i < capacity; i++)
-	{
-		tagged old_obj(array_nth(old_objects,i));
-		tagged new_obj(array_nth(new_objects,i));
-
-		if(old_obj != new_obj)
-			old_obj->h.forward_to(new_obj.untagged());
-	}
-
-	primitive_full_gc();
-
-	/* If a word's definition quotation was in old_objects and the
-	   quotation in new_objects is not compiled, we might leak memory
-	   by referencing the old quotation unless we recompile all
-	   unoptimized words. */
-	compile_all_words();
-}
-
 void factor_vm::inline_gc(cell *data_roots_base, cell data_roots_size)
 {
-	for(cell i = 0; i < data_roots_size; i++)
-		data_roots.push_back((cell)&data_roots_base[i]);
-
+	data_roots.push_back(data_root_range(data_roots_base,data_roots_size));
 	primitive_minor_gc();
-
-	for(cell i = 0; i < data_roots_size; i++)
-		data_roots.pop_back();
+	data_roots.pop_back();
 }
 
 VM_C_API void inline_gc(cell *data_roots_base, cell data_roots_size, factor_vm *parent)
@@ -269,7 +223,7 @@ VM_C_API void inline_gc(cell *data_roots_base, cell data_roots_size, factor_vm *
  * It is up to the caller to fill in the object's fields in a meaningful
  * fashion!
  */
-object *factor_vm::allot_large_object(header header, cell size)
+object *factor_vm::allot_large_object(cell type, cell size)
 {
 	/* If tenured space does not have enough room, collect and compact */
 	if(!data->tenured->can_allot_p(size))
@@ -290,11 +244,9 @@ object *factor_vm::allot_large_object(header header, cell size)
 	/* Allows initialization code to store old->new pointers
 	without hitting the write barrier in the common case of
 	a nursery allocation */
-	char *start = (char *)obj;
-	for(cell offset = 0; offset < size; offset += card_size)
-		write_barrier((cell *)(start + offset));
+	write_barrier(obj,size);
 
-	obj->h = header;
+	obj->initialize(type);
 	return obj;
 }
 
@@ -307,14 +259,28 @@ void factor_vm::primitive_disable_gc_events()
 {
 	if(gc_events)
 	{
-		byte_array *data = byte_array_from_values(&gc_events->front(),gc_events->size());
-		dpush(tag(data));
+		growable_array result(this);
 
-		delete gc_events;
-		gc_events = NULL;
+		std::vector *gc_events = this->gc_events;
+		this->gc_events = NULL;
+
+		std::vector::const_iterator iter = gc_events->begin();
+		std::vector::const_iterator end = gc_events->end();
+
+		for(; iter != end; iter++)
+		{
+			gc_event event = *iter;
+			byte_array *obj = byte_array_from_value(&event);
+			result.add(tag(obj));
+		}
+
+		result.trim();
+		ctx->push(result.elements.value());
+
+		delete this->gc_events;
 	}
 	else
-		dpush(false_object);
+		ctx->push(false_object);
 }
 
 }
diff --git a/vm/gc.hpp b/vm/gc.hpp
index a9250eddb2..d80d57dafe 100755
--- a/vm/gc.hpp
+++ b/vm/gc.hpp
@@ -26,7 +26,7 @@ struct gc_event {
 	cell data_sweep_time;
 	cell code_sweep_time;
 	cell compaction_time;
-	cell temp_time;
+	u64 temp_time;
 
 	explicit gc_event(gc_op op_, factor_vm *parent);
 	void started_card_scan();
diff --git a/vm/generic_arrays.hpp b/vm/generic_arrays.hpp
index f45785f9ef..4c3620277c 100755
--- a/vm/generic_arrays.hpp
+++ b/vm/generic_arrays.hpp
@@ -4,7 +4,7 @@ namespace factor
 template cell array_capacity(const Array *array)
 {
 #ifdef FACTOR_DEBUG
-	assert(array->h.hi_tag() == Array::type_number);
+	assert(array->type() == Array::type_number);
 #endif
 	return array->capacity >> TAG_BITS;
 }
diff --git a/vm/image.cpp b/vm/image.cpp
index b3a9eae7a5..68701c4736 100755
--- a/vm/image.cpp
+++ b/vm/image.cpp
@@ -55,177 +55,177 @@ void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p)
 	code->allocator->initial_free_list(h->code_size);
 }
 
-void factor_vm::data_fixup(cell *handle, cell data_relocation_base)
-{
-	if(immediate_p(*handle))
-		return;
+struct data_fixupper {
+	cell offset;
 
-	*handle += (data->tenured->start - data_relocation_base);
-}
+	explicit data_fixupper(cell offset_) : offset(offset_) {}
 
-template void factor_vm::code_fixup(Type **handle, cell code_relocation_base)
-{
-	Type *ptr = *handle;
-	Type *new_ptr = (Type *)(((cell)ptr) + (code->seg->start - code_relocation_base));
-	*handle = new_ptr;
-}
-
-void factor_vm::fixup_word(word *word, cell code_relocation_base)
-{
-	if(word->code)
-		code_fixup(&word->code,code_relocation_base);
-	if(word->profiling)
-		code_fixup(&word->profiling,code_relocation_base);
-	code_fixup(&word->xt,code_relocation_base);
-}
-
-void factor_vm::fixup_quotation(quotation *quot, cell code_relocation_base)
-{
-	if(quot->code)
+	object *operator()(object *obj)
 	{
-		code_fixup("->xt,code_relocation_base);
-		code_fixup("->code,code_relocation_base);
-	}
-	else
-		quot->xt = (void *)lazy_jit_compile;
-}
-
-void factor_vm::fixup_alien(alien *ptr)
-{
-	if(!to_boolean(ptr->base))
-		ptr->expired = true_object;
-	else
-		ptr->update_address();
-}
-
-struct stack_frame_fixupper {
-	factor_vm *parent;
-	cell code_relocation_base;
-
-	explicit stack_frame_fixupper(factor_vm *parent_, cell code_relocation_base_) :
-		parent(parent_), code_relocation_base(code_relocation_base_) {}
-	void operator()(stack_frame *frame)
-	{
-		parent->code_fixup(&frame->xt,code_relocation_base);
-		parent->code_fixup(&FRAME_RETURN_ADDRESS(frame,parent),code_relocation_base);
+		return (object *)((char *)obj + offset);
 	}
 };
 
-void factor_vm::fixup_callstack_object(callstack *stack, cell code_relocation_base)
+struct code_fixupper {
+	cell offset;
+
+	explicit code_fixupper(cell offset_) : offset(offset_) {}
+
+	code_block *operator()(code_block *compiled)
+	{
+		return (code_block *)((char *)compiled + offset);
+	}
+};
+
+static inline cell tuple_size_with_fixup(cell offset, object *obj)
 {
-	stack_frame_fixupper fixupper(this,code_relocation_base);
-	iterate_callstack_object(stack,fixupper);
+	tuple_layout *layout = (tuple_layout *)((char *)UNTAG(((tuple *)obj)->layout) + offset);
+	return tuple_size(layout);
 }
 
+struct fixup_sizer {
+	cell offset;
+
+	explicit fixup_sizer(cell offset_) : offset(offset_) {}
+
+	cell operator()(object *obj)
+	{
+		if(obj->type() == TUPLE_TYPE)
+			return align(tuple_size_with_fixup(offset,obj),data_alignment);
+		else
+			return obj->size();
+	}
+};
+
 struct object_fixupper {
 	factor_vm *parent;
-	cell data_relocation_base;
+	cell data_offset;
+	slot_visitor data_visitor;
+	code_block_visitor code_visitor;
 
-	explicit object_fixupper(factor_vm *parent_, cell data_relocation_base_) :
-		parent(parent_), data_relocation_base(data_relocation_base_) { }
+	object_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) :
+		parent(parent_),
+		data_offset(data_offset_),
+		data_visitor(slot_visitor(parent_,data_fixupper(data_offset_))),
+		code_visitor(code_block_visitor(parent_,code_fixupper(code_offset_))) {}
 
-	void operator()(cell *scan)
+	void operator()(object *obj, cell size)
 	{
-		parent->data_fixup(scan,data_relocation_base);
+		parent->data->tenured->starts.record_object_start_offset(obj);
+
+		switch(obj->type())
+		{
+		case ALIEN_TYPE:
+			{
+				cell payload_start = obj->binary_payload_start();
+				data_visitor.visit_slots(obj,payload_start);
+
+				alien *ptr = (alien *)obj;
+
+				if(to_boolean(ptr->base))
+					ptr->update_address();
+				else
+					ptr->expired = parent->true_object;
+				break;
+			}
+		case DLL_TYPE:
+			{
+				cell payload_start = obj->binary_payload_start();
+				data_visitor.visit_slots(obj,payload_start);
+
+				parent->ffi_dlopen((dll *)obj);
+				break;
+			}
+		case TUPLE_TYPE:
+			{
+				cell payload_start = tuple_size_with_fixup(data_offset,obj);
+				data_visitor.visit_slots(obj,payload_start);
+				break;
+			}
+		default:
+			{
+				cell payload_start = obj->binary_payload_start();
+				data_visitor.visit_slots(obj,payload_start);
+				code_visitor.visit_object_code_block(obj);
+				break;
+			}
+		}
 	}
 };
 
-/* Initialize an object in a newly-loaded image */
-void factor_vm::relocate_object(object *object,
-	cell data_relocation_base,
-	cell code_relocation_base)
+void factor_vm::fixup_data(cell data_offset, cell code_offset)
 {
-	cell hi_tag = object->h.hi_tag();
-	
-	/* Tuple relocation is a bit trickier; we have to fix up the
-	layout object before we can get the tuple size, so do_slots is
-	out of the question */
-	if(hi_tag == TUPLE_TYPE)
+	slot_visitor data_workhorse(this,data_fixupper(data_offset));
+	data_workhorse.visit_roots();
+
+	object_fixupper fixupper(this,data_offset,code_offset);
+	fixup_sizer sizer(data_offset);
+	data->tenured->iterate(fixupper,sizer);
+}
+
+struct code_block_fixup_relocation_visitor {
+	factor_vm *parent;
+	cell code_offset;
+	slot_visitor data_visitor;
+	code_fixupper code_visitor;
+
+	code_block_fixup_relocation_visitor(factor_vm *parent_, cell data_offset_, cell code_offset_) :
+		parent(parent_),
+		code_offset(code_offset_),
+		data_visitor(slot_visitor(parent_,data_fixupper(data_offset_))),
+		code_visitor(code_fixupper(code_offset_)) {}
+
+	void operator()(instruction_operand op)
 	{
-		tuple *t = (tuple *)object;
-		data_fixup(&t->layout,data_relocation_base);
+		code_block *compiled = op.parent_code_block();
+		cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - code_offset;
 
-		cell *scan = t->data();
-		cell *end = (cell *)((cell)object + object->size());
-
-		for(; scan < end; scan++)
-			data_fixup(scan,data_relocation_base);
-	}
-	else
-	{
-		object_fixupper fixupper(this,data_relocation_base);
-		do_slots((cell)object,fixupper);
-
-		switch(hi_tag)
+		switch(op.rel_type())
 		{
-		case WORD_TYPE:
-			fixup_word((word *)object,code_relocation_base);
+		case RT_LITERAL:
+			op.store_value(data_visitor.visit_pointer(op.load_value(old_offset)));
 			break;
-		case QUOTATION_TYPE:
-			fixup_quotation((quotation *)object,code_relocation_base);
+		case RT_ENTRY_POINT:
+		case RT_ENTRY_POINT_PIC:
+		case RT_ENTRY_POINT_PIC_TAIL:
+			op.store_code_block(code_visitor(op.load_code_block(old_offset)));
 			break;
-		case DLL_TYPE:
-			ffi_dlopen((dll *)object);
+		case RT_HERE:
+			op.store_value(op.load_value(old_offset) + code_offset);
 			break;
-		case ALIEN_TYPE:
-			fixup_alien((alien *)object);
+		case RT_UNTAGGED:
 			break;
-		case CALLSTACK_TYPE:
-			fixup_callstack_object((callstack *)object,code_relocation_base);
+		default:
+			parent->store_external_address(op);
 			break;
 		}
 	}
-}
-
-/* Since the image might have been saved with a different base address than
-where it is loaded, we need to fix up pointers in the image. */
-void factor_vm::relocate_data(cell data_relocation_base, cell code_relocation_base)
-{
-	for(cell i = 0; i < special_object_count; i++)
-		data_fixup(&special_objects[i],data_relocation_base);
-
-	data_fixup(&true_object,data_relocation_base);
-	data_fixup(&bignum_zero,data_relocation_base);
-	data_fixup(&bignum_pos_one,data_relocation_base);
-	data_fixup(&bignum_neg_one,data_relocation_base);
-
-	cell obj = data->tenured->start;
-
-	while(obj)
-	{
-		relocate_object((object *)obj,data_relocation_base,code_relocation_base);
-		data->tenured->starts.record_object_start_offset((object *)obj);
-		obj = data->tenured->next_object_after(obj);
-	}
-}
-
-void factor_vm::fixup_code_block(code_block *compiled, cell data_relocation_base)
-{
-	/* relocate literal table data */
-	data_fixup(&compiled->owner,data_relocation_base);
-	data_fixup(&compiled->literals,data_relocation_base);
-	data_fixup(&compiled->relocation,data_relocation_base);
-
-	relocate_code_block(compiled);
-}
+};
 
 struct code_block_fixupper {
 	factor_vm *parent;
-	cell data_relocation_base;
+	cell data_offset;
+	cell code_offset;
 
-	explicit code_block_fixupper(factor_vm *parent_, cell data_relocation_base_) :
-		parent(parent_), data_relocation_base(data_relocation_base_) { }
+	code_block_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) :
+		parent(parent_),
+		data_offset(data_offset_),
+		code_offset(code_offset_) {}
 
 	void operator()(code_block *compiled, cell size)
 	{
-		parent->fixup_code_block(compiled,data_relocation_base);
+		slot_visitor data_visitor(parent,data_fixupper(data_offset));
+		data_visitor.visit_code_block_objects(compiled);
+
+		code_block_fixup_relocation_visitor code_visitor(parent,data_offset,code_offset);
+		compiled->each_instruction_operand(code_visitor);
 	}
 };
 
-void factor_vm::relocate_code(cell data_relocation_base)
+void factor_vm::fixup_code(cell data_offset, cell code_offset)
 {
-	code_block_fixupper fixupper(this,data_relocation_base);
-	iterate_code_heap(fixupper);
+	code_block_fixupper fixupper(this,data_offset,code_offset);
+	code->allocator->iterate(fixupper);
 }
 
 /* Read an image file from disk, only done once during startup */
@@ -257,8 +257,11 @@ void factor_vm::load_image(vm_parameters *p)
 
 	init_objects(&h);
 
-	relocate_data(h.data_relocation_base,h.code_relocation_base);
-	relocate_code(h.data_relocation_base);
+	cell data_offset = data->tenured->start - h.data_relocation_base;
+	cell code_offset = code->seg->start - h.code_relocation_base;
+
+	fixup_data(data_offset,code_offset);
+	fixup_code(data_offset,code_offset);
 
 	/* Store image path name */
 	special_objects[OBJ_IMAGE] = allot_alien(false_object,(cell)p->image_path);
@@ -291,7 +294,7 @@ bool factor_vm::save_image(const vm_char *filename)
 	h.bignum_neg_one = bignum_neg_one;
 
 	for(cell i = 0; i < special_object_count; i++)
-		h.special_objects[i] = (save_env_p(i) ? special_objects[i] : false_object);
+		h.special_objects[i] = (save_special_p(i) ? special_objects[i] : false_object);
 
 	bool ok = true;
 
@@ -311,7 +314,7 @@ void factor_vm::primitive_save_image()
 	/* do a full GC to push everything into tenured space */
 	primitive_compact_gc();
 
-	data_root path(dpop(),this);
+	data_root path(ctx->pop(),this);
 	path.untag_check(this);
 	save_image((vm_char *)(path.untagged() + 1));
 }
@@ -321,12 +324,12 @@ void factor_vm::primitive_save_image_and_exit()
 	/* We unbox this before doing anything else. This is the only point
 	where we might throw an error, so we have to throw an error here since
 	later steps destroy the current image. */
-	data_root path(dpop(),this);
+	data_root path(ctx->pop(),this);
 	path.untag_check(this);
 
 	/* strip out special_objects data which is set on startup anyway */
 	for(cell i = 0; i < special_object_count; i++)
-		if(!save_env_p(i)) special_objects[i] = false_object;
+		if(!save_special_p(i)) special_objects[i] = false_object;
 
 	gc(collect_compact_op,
 		0, /* requested size */
diff --git a/vm/image.hpp b/vm/image.hpp
index cca0e9e378..101482b1da 100755
--- a/vm/image.hpp
+++ b/vm/image.hpp
@@ -7,12 +7,11 @@ static const cell image_version = 4;
 struct image_header {
 	cell magic;
 	cell version;
-	/* all pointers in the image file are relocated from
-	   relocation_base to here when the image is loaded */
+	/* base address of data heap when image was saved */
 	cell data_relocation_base;
 	/* size of heap */
 	cell data_size;
-	/* code relocation base */
+	/* base address of code heap when image was saved */
 	cell code_relocation_base;
 	/* size of code heap */
 	cell code_size;
diff --git a/vm/inline_cache.cpp b/vm/inline_cache.cpp
index 469bb8bf2e..c8a1b22879 100755
--- a/vm/inline_cache.cpp
+++ b/vm/inline_cache.cpp
@@ -11,14 +11,14 @@ void factor_vm::init_inline_caching(int max_size)
 void factor_vm::deallocate_inline_cache(cell return_address)
 {
 	/* Find the call target. */
-	void *old_xt = get_call_target(return_address);
-	check_code_pointer((cell)old_xt);
+	void *old_entry_point = get_call_target(return_address);
+	check_code_pointer((cell)old_entry_point);
 
-	code_block *old_block = (code_block *)old_xt - 1;
+	code_block *old_block = (code_block *)old_entry_point - 1;
 
 	/* Free the old PIC since we know its unreachable */
 	if(old_block->pic_p())
-		code->code_heap_free(old_block);
+		code->free(old_block);
 }
 
 /* Figure out what kind of type check the PIC needs based on the methods
@@ -70,7 +70,7 @@ void inline_cache_jit::emit_check(cell klass)
 	else
 		code_template = parent->special_objects[PIC_CHECK_TUPLE];
 
-	emit_with(code_template,klass);
+	emit_with_literal(code_template,klass);
 }
 
 /* index: 0 = top of stack, 1 = item underneath, etc
@@ -101,19 +101,27 @@ void inline_cache_jit::compile_inline_cache(fixnum index,
 
 		/* Yes? Jump to method */
 		cell method = array_nth(cache_entries.untagged(),i + 1);
-		emit_with(parent->special_objects[PIC_HIT],method);
+		emit_with_literal(parent->special_objects[PIC_HIT],method);
 	}
 
-	/* Generate machine code to handle a cache miss, which ultimately results in
-	   this function being called again.
+	/* If none of the above conditionals tested true, then execution "falls
+	   through" to here. */
 
-	   The inline-cache-miss primitive call receives enough information to
-	   reconstruct the PIC. */
+	/* A stack frame is set up, since the inline-cache-miss sub-primitive
+	makes a subroutine call to the VM. */
+	emit(parent->special_objects[JIT_PROLOG]);
+
+	/* The inline-cache-miss sub-primitive call receives enough information to
+	   reconstruct the PIC with the new entry. */
 	push(generic_word.value());
 	push(methods.value());
 	push(tag_fixnum(index));
 	push(cache_entries.value());
-	word_special(parent->special_objects[tail_call_p ? PIC_MISS_TAIL_WORD : PIC_MISS_WORD]);
+
+	emit_subprimitive(
+		parent->special_objects[tail_call_p ? PIC_MISS_TAIL_WORD : PIC_MISS_WORD],
+		true, /* tail_call_p */
+		true); /* stack_frame_p */
 }
 
 code_block *factor_vm::compile_inline_cache(fixnum index,
@@ -133,14 +141,14 @@ code_block *factor_vm::compile_inline_cache(fixnum index,
 				 cache_entries.value(),
 				 tail_call_p);
 	code_block *code = jit.to_code_block();
-	relocate_code_block(code);
+	initialize_code_block(code);
 	return code;
 }
 
 /* A generic word's definition performs general method lookup. */
 void *factor_vm::megamorphic_call_stub(cell generic_word)
 {
-	return untag(generic_word)->xt;
+	return untag(generic_word)->entry_point;
 }
 
 cell factor_vm::inline_cache_size(cell cache_entries)
@@ -180,26 +188,28 @@ to take care of the details. */
 void *factor_vm::inline_cache_miss(cell return_address_)
 {
 	code_root return_address(return_address_,this);
-
 	check_code_pointer(return_address.value);
+	bool tail_call_site = tail_call_site_p(return_address.value);
 
-	/* Since each PIC is only referenced from a single call site,
-	   if the old call target was a PIC, we can deallocate it immediately,
-	   instead of leaving dead PICs around until the next GC. */
-	deallocate_inline_cache(return_address.value);
+#ifdef PIC_DEBUG
+	std::cout << "Inline cache miss at "
+		<< (tail_call_site ? "tail" : "non-tail")
+		<< " call site 0x" << std::hex << return_address.value << std::dec
+		<< std::endl;
+#endif
 
-	data_root cache_entries(dpop(),this);
-	fixnum index = untag_fixnum(dpop());
-	data_root methods(dpop(),this);
-	data_root generic_word(dpop(),this);
-	data_root object(((cell *)ds)[-index],this);
-
-	void *xt;
+	data_root cache_entries(ctx->pop(),this);
+	fixnum index = untag_fixnum(ctx->pop());
+	data_root methods(ctx->pop(),this);
+	data_root generic_word(ctx->pop(),this);
+	data_root object(((cell *)ctx->datastack)[-index],this);
 
 	cell pic_size = inline_cache_size(cache_entries.value());
 
 	update_pic_transitions(pic_size);
 
+	void *xt;
+
 	if(pic_size >= max_pic_size)
 		xt = megamorphic_call_stub(generic_word.value());
 	else
@@ -208,26 +218,31 @@ void *factor_vm::inline_cache_miss(cell return_address_)
 		cell method = lookup_method(object.value(),methods.value());
 
 		data_root new_cache_entries(add_inline_cache_entry(
-							   cache_entries.value(),
-							   klass,
-							   method),this);
+			cache_entries.value(),
+			klass,
+			method),this);
+
 		xt = compile_inline_cache(index,
-					  generic_word.value(),
-					  methods.value(),
-					  new_cache_entries.value(),
-					  tail_call_site_p(return_address.value))->xt();
+			generic_word.value(),
+			methods.value(),
+			new_cache_entries.value(),
+			tail_call_site)->entry_point();
 	}
 
 	/* Install the new stub. */
 	if(return_address.valid)
 	{
+		/* Since each PIC is only referenced from a single call site,
+		   if the old call target was a PIC, we can deallocate it immediately,
+		   instead of leaving dead PICs around until the next GC. */
+		deallocate_inline_cache(return_address.value);
 		set_call_target(return_address.value,xt);
 
 #ifdef PIC_DEBUG
 		std::cout << "Updated "
-			<< (tail_call_site_p(return_address) ? "tail" : "non-tail")
-			<< " call site 0x" << std::hex << return_address << std::dec
-			<< " with " << std::hex << (cell)xt << std::dec;
+			<< (tail_call_site ? "tail" : "non-tail")
+			<< " call site 0x" << std::hex << return_address.value << std::dec
+			<< " with 0x" << std::hex << (cell)xt << std::dec << std::endl;
 #endif
 	}
 
diff --git a/vm/instruction_operands.cpp b/vm/instruction_operands.cpp
new file mode 100644
index 0000000000..db869d9d01
--- /dev/null
+++ b/vm/instruction_operands.cpp
@@ -0,0 +1,138 @@
+#include "master.hpp"
+
+namespace factor
+{
+
+instruction_operand::instruction_operand(relocation_entry rel_, code_block *compiled_, cell index_) :
+	rel(rel_), compiled(compiled_), index(index_), pointer((cell)compiled_->entry_point() + rel_.rel_offset()) {}
+
+/* Load a 32-bit value from a PowerPC LIS/ORI sequence */
+fixnum instruction_operand::load_value_2_2()
+{
+	cell *ptr = (cell *)pointer;
+	cell hi = (ptr[-2] & 0xffff);
+	cell lo = (ptr[-1] & 0xffff);
+	return hi << 16 | lo;
+}
+
+/* Load a value from a bitfield of a PowerPC instruction */
+fixnum instruction_operand::load_value_masked(cell mask, cell bits, cell shift)
+{
+	s32 *ptr = (s32 *)(pointer - sizeof(u32));
+
+	return (((*ptr & (s32)mask) << bits) >> bits) << shift;
+}
+
+fixnum instruction_operand::load_value(cell relative_to)
+{
+	switch(rel.rel_class())
+	{
+	case RC_ABSOLUTE_CELL:
+		return *(cell *)(pointer - sizeof(cell));
+	case RC_ABSOLUTE:
+		return *(u32 *)(pointer - sizeof(u32));
+	case RC_RELATIVE:
+		return *(s32 *)(pointer - sizeof(u32)) + relative_to;
+	case RC_ABSOLUTE_PPC_2_2:
+		return load_value_2_2();
+	case RC_ABSOLUTE_PPC_2:
+		return load_value_masked(rel_absolute_ppc_2_mask,16,0);
+	case RC_RELATIVE_PPC_2:
+		return load_value_masked(rel_relative_ppc_2_mask,16,0) + relative_to - sizeof(cell);
+	case RC_RELATIVE_PPC_3:
+		return load_value_masked(rel_relative_ppc_3_mask,6,0) + relative_to - sizeof(cell);
+	case RC_RELATIVE_ARM_3:
+		return load_value_masked(rel_relative_arm_3_mask,6,2) + relative_to + sizeof(cell);
+	case RC_INDIRECT_ARM:
+		return load_value_masked(rel_indirect_arm_mask,20,0) + relative_to;
+	case RC_INDIRECT_ARM_PC:
+		return load_value_masked(rel_indirect_arm_mask,20,0) + relative_to + sizeof(cell);
+	case RC_ABSOLUTE_2:
+		return *(u16 *)(pointer - sizeof(u16));
+	default:
+		critical_error("Bad rel class",rel.rel_class());
+		return 0;
+	}
+}
+
+fixnum instruction_operand::load_value()
+{
+	return load_value(pointer);
+}
+
+code_block *instruction_operand::load_code_block(cell relative_to)
+{
+	return ((code_block *)load_value(relative_to) - 1);
+}
+
+code_block *instruction_operand::load_code_block()
+{
+	return load_code_block(pointer);
+}
+
+/* Store a 32-bit value into a PowerPC LIS/ORI sequence */
+void instruction_operand::store_value_2_2(fixnum value)
+{
+	cell *ptr = (cell *)pointer;
+	ptr[-2] = ((ptr[-2] & ~0xffff) | ((value >> 16) & 0xffff));
+	ptr[-1] = ((ptr[-1] & ~0xffff) | (value & 0xffff));
+}
+
+/* Store a value into a bitfield of a PowerPC instruction */
+void instruction_operand::store_value_masked(fixnum value, cell mask, cell shift)
+{
+	u32 *ptr = (u32 *)(pointer - sizeof(u32));
+	*ptr = ((*ptr & ~mask) | ((value >> shift) & mask));
+}
+
+void instruction_operand::store_value(fixnum absolute_value)
+{
+	fixnum relative_value = absolute_value - pointer;
+
+	switch(rel.rel_class())
+	{
+	case RC_ABSOLUTE_CELL:
+		*(cell *)(pointer - sizeof(cell)) = absolute_value;
+		break;
+	case RC_ABSOLUTE:
+		*(u32 *)(pointer - sizeof(u32)) = absolute_value;
+		break;
+	case RC_RELATIVE:
+		*(s32 *)(pointer - sizeof(s32)) = relative_value;
+		break;
+	case RC_ABSOLUTE_PPC_2_2:
+		store_value_2_2(absolute_value);
+		break;
+	case RC_ABSOLUTE_PPC_2:
+		store_value_masked(absolute_value,rel_absolute_ppc_2_mask,0);
+		break;
+	case RC_RELATIVE_PPC_2:
+		store_value_masked(relative_value + sizeof(cell),rel_relative_ppc_2_mask,0);
+		break;
+	case RC_RELATIVE_PPC_3:
+		store_value_masked(relative_value + sizeof(cell),rel_relative_ppc_3_mask,0);
+		break;
+	case RC_RELATIVE_ARM_3:
+		store_value_masked(relative_value - sizeof(cell),rel_relative_arm_3_mask,2);
+		break;
+	case RC_INDIRECT_ARM:
+		store_value_masked(relative_value,rel_indirect_arm_mask,0);
+		break;
+	case RC_INDIRECT_ARM_PC:
+		store_value_masked(relative_value - sizeof(cell),rel_indirect_arm_mask,0);
+		break;
+	case RC_ABSOLUTE_2:
+		*(u16 *)(pointer - sizeof(u16)) = (u16)absolute_value;
+		break;
+	default:
+		critical_error("Bad rel class",rel.rel_class());
+		break;
+	}
+}
+
+void instruction_operand::store_code_block(code_block *compiled)
+{
+	store_value((cell)compiled->entry_point());
+}
+
+}
diff --git a/vm/instruction_operands.hpp b/vm/instruction_operands.hpp
new file mode 100644
index 0000000000..d46b5cf391
--- /dev/null
+++ b/vm/instruction_operands.hpp
@@ -0,0 +1,157 @@
+namespace factor
+{
+
+enum relocation_type {
+	/* arg is a literal table index, holding a pair (symbol/dll) */
+	RT_DLSYM,
+	/* a word or quotation's general entry point */
+	RT_ENTRY_POINT,
+	/* a word's PIC entry point */
+	RT_ENTRY_POINT_PIC,
+	/* a word's tail-call PIC entry point */
+	RT_ENTRY_POINT_PIC_TAIL,
+	/* current offset */
+	RT_HERE,
+	/* current code block */
+	RT_THIS,
+	/* data heap literal */
+	RT_LITERAL,
+	/* untagged fixnum literal */
+	RT_UNTAGGED,
+	/* address of megamorphic_cache_hits var */
+	RT_MEGAMORPHIC_CACHE_HITS,
+	/* address of vm object */
+	RT_VM,
+	/* value of vm->cards_offset */
+	RT_CARDS_OFFSET,
+	/* value of vm->decks_offset */
+	RT_DECKS_OFFSET,
+};
+
+enum relocation_class {
+	/* absolute address in a 64-bit location */
+	RC_ABSOLUTE_CELL,
+	/* absolute address in a 32-bit location */
+	RC_ABSOLUTE,
+	/* relative address in a 32-bit location */
+	RC_RELATIVE,
+	/* absolute address in a PowerPC LIS/ORI sequence */
+	RC_ABSOLUTE_PPC_2_2,
+	/* absolute address in a PowerPC LWZ instruction */
+	RC_ABSOLUTE_PPC_2,
+	/* relative address in a PowerPC LWZ/STW/BC instruction */
+	RC_RELATIVE_PPC_2,
+	/* relative address in a PowerPC B/BL instruction */
+	RC_RELATIVE_PPC_3,
+	/* relative address in an ARM B/BL instruction */
+	RC_RELATIVE_ARM_3,
+	/* pointer to address in an ARM LDR/STR instruction */
+	RC_INDIRECT_ARM,
+	/* pointer to address in an ARM LDR/STR instruction offset by 8 bytes */
+	RC_INDIRECT_ARM_PC,
+	/* absolute address in a 16-bit location */
+	RC_ABSOLUTE_2
+};
+
+static const cell rel_absolute_ppc_2_mask = 0xffff;
+static const cell rel_relative_ppc_2_mask = 0xfffc;
+static const cell rel_relative_ppc_3_mask = 0x3fffffc;
+static const cell rel_indirect_arm_mask = 0xfff;
+static const cell rel_relative_arm_3_mask = 0xffffff;
+
+/* code relocation table consists of a table of entries for each fixup */
+struct relocation_entry {
+	u32 value;
+
+	explicit relocation_entry(u32 value_) : value(value_) {}
+
+	relocation_entry(relocation_type rel_type,
+		relocation_class rel_class,
+		cell offset)
+	{
+		value = (rel_type << 28) | (rel_class << 24) | offset;
+	}
+
+	relocation_type rel_type()
+	{
+		return (relocation_type)((value & 0xf0000000) >> 28);
+	}
+
+	relocation_class rel_class()
+	{
+		return (relocation_class)((value & 0x0f000000) >> 24);
+	}
+
+	cell rel_offset()
+	{
+		return (value & 0x00ffffff);
+	}
+
+	int number_of_parameters()
+	{
+		switch(rel_type())
+		{
+		case RT_VM:
+			return 1;
+		case RT_DLSYM:
+			return 2;
+		case RT_ENTRY_POINT:
+		case RT_ENTRY_POINT_PIC:
+		case RT_ENTRY_POINT_PIC_TAIL:
+		case RT_LITERAL:
+		case RT_HERE:
+		case RT_UNTAGGED:
+		case RT_THIS:
+		case RT_MEGAMORPHIC_CACHE_HITS:
+		case RT_CARDS_OFFSET:
+		case RT_DECKS_OFFSET:
+			return 0;
+		default:
+			critical_error("Bad rel type",rel_type());
+			return -1; /* Can't happen */
+		}
+	}
+};
+
+struct instruction_operand {
+	relocation_entry rel;
+	code_block *compiled;
+	cell index;
+	cell pointer;
+
+	instruction_operand(relocation_entry rel_, code_block *compiled_, cell index_);
+
+	relocation_type rel_type()
+	{
+		return rel.rel_type();
+	}
+
+	cell rel_offset()
+	{
+		return rel.rel_offset();
+	}
+
+	cell parameter_index()
+	{
+		return index;
+	}
+
+	code_block *parent_code_block()
+	{
+		return compiled;
+	}
+
+	fixnum load_value_2_2();
+	fixnum load_value_masked(cell mask, cell bits, cell shift);
+	fixnum load_value(cell relative_to);
+	fixnum load_value();
+	code_block *load_code_block(cell relative_to);
+	code_block *load_code_block();
+
+	void store_value_2_2(fixnum value);
+	void store_value_masked(fixnum value, cell mask, cell shift);
+	void store_value(fixnum value);
+	void store_code_block(code_block *compiled);
+};
+
+}
diff --git a/vm/io.cpp b/vm/io.cpp
index a8f9cb6897..a45e1d10ab 100755
--- a/vm/io.cpp
+++ b/vm/io.cpp
@@ -33,8 +33,8 @@ void factor_vm::io_error()
 
 void factor_vm::primitive_fopen()
 {
-	data_root mode(dpop(),this);
-	data_root path(dpop(),this);
+	data_root mode(ctx->pop(),this);
+	data_root path(ctx->pop(),this);
 	mode.untag_check(this);
 	path.untag_check(this);
 
@@ -46,15 +46,20 @@ void factor_vm::primitive_fopen()
 			io_error();
 		else
 		{
-			box_alien(file);
+			ctx->push(allot_alien(file));
 			break;
 		}
 	}
 }
 
+FILE *factor_vm::pop_file_handle()
+{
+	return (FILE *)alien_offset(ctx->pop());
+}
+
 void factor_vm::primitive_fgetc()
 {
-	FILE *file = (FILE *)unbox_alien();
+	FILE *file = pop_file_handle();
 
 	for(;;)
 	{
@@ -63,7 +68,7 @@ void factor_vm::primitive_fgetc()
 		{
 			if(feof(file))
 			{
-				dpush(false_object);
+				ctx->push(false_object);
 				break;
 			}
 			else
@@ -71,7 +76,7 @@ void factor_vm::primitive_fgetc()
 		}
 		else
 		{
-			dpush(tag_fixnum(c));
+			ctx->push(tag_fixnum(c));
 			break;
 		}
 	}
@@ -79,12 +84,12 @@ void factor_vm::primitive_fgetc()
 
 void factor_vm::primitive_fread()
 {
-	FILE *file = (FILE *)unbox_alien();
+	FILE *file = pop_file_handle();
 	fixnum size = unbox_array_size();
 
 	if(size == 0)
 	{
-		dpush(tag(allot_string(0,0)));
+		ctx->push(tag(allot_string(0,0)));
 		return;
 	}
 
@@ -97,7 +102,7 @@ void factor_vm::primitive_fread()
 		{
 			if(feof(file))
 			{
-				dpush(false_object);
+				ctx->push(false_object);
 				break;
 			}
 			else
@@ -111,7 +116,7 @@ void factor_vm::primitive_fread()
 				memcpy(new_buf + 1, buf.untagged() + 1,c);
 				buf = new_buf;
 			}
-			dpush(buf.value());
+			ctx->push(buf.value());
 			break;
 		}
 	}
@@ -119,8 +124,8 @@ void factor_vm::primitive_fread()
 
 void factor_vm::primitive_fputc()
 {
-	FILE *file = (FILE *)unbox_alien();
-	fixnum ch = to_fixnum(dpop());
+	FILE *file = pop_file_handle();
+	fixnum ch = to_fixnum(ctx->pop());
 
 	for(;;)
 	{
@@ -137,8 +142,8 @@ void factor_vm::primitive_fputc()
 
 void factor_vm::primitive_fwrite()
 {
-	FILE *file = (FILE *)unbox_alien();
-	byte_array *text = untag_check(dpop());
+	FILE *file = pop_file_handle();
+	byte_array *text = untag_check(ctx->pop());
 	cell length = array_capacity(text);
 	char *string = (char *)(text + 1);
 
@@ -166,20 +171,20 @@ void factor_vm::primitive_fwrite()
 
 void factor_vm::primitive_ftell()
 {
-	FILE *file = (FILE *)unbox_alien();
+	FILE *file = pop_file_handle();
 	off_t offset;
 
 	if((offset = FTELL(file)) == -1)
 		io_error();
 
-	box_signed_8(offset);
+	ctx->push(from_signed_8(offset));
 }
 
 void factor_vm::primitive_fseek()
 {
-	int whence = to_fixnum(dpop());
-	FILE *file = (FILE *)unbox_alien();
-	off_t offset = to_signed_8(dpop());
+	int whence = to_fixnum(ctx->pop());
+	FILE *file = pop_file_handle();
+	off_t offset = to_signed_8(ctx->pop());
 
 	switch(whence)
 	{
@@ -202,7 +207,7 @@ void factor_vm::primitive_fseek()
 
 void factor_vm::primitive_fflush()
 {
-	FILE *file = (FILE *)unbox_alien();
+	FILE *file = pop_file_handle();
 	for(;;)
 	{
 		if(fflush(file) == EOF)
@@ -214,7 +219,7 @@ void factor_vm::primitive_fflush()
 
 void factor_vm::primitive_fclose()
 {
-	FILE *file = (FILE *)unbox_alien();
+	FILE *file = pop_file_handle();
 	for(;;)
 	{
 		if(fclose(file) == EOF)
diff --git a/vm/jit.cpp b/vm/jit.cpp
index e72e88bfdf..8d2f5abb9a 100644
--- a/vm/jit.cpp
+++ b/vm/jit.cpp
@@ -15,6 +15,7 @@ jit::jit(code_block_type type_, cell owner_, factor_vm *vm)
 	  owner(owner_,vm),
 	  code(vm),
 	  relocation(vm),
+	  parameters(vm),
 	  literals(vm),
 	  computing_offset_p(false),
 	  position(0),
@@ -28,14 +29,11 @@ void jit::emit_relocation(cell code_template_)
 	cell capacity = array_capacity(code_template.untagged());
 	for(cell i = 1; i < capacity; i += 3)
 	{
-		cell rel_class = array_nth(code_template.untagged(),i);
-		cell rel_type = array_nth(code_template.untagged(),i + 1);
+		relocation_class rel_class = (relocation_class)untag_fixnum(array_nth(code_template.untagged(),i));
+		relocation_type rel_type = (relocation_type)untag_fixnum(array_nth(code_template.untagged(),i + 1));
 		cell offset = array_nth(code_template.untagged(),i + 2);
 
-		relocation_entry new_entry
-			= (untag_fixnum(rel_type) << 28)
-			| (untag_fixnum(rel_class) << 24)
-			| ((code.count + untag_fixnum(offset)));
+		relocation_entry new_entry(rel_type,rel_class,code.count + untag_fixnum(offset));
 		relocation.append_bytes(&new_entry,sizeof(relocation_entry));
 	}
 }
@@ -70,16 +68,44 @@ void jit::emit(cell code_template_)
 	code.append_byte_array(insns.value());
 }
 
-void jit::emit_with(cell code_template_, cell argument_) {
+void jit::emit_with_literal(cell code_template_, cell argument_) {
 	data_root code_template(code_template_,parent);
 	data_root argument(argument_,parent);
 	literal(argument.value());
 	emit(code_template.value());
 }
 
+void jit::emit_with_parameter(cell code_template_, cell argument_) {
+	data_root code_template(code_template_,parent);
+	data_root argument(argument_,parent);
+	parameter(argument.value());
+	emit(code_template.value());
+}
+
+bool jit::emit_subprimitive(cell word_, bool tail_call_p, bool stack_frame_p)
+{
+	data_root word(word_,parent);
+	data_root code_template(word->subprimitive,parent);
+	parameters.append(untag(array_nth(code_template.untagged(),0)));
+	literals.append(untag(array_nth(code_template.untagged(),1)));
+	emit(array_nth(code_template.untagged(),2));
+	if(array_capacity(code_template.untagged()) == 5)
+	{
+		if(tail_call_p)
+		{
+			if(stack_frame_p) emit(parent->special_objects[JIT_EPILOG]);
+			emit(array_nth(code_template.untagged(),4));
+			return true;
+		}
+		else
+			emit(array_nth(code_template.untagged(),3));
+	}
+	return false;
+}
+	
 void jit::emit_class_lookup(fixnum index, cell type)
 {
-	emit_with(parent->special_objects[PIC_LOAD],tag_fixnum(-index * sizeof(cell)));
+	emit_with_literal(parent->special_objects[PIC_LOAD],tag_fixnum(-index * sizeof(cell)));
 	emit(parent->special_objects[type]);
 }
 
@@ -98,6 +124,7 @@ code_block *jit::to_code_block()
 {
 	code.trim();
 	relocation.trim();
+	parameters.trim();
 	literals.trim();
 
 	return parent->add_code_block(
@@ -106,6 +133,7 @@ code_block *jit::to_code_block()
 		false_object, /* no labels */
 		owner.value(),
 		relocation.elements.value(),
+		parameters.elements.value(),
 		literals.elements.value());
 }
 
diff --git a/vm/jit.hpp b/vm/jit.hpp
index b5a2457d57..277aecb66d 100644
--- a/vm/jit.hpp
+++ b/vm/jit.hpp
@@ -6,6 +6,7 @@ struct jit {
 	data_root owner;
 	growable_byte_array code;
 	growable_byte_array relocation;
+	growable_array parameters;
 	growable_array literals;
 	bool computing_offset_p;
 	fixnum position;
@@ -18,12 +19,15 @@ struct jit {
 	void emit_relocation(cell code_template);
 	void emit(cell code_template);
 
+	void parameter(cell parameter) { parameters.add(parameter); }
+	void emit_with_parameter(cell code_template_, cell parameter_);
+
 	void literal(cell literal) { literals.add(literal); }
-	void emit_with(cell code_template_, cell literal_);
+	void emit_with_literal(cell code_template_, cell literal_);
 
 	void push(cell literal)
 	{
-		emit_with(parent->special_objects[JIT_PUSH_IMMEDIATE],literal);
+		emit_with_literal(parent->special_objects[JIT_PUSH_IMMEDIATE],literal);
 	}
 
 	void word_jump(cell word_)
@@ -36,21 +40,10 @@ struct jit {
 
 	void word_call(cell word)
 	{
-		emit_with(parent->special_objects[JIT_WORD_CALL],word);
+		emit_with_literal(parent->special_objects[JIT_WORD_CALL],word);
 	}
 
-	void word_special(cell word)
-	{
-		emit_with(parent->special_objects[JIT_WORD_SPECIAL],word);
-	}
-
-	void emit_subprimitive(cell word_)
-	{
-		data_root word(word_,parent);
-		data_root code_pair(word->subprimitive,parent);
-		literals.append(untag(array_nth(code_pair.untagged(),0)));
-		emit(array_nth(code_pair.untagged(),1));
-	}
+	bool emit_subprimitive(cell word_, bool tail_call_p, bool stack_frame_p);
 
 	void emit_class_lookup(fixnum index, cell type);
 
diff --git a/vm/layouts.hpp b/vm/layouts.hpp
index 5f3f3e9310..9b574e554d 100644
--- a/vm/layouts.hpp
+++ b/vm/layouts.hpp
@@ -51,8 +51,6 @@ static const cell data_alignment = 16;
 
 #define TYPE_COUNT 14
 
-#define FORWARDING_POINTER 5 /* can be anything other than FIXNUM_TYPE */
-
 enum code_block_type
 {
 	code_block_unoptimized,
@@ -95,59 +93,59 @@ inline static cell tag_fixnum(fixnum untagged)
 
 struct object;
 
-struct header {
-	cell value;
-
-        /* Default ctor to make gcc 3.x happy */
-        explicit header() { abort(); }
-
-	explicit header(cell value_) : value(value_ << TAG_BITS) {}
-
-	void check_header() const
-	{
-#ifdef FACTOR_DEBUG
-		assert(TAG(value) == FIXNUM_TYPE && untag_fixnum(value) < TYPE_COUNT);
-#endif
-	}
-
-	cell hi_tag() const
-	{
-		check_header();
-		return value >> TAG_BITS;
-	}
-
-	bool forwarding_pointer_p() const
-	{
-		return TAG(value) == FORWARDING_POINTER;
-	}
-
-	object *forwarding_pointer() const
-	{
-		return (object *)UNTAG(value);
-	}
-
-	void forward_to(object *pointer)
-	{
-		value = RETAG(pointer,FORWARDING_POINTER);
-	}
-};
-
 #define NO_TYPE_CHECK static const cell type_number = TYPE_COUNT
 
 struct object {
 	NO_TYPE_CHECK;
-	header h;
+	cell header;
 
 	cell size() const;
 	cell binary_payload_start() const;
 
-	cell *slots()  const { return (cell *)this; }
+	cell *slots() const { return (cell *)this; }
 
-	/* Only valid for objects in tenured space; must fast to free_heap_block
+	template void each_slot(Iterator &iter);
+
+	/* Only valid for objects in tenured space; must cast to free_heap_block
 	to do anything with it if its free */
 	bool free_p() const
 	{
-		return h.value & 1 == 1;
+		return (header & 1) == 1;
+	}
+
+	cell type() const
+	{
+		return (header >> 2) & TAG_MASK;
+	}
+
+	void initialize(cell type)
+	{
+		header = type << 2;
+	}
+
+	cell hashcode() const
+	{
+		return (header >> 6);
+	}
+
+	void set_hashcode(cell hashcode)
+	{
+		header = (header & 0x3f) | (hashcode << 6);
+	}
+
+	bool forwarding_pointer_p() const
+	{
+		return (header & 2) == 2;
+	}
+
+	object *forwarding_pointer() const
+	{
+		return (object *)UNTAG(header);
+	}
+
+	void forward_to(object *pointer)
+	{
+		header = ((cell)pointer | 2);
 	}
 };
 
@@ -211,49 +209,7 @@ struct string : public object {
 	cell nth(cell i) const;
 };
 
-/* The compiled code heap is structured into blocks. */
-struct code_block
-{
-	cell header;
-	cell owner; /* tagged pointer to word, quotation or f */
-	cell literals; /* tagged pointer to array or f */
-	cell relocation; /* tagged pointer to byte-array or f */
-
-	bool free_p() const
-	{
-		return header & 1 == 1;
-	}
-
-	code_block_type type() const
-	{
-		return (code_block_type)((header >> 1) & 0x3);
-	}
-
-	void set_type(code_block_type type)
-	{
-		header = ((header & ~0x7) | (type << 1));
-	}
-
-	bool pic_p() const
-	{
-		return type() == code_block_pic;
-	}
-
-	bool optimized_p() const
-	{
-		return type() == code_block_optimized;
-	}
-
-	cell size() const
-	{
-		return header >> 3;
-	}
-
-	void *xt() const
-	{
-		return (void *)(this + 1);
-	}
-};
+struct code_block;
 
 /* Assembly code makes assumptions about the layout of this struct */
 struct word : public object {
@@ -276,8 +232,8 @@ struct word : public object {
 	cell counter;
 	/* TAGGED machine code for sub-primitive */
 	cell subprimitive;
-	/* UNTAGGED execution token: jump here to execute word */
-	void *xt;
+	/* UNTAGGED entry point: jump here to execute word */
+	void *entry_point;
 	/* UNTAGGED compiled code block */
 	code_block *code;
 	/* UNTAGGED profiler stub */
@@ -310,8 +266,8 @@ struct quotation : public object {
 	cell cached_effect;
 	/* tagged */
 	cell cache_counter;
-	/* UNTAGGED */
-	void *xt;
+	/* UNTAGGED entry point; jump here to call quotation */
+	void *entry_point;
 	/* UNTAGGED compiled code block */
 	code_block *code;
 };
@@ -342,11 +298,12 @@ struct dll : public object {
 	/* tagged byte array holding a C string */
 	cell path;
 	/* OS-specific handle */
-	void *dll;
+	void *handle;
 };
 
 struct stack_frame {
-	void *xt;
+	/* Updated by procedure prologue with procedure start address */
+	void *entry_point;
 	/* Frame size in bytes */
 	cell size;
 };
@@ -373,4 +330,12 @@ struct tuple : public object {
 	cell *data() const { return (cell *)(this + 1); }
 };
 
+struct data_root_range {
+	cell *start;
+	cell len;
+
+	explicit data_root_range(cell *start_, cell len_) :
+		start(start_), len(len_) {}
+};
+
 }
diff --git a/vm/main-windows-ce.cpp b/vm/main-windows-ce.cpp
old mode 100644
new mode 100755
index 526f3b2c36..ed5844167a
--- a/vm/main-windows-ce.cpp
+++ b/vm/main-windows-ce.cpp
@@ -1,29 +1,22 @@
 #include "master.hpp"
 
 /* 
-	Windows CE argument parsing ported to work on
+	Windows argument parsing ported to work on
 	int main(int argc, wchar_t **argv).
 
-	This would not be necessary if Windows CE had CommandLineToArgvW.
-
 	Based on MinGW's public domain char** version.
-
 */
 
-int __argc;
-wchar_t **__argv;
-
-static int
-parse_tokens(wchar_t* string, wchar_t*** tokens, int length)
+VM_C_API int parse_tokens(wchar_t *string, wchar_t ***tokens, int length)
 {
 	/* Extract whitespace- and quotes- delimited tokens from the given string
 	   and put them into the tokens array. Returns number of tokens
 	   extracted. Length specifies the current size of tokens[].
 	   THIS METHOD MODIFIES string.  */
 
-	const wchar_t* whitespace = L" \t\r\n";
-	wchar_t* tokenEnd = 0;
-	const wchar_t* quoteCharacters = L"\"\'";
+	const wchar_t *whitespace = L" \t\r\n";
+	wchar_t *tokenEnd = 0;
+	const wchar_t *quoteCharacters = L"\"\'";
 	wchar_t *end = string + wcslen(string);
 
 	if (string == NULL)
@@ -31,7 +24,7 @@ parse_tokens(wchar_t* string, wchar_t*** tokens, int length)
 
 	while (1)
 	{
-		const wchar_t* q;
+		const wchar_t *q;
 		/* Skip over initial whitespace.  */
 		string += wcsspn(string, whitespace);
 		if (*string == '\0')
@@ -59,9 +52,9 @@ parse_tokens(wchar_t* string, wchar_t*** tokens, int length)
 		*tokenEnd = '\0';
 
 		{
-			wchar_t** new_tokens;
+			wchar_t **new_tokens;
 			int newlen = length + 1;
-			new_tokens = realloc (*tokens, sizeof (wchar_t**) * newlen);
+			new_tokens = (wchar_t **)realloc (*tokens, sizeof (wchar_t**) * newlen);
 			if (!new_tokens)
 			{
 				/* Out of memory.  */
@@ -79,16 +72,9 @@ parse_tokens(wchar_t* string, wchar_t*** tokens, int length)
 	return length;
 }
 
-static void
-parse_args(int *argc, wchar_t ***argv, wchar_t *cmdlinePtrW)
+VM_C_API void parse_args(int *argc, wchar_t ***argv, wchar_t *cmdlinePtrW)
 {
-	wchar_t cmdnameBufW[MAX_UNICODE_PATH];
 	int cmdlineLen = 0;
-	int modlen;
-
-	/* argv[0] is the path of invoked program - get this from CE.  */
-	cmdnameBufW[0] = 0;
-	modlen = GetModuleFileNameW(NULL, cmdnameBufW, sizeof (cmdnameBufW)/sizeof (cmdnameBufW[0]));
 
 	if (!cmdlinePtrW)
 		cmdlineLen = 0;
@@ -96,39 +82,51 @@ parse_args(int *argc, wchar_t ***argv, wchar_t *cmdlinePtrW)
 		cmdlineLen = wcslen(cmdlinePtrW);
 
 	/* gets realloc()'d later */
-	*argv = malloc (sizeof (wchar_t**) * 1);
+	*argc = 0;
+	*argv = (wchar_t **)malloc (sizeof (wchar_t**));
+
 	if (!*argv)
-		ExitProcess(-1);
+		ExitProcess(1);
+
+#ifdef WINCE
+	wchar_t cmdnameBufW[MAX_UNICODE_PATH];
+
+	/* argv[0] is the path of invoked program - get this from CE.  */
+	cmdnameBufW[0] = 0;
+	GetModuleFileNameW(NULL, cmdnameBufW, sizeof (cmdnameBufW)/sizeof (cmdnameBufW[0]));
 
 	(*argv)[0] = wcsdup(cmdnameBufW);
 	if(!(*argv[0]))
-		ExitProcess(-1);
+		ExitProcess(1);
 	/* Add one to account for argv[0] */
 	(*argc)++;
+#endif
 
 	if (cmdlineLen > 0)
 	{
-		wchar_t* argv1 = (*argv)[0] + wcslen((*argv)[0]) + 1;
-		argv1 = wcsdup(cmdlinePtrW);
-		if(!argv1)
-			ExitProcess(-1);
-		*argc = parse_tokens(argv1, argv, 1);
+		wchar_t *string = wcsdup(cmdlinePtrW);
+		if(!string)
+			ExitProcess(1);
+		*argc = parse_tokens(string, argv, *argc);
 		if (*argc < 0)
-			ExitProcess(-1);
+			ExitProcess(1);
 	}
 	(*argv)[*argc] = 0;
 	return;
 }
 
-int WINAPI
-WinMain(
+int WINAPI WinMain(
 	HINSTANCE hInstance,
 	HINSTANCE hPrevInstance,
 	LPWSTR lpCmdLine,
 	int nCmdShow)
 {
-	parse_args(&__argc, &__argv, lpCmdLine);
+	int __argc;
+	wchar_t **__argv;
+	factor::parse_args(&__argc, &__argv, lpCmdLine);
+	factor::init_globals();
 	factor::start_standalone_factor(__argc,(LPWSTR*)__argv);
+
 	// memory leak from malloc, wcsdup
 	return 0;
 }
diff --git a/vm/main-windows-nt.cpp b/vm/main-windows-nt.cpp
old mode 100644
new mode 100755
index df4a1172f1..64e2cce54b
--- a/vm/main-windows-nt.cpp
+++ b/vm/main-windows-nt.cpp
@@ -1,30 +1,29 @@
 #include "master.hpp"
 
+VM_C_API int wmain(int argc, wchar_t **argv)
+{
+	factor::init_globals();
+#ifdef FACTOR_MULTITHREADED
+	factor::THREADHANDLE thread = factor::start_standalone_factor_in_new_thread(argv,argc);
+	WaitForSingleObject(thread, INFINITE);
+#else
+	factor::start_standalone_factor(argc,argv);
+#endif
+	return 0;
+}
+
 int WINAPI WinMain(
 	HINSTANCE hInstance,
 	HINSTANCE hPrevInstance,
 	LPSTR lpCmdLine,
 	int nCmdShow)
 {
-	LPWSTR *szArglist;
-	int nArgs;
+	int argc;
+	wchar_t **argv;
 
-	szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
-	if(NULL == szArglist)
-	{
-		puts("CommandLineToArgvW failed");
-		return 1;
-	}
-
-	factor::init_globals();
-  #ifdef FACTOR_MULTITHREADED
-	factor::THREADHANDLE thread = factor::start_standalone_factor_in_new_thread(nArgs,szArglist);
-	WaitForSingleObject(thread, INFINITE);
-  #else
-	factor::start_standalone_factor(nArgs,szArglist);
-  #endif
-
-	LocalFree(szArglist);
+	argv = CommandLineToArgvW(GetCommandLine(),&argc);
+	wmain(argc,argv);
 
+	// memory leak from malloc, wcsdup
 	return 0;
 }
diff --git a/vm/mark_bits.hpp b/vm/mark_bits.hpp
index b54a2c9d46..5115f9a821 100644
--- a/vm/mark_bits.hpp
+++ b/vm/mark_bits.hpp
@@ -1,19 +1,19 @@
 namespace factor
 {
 
-const int block_granularity = 16;
-const int forwarding_granularity = 64;
+const int mark_bits_granularity = sizeof(cell) * 8;
+const int mark_bits_mask = sizeof(cell) * 8 - 1;
 
 template struct mark_bits {
 	cell size;
 	cell start;
 	cell bits_size;
-	u64 *marked;
+	cell *marked;
 	cell *forwarding;
 
 	void clear_mark_bits()
 	{
-		memset(marked,0,bits_size * sizeof(u64));
+		memset(marked,0,bits_size * sizeof(cell));
 	}
 
 	void clear_forwarding()
@@ -24,8 +24,8 @@ template struct mark_bits {
 	explicit mark_bits(cell size_, cell start_) :
 		size(size_),
 		start(start_),
-		bits_size(size / block_granularity / forwarding_granularity),
-		marked(new u64[bits_size]),
+		bits_size(size / data_alignment / mark_bits_granularity),
+		marked(new cell[bits_size]),
 		forwarding(new cell[bits_size])
 	{
 		clear_mark_bits();
@@ -42,26 +42,26 @@ template struct mark_bits {
 
 	cell block_line(Block *address)
 	{
-		return (((cell)address - start) / block_granularity);
+		return (((cell)address - start) / data_alignment);
 	}
 
 	Block *line_block(cell line)
 	{
-		return (Block *)(line * block_granularity + start);
+		return (Block *)(line * data_alignment + start);
 	}
 
 	std::pair bitmap_deref(Block *address)
 	{
 		cell line_number = block_line(address);
-		cell word_index = (line_number >> 6);
-		cell word_shift = (line_number & 63);
+		cell word_index = (line_number / mark_bits_granularity);
+		cell word_shift = (line_number & mark_bits_mask);
 		return std::make_pair(word_index,word_shift);
 	}
 
-	bool bitmap_elt(u64 *bits, Block *address)
+	bool bitmap_elt(cell *bits, Block *address)
 	{
 		std::pair position = bitmap_deref(address);
-		return (bits[position.first] & ((u64)1 << position.second)) != 0;
+		return (bits[position.first] & ((cell)1 << position.second)) != 0;
 	}
 
 	Block *next_block_after(Block *block)
@@ -69,13 +69,13 @@ template struct mark_bits {
 		return (Block *)((cell)block + block->size());
 	}
 
-	void set_bitmap_range(u64 *bits, Block *address)
+	void set_bitmap_range(cell *bits, Block *address)
 	{
 		std::pair start = bitmap_deref(address);
 		std::pair end = bitmap_deref(next_block_after(address));
 
-		u64 start_mask = ((u64)1 << start.second) - 1;
-		u64 end_mask = ((u64)1 << end.second) - 1;
+		cell start_mask = ((cell)1 << start.second) - 1;
+		cell end_mask = ((cell)1 << end.second) - 1;
 
 		if(start.first == end.first)
 			bits[start.first] |= start_mask ^ end_mask;
@@ -87,7 +87,7 @@ template struct mark_bits {
 			bits[start.first] |= ~start_mask;
 
 			for(cell index = start.first + 1; index < end.first; index++)
-				bits[index] = (u64)-1;
+				bits[index] = (cell)-1;
 
 			if(end_mask != 0)
 			{
@@ -121,7 +121,8 @@ template struct mark_bits {
 		}
 	}
 
-	/* We have the popcount for every 64 entries; look up and compute the rest */
+	/* We have the popcount for every mark_bits_granularity entries; look
+	up and compute the rest */
 	Block *forward_block(Block *original)
 	{
 #ifdef FACTOR_DEBUG
@@ -130,7 +131,7 @@ template struct mark_bits {
 		std::pair position = bitmap_deref(original);
 
 		cell approx_popcount = forwarding[position.first];
-		u64 mask = ((u64)1 << position.second) - 1;
+		cell mask = ((cell)1 << position.second) - 1;
 
 		cell new_line_number = approx_popcount + popcount(marked[position.first] & mask);
 		Block *new_block = line_block(new_line_number);
@@ -147,13 +148,13 @@ template struct mark_bits {
 
 		for(cell index = position.first; index < bits_size; index++)
 		{
-			u64 mask = ((s64)marked[index] >> bit_index);
+			cell mask = ((fixnum)marked[index] >> bit_index);
 			if(~mask)
 			{
 				/* Found an unmarked block on this page.
 				Stop, it's hammer time */
 				cell clear_bit = rightmost_clear_bit(mask);
-				return line_block(index * 64 + bit_index + clear_bit);
+				return line_block(index * mark_bits_granularity + bit_index + clear_bit);
 			}
 			else
 			{
@@ -174,13 +175,13 @@ template struct mark_bits {
 
 		for(cell index = position.first; index < bits_size; index++)
 		{
-			u64 mask = (marked[index] >> bit_index);
+			cell mask = (marked[index] >> bit_index);
 			if(mask)
 			{
 				/* Found an marked block on this page.
 				Stop, it's hammer time */
 				cell set_bit = rightmost_set_bit(mask);
-				return line_block(index * 64 + bit_index + set_bit);
+				return line_block(index * mark_bits_granularity + bit_index + set_bit);
 			}
 			else
 			{
diff --git a/vm/master.hpp b/vm/master.hpp
index 39242a36af..f4c0934478 100755
--- a/vm/master.hpp
+++ b/vm/master.hpp
@@ -16,7 +16,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -30,6 +29,31 @@
 #include 
 #include 
 
+/* Detect target CPU type */
+#if defined(__arm__)
+	#define FACTOR_ARM
+#elif defined(__amd64__) || defined(__x86_64__)
+	#define FACTOR_AMD64
+	#define FACTOR_64
+#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(WIN32) || defined(_MSC_VER)
+	#define FACTOR_X86
+#elif defined(__POWERPC__) || defined(__ppc__) || defined(_ARCH_PPC)
+	#define FACTOR_PPC
+#else
+	#error "Unsupported architecture"
+#endif
+
+#if defined(_MSC_VER)
+	#define WINDOWS
+	#define WINNT
+#elif defined(WIN32)
+	#define WINDOWS
+#endif
+
+#ifndef _MSC_VER
+	#include 
+#endif
+
 /* Forward-declare this since it comes up in function prototypes */
 namespace factor
 {
@@ -40,15 +64,17 @@ namespace factor
 #include "layouts.hpp"
 #include "platform.hpp"
 #include "primitives.hpp"
-#include "stacks.hpp"
 #include "segments.hpp"
 #include "contexts.hpp"
 #include "run.hpp"
+#include "objects.hpp"
 #include "profiler.hpp"
 #include "errors.hpp"
 #include "bignumint.hpp"
 #include "bignum.hpp"
-#include "code_block.hpp"
+#include "booleans.hpp"
+#include "instruction_operands.hpp"
+#include "code_blocks.hpp"
 #include "bump_allocator.hpp"
 #include "bitwise_hacks.hpp"
 #include "mark_bits.hpp"
@@ -72,11 +98,13 @@ namespace factor
 #include "alien.hpp"
 #include "callbacks.hpp"
 #include "dispatch.hpp"
+#include "entry_points.hpp"
 #include "vm.hpp"
 #include "allot.hpp"
 #include "tagged.hpp"
 #include "data_roots.hpp"
 #include "code_roots.hpp"
+#include "generic_arrays.hpp"
 #include "slot_visitor.hpp"
 #include "collector.hpp"
 #include "copying_collector.hpp"
@@ -87,10 +115,8 @@ namespace factor
 #include "compaction.hpp"
 #include "full_collector.hpp"
 #include "callstack.hpp"
-#include "generic_arrays.hpp"
 #include "arrays.hpp"
 #include "math.hpp"
-#include "booleans.hpp"
 #include "byte_arrays.hpp"
 #include "jit.hpp"
 #include "quotations.hpp"
diff --git a/vm/math.cpp b/vm/math.cpp
index 4266edc09c..a2c69c31f2 100755
--- a/vm/math.cpp
+++ b/vm/math.cpp
@@ -5,40 +5,40 @@ namespace factor
 
 void factor_vm::primitive_bignum_to_fixnum()
 {
-	drepl(tag_fixnum(bignum_to_fixnum(untag(dpeek()))));
+	ctx->replace(tag_fixnum(bignum_to_fixnum(untag(ctx->peek()))));
 }
 
 void factor_vm::primitive_float_to_fixnum()
 {
-	drepl(tag_fixnum(float_to_fixnum(dpeek())));
+	ctx->replace(tag_fixnum(float_to_fixnum(ctx->peek())));
 }
 
 /* Division can only overflow when we are dividing the most negative fixnum
 by -1. */
 void factor_vm::primitive_fixnum_divint()
 {
-	fixnum y = untag_fixnum(dpop()); \
-	fixnum x = untag_fixnum(dpeek());
+	fixnum y = untag_fixnum(ctx->pop()); \
+	fixnum x = untag_fixnum(ctx->peek());
 	fixnum result = x / y;
 	if(result == -fixnum_min)
-		drepl(allot_integer(-fixnum_min));
+		ctx->replace(allot_integer(-fixnum_min));
 	else
-		drepl(tag_fixnum(result));
+		ctx->replace(tag_fixnum(result));
 }
 
 void factor_vm::primitive_fixnum_divmod()
 {
-	cell y = ((cell *)ds)[0];
-	cell x = ((cell *)ds)[-1];
+	cell y = ((cell *)ctx->datastack)[0];
+	cell x = ((cell *)ctx->datastack)[-1];
 	if(y == tag_fixnum(-1) && x == tag_fixnum(fixnum_min))
 	{
-		((cell *)ds)[-1] = allot_integer(-fixnum_min);
-		((cell *)ds)[0] = tag_fixnum(0);
+		((cell *)ctx->datastack)[-1] = allot_integer(-fixnum_min);
+		((cell *)ctx->datastack)[0] = tag_fixnum(0);
 	}
 	else
 	{
-		((cell *)ds)[-1] = tag_fixnum(untag_fixnum(x) / untag_fixnum(y));
-		((cell *)ds)[0] = (fixnum)x % (fixnum)y;
+		((cell *)ctx->datastack)[-1] = tag_fixnum(untag_fixnum(x) / untag_fixnum(y));
+		((cell *)ctx->datastack)[0] = (fixnum)x % (fixnum)y;
 	}
 }
 
@@ -63,15 +63,15 @@ inline fixnum factor_vm::branchless_abs(fixnum x)
 
 void factor_vm::primitive_fixnum_shift()
 {
-	fixnum y = untag_fixnum(dpop());
-	fixnum x = untag_fixnum(dpeek());
+	fixnum y = untag_fixnum(ctx->pop());
+	fixnum x = untag_fixnum(ctx->peek());
 
 	if(x == 0)
 		return;
 	else if(y < 0)
 	{
 		y = branchless_max(y,-WORD_SIZE + 1);
-		drepl(tag_fixnum(x >> -y));
+		ctx->replace(tag_fixnum(x >> -y));
 		return;
 	}
 	else if(y < WORD_SIZE - TAG_BITS)
@@ -79,57 +79,57 @@ void factor_vm::primitive_fixnum_shift()
 		fixnum mask = -((fixnum)1 << (WORD_SIZE - 1 - TAG_BITS - y));
 		if(!(branchless_abs(x) & mask))
 		{
-			drepl(tag_fixnum(x << y));
+			ctx->replace(tag_fixnum(x << y));
 			return;
 		}
 	}
 
-	drepl(tag(bignum_arithmetic_shift(
+	ctx->replace(tag(bignum_arithmetic_shift(
 		fixnum_to_bignum(x),y)));
 }
 
 void factor_vm::primitive_fixnum_to_bignum()
 {
-	drepl(tag(fixnum_to_bignum(untag_fixnum(dpeek()))));
+	ctx->replace(tag(fixnum_to_bignum(untag_fixnum(ctx->peek()))));
 }
 
 void factor_vm::primitive_float_to_bignum()
 {
-	drepl(tag(float_to_bignum(dpeek())));
+	ctx->replace(tag(float_to_bignum(ctx->peek())));
 }
 
 #define POP_BIGNUMS(x,y) \
-	bignum * y = untag(dpop()); \
-	bignum * x = untag(dpop());
+	bignum * y = untag(ctx->pop()); \
+	bignum * x = untag(ctx->pop());
 
 void factor_vm::primitive_bignum_eq()
 {
 	POP_BIGNUMS(x,y);
-	box_boolean(bignum_equal_p(x,y));
+	ctx->push(tag_boolean(bignum_equal_p(x,y)));
 }
 
 void factor_vm::primitive_bignum_add()
 {
 	POP_BIGNUMS(x,y);
-	dpush(tag(bignum_add(x,y)));
+	ctx->push(tag(bignum_add(x,y)));
 }
 
 void factor_vm::primitive_bignum_subtract()
 {
 	POP_BIGNUMS(x,y);
-	dpush(tag(bignum_subtract(x,y)));
+	ctx->push(tag(bignum_subtract(x,y)));
 }
 
 void factor_vm::primitive_bignum_multiply()
 {
 	POP_BIGNUMS(x,y);
-	dpush(tag(bignum_multiply(x,y)));
+	ctx->push(tag(bignum_multiply(x,y)));
 }
 
 void factor_vm::primitive_bignum_divint()
 {
 	POP_BIGNUMS(x,y);
-	dpush(tag(bignum_quotient(x,y)));
+	ctx->push(tag(bignum_quotient(x,y)));
 }
 
 void factor_vm::primitive_bignum_divmod()
@@ -137,85 +137,85 @@ void factor_vm::primitive_bignum_divmod()
 	bignum *q, *r;
 	POP_BIGNUMS(x,y);
 	bignum_divide(x,y,&q,&r);
-	dpush(tag(q));
-	dpush(tag(r));
+	ctx->push(tag(q));
+	ctx->push(tag(r));
 }
 
 void factor_vm::primitive_bignum_mod()
 {
 	POP_BIGNUMS(x,y);
-	dpush(tag(bignum_remainder(x,y)));
+	ctx->push(tag(bignum_remainder(x,y)));
 }
 
 void factor_vm::primitive_bignum_and()
 {
 	POP_BIGNUMS(x,y);
-	dpush(tag(bignum_bitwise_and(x,y)));
+	ctx->push(tag(bignum_bitwise_and(x,y)));
 }
 
 void factor_vm::primitive_bignum_or()
 {
 	POP_BIGNUMS(x,y);
-	dpush(tag(bignum_bitwise_ior(x,y)));
+	ctx->push(tag(bignum_bitwise_ior(x,y)));
 }
 
 void factor_vm::primitive_bignum_xor()
 {
 	POP_BIGNUMS(x,y);
-	dpush(tag(bignum_bitwise_xor(x,y)));
+	ctx->push(tag(bignum_bitwise_xor(x,y)));
 }
 
 void factor_vm::primitive_bignum_shift()
 {
-	fixnum y = untag_fixnum(dpop());
-        bignum* x = untag(dpop());
-	dpush(tag(bignum_arithmetic_shift(x,y)));
+	fixnum y = untag_fixnum(ctx->pop());
+        bignum* x = untag(ctx->pop());
+	ctx->push(tag(bignum_arithmetic_shift(x,y)));
 }
 
 void factor_vm::primitive_bignum_less()
 {
 	POP_BIGNUMS(x,y);
-	box_boolean(bignum_compare(x,y) == bignum_comparison_less);
+	ctx->push(tag_boolean(bignum_compare(x,y) == bignum_comparison_less));
 }
 
 void factor_vm::primitive_bignum_lesseq()
 {
 	POP_BIGNUMS(x,y);
-	box_boolean(bignum_compare(x,y) != bignum_comparison_greater);
+	ctx->push(tag_boolean(bignum_compare(x,y) != bignum_comparison_greater));
 }
 
 void factor_vm::primitive_bignum_greater()
 {
 	POP_BIGNUMS(x,y);
-	box_boolean(bignum_compare(x,y) == bignum_comparison_greater);
+	ctx->push(tag_boolean(bignum_compare(x,y) == bignum_comparison_greater));
 }
 
 void factor_vm::primitive_bignum_greatereq()
 {
 	POP_BIGNUMS(x,y);
-	box_boolean(bignum_compare(x,y) != bignum_comparison_less);
+	ctx->push(tag_boolean(bignum_compare(x,y) != bignum_comparison_less));
 }
 
 void factor_vm::primitive_bignum_not()
 {
-	drepl(tag(bignum_bitwise_not(untag(dpeek()))));
+	ctx->replace(tag(bignum_bitwise_not(untag(ctx->peek()))));
 }
 
 void factor_vm::primitive_bignum_bitp()
 {
-	fixnum bit = to_fixnum(dpop());
-	bignum *x = untag(dpop());
-	box_boolean(bignum_logbitp(bit,x));
+	fixnum bit = to_fixnum(ctx->pop());
+	bignum *x = untag(ctx->pop());
+	ctx->push(tag_boolean(bignum_logbitp(bit,x)));
 }
 
 void factor_vm::primitive_bignum_log2()
 {
-	drepl(tag(bignum_integer_length(untag(dpeek()))));
+	ctx->replace(tag(bignum_integer_length(untag(ctx->peek()))));
 }
 
 unsigned int factor_vm::bignum_producer(unsigned int digit)
 {
-	unsigned char *ptr = (unsigned char *)alien_offset(dpeek());
+	unsigned char *ptr = (unsigned char *)alien_offset(ctx->peek());
 	return *(ptr + digit);
 }
 
@@ -226,145 +226,146 @@ unsigned int bignum_producer(unsigned int digit, factor_vm *parent)
 
 void factor_vm::primitive_byte_array_to_bignum()
 {
-	cell n_digits = array_capacity(untag_check(dpeek()));
+	cell n_digits = array_capacity(untag_check(ctx->peek()));
 	bignum * result = digit_stream_to_bignum(n_digits,factor::bignum_producer,0x100,0);
-	drepl(tag(result));
+	ctx->replace(tag(result));
 }
 
 cell factor_vm::unbox_array_size_slow()
 {
-	if(tagged(dpeek()).type() == BIGNUM_TYPE)
+	if(tagged(ctx->peek()).type() == BIGNUM_TYPE)
 	{
 		bignum *zero = untag(bignum_zero);
 		bignum *max = cell_to_bignum(array_size_max);
-		bignum *n = untag(dpeek());
+		bignum *n = untag(ctx->peek());
 		if(bignum_compare(n,zero) != bignum_comparison_less
 			&& bignum_compare(n,max) == bignum_comparison_less)
 		{
-			dpop();
+			ctx->pop();
 			return bignum_to_cell(n);
 		}
 	}
 
-	general_error(ERROR_ARRAY_SIZE,dpop(),tag_fixnum(array_size_max),NULL);
+	general_error(ERROR_ARRAY_SIZE,ctx->pop(),tag_fixnum(array_size_max),NULL);
 	return 0; /* can't happen */
 }
 
 void factor_vm::primitive_fixnum_to_float()
 {
-	drepl(allot_float(fixnum_to_float(dpeek())));
+	ctx->replace(allot_float(fixnum_to_float(ctx->peek())));
 }
 
 void factor_vm::primitive_bignum_to_float()
 {
-	drepl(allot_float(bignum_to_float(dpeek())));
+	ctx->replace(allot_float(bignum_to_float(ctx->peek())));
 }
 
 void factor_vm::primitive_str_to_float()
 {
-	byte_array *bytes = untag_check(dpeek());
+	byte_array *bytes = untag_check(ctx->peek());
 	cell capacity = array_capacity(bytes);
 
 	char *c_str = (char *)(bytes + 1);
 	char *end = c_str;
 	double f = strtod(c_str,&end);
 	if(end == c_str + capacity - 1)
-		drepl(allot_float(f));
+		ctx->replace(allot_float(f));
 	else
-		drepl(false_object);
+		ctx->replace(false_object);
 }
 
 void factor_vm::primitive_float_to_str()
 {
 	byte_array *array = allot_byte_array(33);
-	snprintf((char *)(array + 1),32,"%.16g",untag_float_check(dpop()));
-	dpush(tag(array));
+	SNPRINTF((char *)(array + 1),32,"%.16g",untag_float_check(ctx->pop()));
+	ctx->push(tag(array));
 }
 
 #define POP_FLOATS(x,y) \
-	double y = untag_float(dpop()); \
-	double x = untag_float(dpop());
+	double y = untag_float(ctx->pop()); \
+	double x = untag_float(ctx->pop());
 
 void factor_vm::primitive_float_eq()
 {
 	POP_FLOATS(x,y);
-	box_boolean(x == y);
+	ctx->push(tag_boolean(x == y));
 }
 
 void factor_vm::primitive_float_add()
 {
 	POP_FLOATS(x,y);
-	box_double(x + y);
+	ctx->push(allot_float(x + y));
 }
 
 void factor_vm::primitive_float_subtract()
 {
 	POP_FLOATS(x,y);
-	box_double(x - y);
+	ctx->push(allot_float(x - y));
 }
 
 void factor_vm::primitive_float_multiply()
 {
 	POP_FLOATS(x,y);
-	box_double(x * y);
+	ctx->push(allot_float(x * y));
 }
 
 void factor_vm::primitive_float_divfloat()
 {
 	POP_FLOATS(x,y);
-	box_double(x / y);
+	ctx->push(allot_float(x / y));
 }
 
 void factor_vm::primitive_float_mod()
 {
 	POP_FLOATS(x,y);
-	box_double(fmod(x,y));
+	ctx->push(allot_float(fmod(x,y)));
 }
 
 void factor_vm::primitive_float_less()
 {
 	POP_FLOATS(x,y);
-	box_boolean(x < y);
+	ctx->push(tag_boolean(x < y));
 }
 
 void factor_vm::primitive_float_lesseq()
 {
 	POP_FLOATS(x,y);
-	box_boolean(x <= y);
+	ctx->push(tag_boolean(x <= y));
 }
 
 void factor_vm::primitive_float_greater()
 {
 	POP_FLOATS(x,y);
-	box_boolean(x > y);
+	ctx->push(tag_boolean(x > y));
 }
 
 void factor_vm::primitive_float_greatereq()
 {
 	POP_FLOATS(x,y);
-	box_boolean(x >= y);
+	ctx->push(tag_boolean(x >= y));
 }
 
 void factor_vm::primitive_float_bits()
 {
-	box_unsigned_4(float_bits(untag_float_check(dpop())));
+	ctx->push(from_unsigned_4(float_bits((float)untag_float_check(ctx->pop()))));
 }
 
 void factor_vm::primitive_bits_float()
 {
-	box_float(bits_float(to_cell(dpop())));
+	ctx->push(allot_float(bits_float(to_cell(ctx->pop()))));
 }
 
 void factor_vm::primitive_double_bits()
 {
-	box_unsigned_8(double_bits(untag_float_check(dpop())));
+	ctx->push(from_unsigned_8(double_bits(untag_float_check(ctx->pop()))));
 }
 
 void factor_vm::primitive_bits_double()
 {
-	box_double(bits_double(to_unsigned_8(dpop())));
+	ctx->push(allot_float(bits_double(to_unsigned_8(ctx->pop()))));
 }
 
+/* Cannot allocate */
 fixnum factor_vm::to_fixnum(cell tagged)
 {
 	switch(TAG(tagged))
@@ -394,99 +395,100 @@ VM_C_API cell to_cell(cell tagged, factor_vm *parent)
 	return parent->to_cell(tagged);
 }
 
-void factor_vm::box_signed_1(s8 n)
+cell factor_vm::from_signed_1(s8 n)
 {
-	dpush(tag_fixnum(n));
+	return tag_fixnum(n);
 }
 
-VM_C_API void box_signed_1(s8 n, factor_vm *parent)
+VM_C_API cell from_signed_1(s8 n, factor_vm *parent)
 {
-	return parent->box_signed_1(n);
+	return parent->from_signed_1(n);
 }
 
-void factor_vm::box_unsigned_1(u8 n)
+cell factor_vm::from_unsigned_1(u8 n)
 {
-	dpush(tag_fixnum(n));
+	return tag_fixnum(n);
 }
 
-VM_C_API void box_unsigned_1(u8 n, factor_vm *parent)
+VM_C_API cell from_unsigned_1(u8 n, factor_vm *parent)
 {
-	return parent->box_unsigned_1(n);
+	return parent->from_unsigned_1(n);
 }
 
-void factor_vm::box_signed_2(s16 n)
+cell factor_vm::from_signed_2(s16 n)
 {
-	dpush(tag_fixnum(n));
+	return tag_fixnum(n);
 }
 
-VM_C_API void box_signed_2(s16 n, factor_vm *parent)
+VM_C_API cell from_signed_2(s16 n, factor_vm *parent)
 {
-	return parent->box_signed_2(n);
+	return parent->from_signed_2(n);
 }
 
-void factor_vm::box_unsigned_2(u16 n)
+cell factor_vm::from_unsigned_2(u16 n)
 {
-	dpush(tag_fixnum(n));
+	return tag_fixnum(n);
 }
 
-VM_C_API void box_unsigned_2(u16 n, factor_vm *parent)
+VM_C_API cell from_unsigned_2(u16 n, factor_vm *parent)
 {
-	return parent->box_unsigned_2(n);
+	return parent->from_unsigned_2(n);
 }
 
-void factor_vm::box_signed_4(s32 n)
+cell factor_vm::from_signed_4(s32 n)
 {
-	dpush(allot_integer(n));
+	return allot_integer(n);
 }
 
-VM_C_API void box_signed_4(s32 n, factor_vm *parent)
+VM_C_API cell from_signed_4(s32 n, factor_vm *parent)
 {
-	return parent->box_signed_4(n);
+	return parent->from_signed_4(n);
 }
 
-void factor_vm::box_unsigned_4(u32 n)
+cell factor_vm::from_unsigned_4(u32 n)
 {
-	dpush(allot_cell(n));
+	return allot_cell(n);
 }
 
-VM_C_API void box_unsigned_4(u32 n, factor_vm *parent)
+VM_C_API cell from_unsigned_4(u32 n, factor_vm *parent)
 {
-	return parent->box_unsigned_4(n);
+	return parent->from_unsigned_4(n);
 }
 
-void factor_vm::box_signed_cell(fixnum integer)
+cell factor_vm::from_signed_cell(fixnum integer)
 {
-	dpush(allot_integer(integer));
+	return allot_integer(integer);
 }
 
-VM_C_API void box_signed_cell(fixnum integer, factor_vm *parent)
+cell factor_vm::from_unsigned_cell(cell integer)
 {
-	return parent->box_signed_cell(integer);
+	return allot_cell(integer);
 }
 
-void factor_vm::box_unsigned_cell(cell cell)
+VM_C_API cell from_signed_cell(fixnum integer, factor_vm *parent)
 {
-	dpush(allot_cell(cell));
+	return parent->from_signed_cell(integer);
 }
 
-VM_C_API void box_unsigned_cell(cell cell, factor_vm *parent)
+VM_C_API cell from_unsigned_cell(cell integer, factor_vm *parent)
 {
-	return parent->box_unsigned_cell(cell);
+	return parent->from_unsigned_cell(integer);
 }
 
-void factor_vm::box_signed_8(s64 n)
+cell factor_vm::from_signed_8(s64 n)
 {
 	if(n < fixnum_min || n > fixnum_max)
-		dpush(tag(long_long_to_bignum(n)));
+		return tag(long_long_to_bignum(n));
 	else
-		dpush(tag_fixnum(n));
+		return tag_fixnum((fixnum)n);
 }
 
-VM_C_API void box_signed_8(s64 n, factor_vm *parent)
+VM_C_API cell from_signed_8(s64 n, factor_vm *parent)
 {
-	return parent->box_signed_8(n);
+	return parent->from_signed_8(n);
 }
 
+/* Cannot allocate */
 s64 factor_vm::to_signed_8(cell obj)
 {
 	switch(tagged(obj).type())
@@ -506,19 +508,20 @@ VM_C_API s64 to_signed_8(cell obj, factor_vm *parent)
 	return parent->to_signed_8(obj);
 }
 
-void factor_vm::box_unsigned_8(u64 n)
+cell factor_vm::from_unsigned_8(u64 n)
 {
 	if(n > (u64)fixnum_max)
-		dpush(tag(ulong_long_to_bignum(n)));
+		return tag(ulong_long_to_bignum(n));
 	else
-		dpush(tag_fixnum(n));
+		return tag_fixnum((fixnum)n);
 }
 
-VM_C_API void box_unsigned_8(u64 n, factor_vm *parent)
+VM_C_API cell from_unsigned_8(u64 n, factor_vm *parent)
 {
-	return parent->box_unsigned_8(n);
+	return parent->from_unsigned_8(n);
 }
 
+/* Cannot allocate */
 u64 factor_vm::to_unsigned_8(cell obj)
 {
 	switch(tagged(obj).type())
@@ -538,19 +541,15 @@ VM_C_API u64 to_unsigned_8(cell obj, factor_vm *parent)
 	return parent->to_unsigned_8(obj);
 }
  
-void factor_vm::box_float(float flo)
+VM_C_API cell from_float(float flo, factor_vm *parent)
 {
-        dpush(allot_float(flo));
-}
-
-VM_C_API void box_float(float flo, factor_vm *parent)
-{
-	return parent->box_float(flo);
+	return parent->allot_float(flo);
 }
 
+/* Cannot allocate */
 float factor_vm::to_float(cell value)
 {
-	return untag_float_check(value);
+	return (float)untag_float_check(value);
 }
 
 VM_C_API float to_float(cell value, factor_vm *parent)
@@ -558,16 +557,12 @@ VM_C_API float to_float(cell value, factor_vm *parent)
 	return parent->to_float(value);
 }
 
-void factor_vm::box_double(double flo)
+VM_C_API cell from_double(double flo, factor_vm *parent)
 {
-        dpush(allot_float(flo));
-}
-
-VM_C_API void box_double(double flo, factor_vm *parent)
-{
-	return parent->box_double(flo);
+	return parent->allot_float(flo);
 }
 
+/* Cannot allocate */
 double factor_vm::to_double(cell value)
 {
 	return untag_float_check(value);
@@ -582,22 +577,22 @@ VM_C_API double to_double(cell value, factor_vm *parent)
 overflow, they call these functions. */
 inline void factor_vm::overflow_fixnum_add(fixnum x, fixnum y)
 {
-	drepl(tag(fixnum_to_bignum(
+	ctx->replace(tag(fixnum_to_bignum(
 		untag_fixnum(x) + untag_fixnum(y))));
 }
 
-VM_ASM_API void overflow_fixnum_add(fixnum x, fixnum y, factor_vm *parent)
+VM_C_API void overflow_fixnum_add(fixnum x, fixnum y, factor_vm *parent)
 {
 	parent->overflow_fixnum_add(x,y);
 }
 
 inline void factor_vm::overflow_fixnum_subtract(fixnum x, fixnum y)
 {
-	drepl(tag(fixnum_to_bignum(
+	ctx->replace(tag(fixnum_to_bignum(
 		untag_fixnum(x) - untag_fixnum(y))));
 }
 
-VM_ASM_API void overflow_fixnum_subtract(fixnum x, fixnum y, factor_vm *parent)
+VM_C_API void overflow_fixnum_subtract(fixnum x, fixnum y, factor_vm *parent)
 {
 	parent->overflow_fixnum_subtract(x,y);
 }
@@ -608,10 +603,10 @@ inline void factor_vm::overflow_fixnum_multiply(fixnum x, fixnum y)
 	GC_BIGNUM(bx);
 	bignum *by = fixnum_to_bignum(y);
 	GC_BIGNUM(by);
-	drepl(tag(bignum_multiply(bx,by)));
+	ctx->replace(tag(bignum_multiply(bx,by)));
 }
 
-VM_ASM_API void overflow_fixnum_multiply(fixnum x, fixnum y, factor_vm *parent)
+VM_C_API void overflow_fixnum_multiply(fixnum x, fixnum y, factor_vm *parent)
 {
 	parent->overflow_fixnum_multiply(x,y);
 }
diff --git a/vm/math.hpp b/vm/math.hpp
index 2fed585f98..d78ae54010 100644
--- a/vm/math.hpp
+++ b/vm/math.hpp
@@ -60,13 +60,13 @@ inline double factor_vm::fixnum_to_float(cell tagged)
 
 inline cell factor_vm::unbox_array_size()
 {
-	cell obj = dpeek();
+	cell obj = ctx->peek();
 	if(TAG(obj) == FIXNUM_TYPE)
 	{
 		fixnum n = untag_fixnum(obj);
 		if(n >= 0 && n < (fixnum)array_size_max)
 		{
-			dpop();
+			ctx->pop();
 			return n;
 		}
 	}
@@ -74,21 +74,21 @@ inline cell factor_vm::unbox_array_size()
 	return unbox_array_size_slow();
 }
 
-VM_C_API void box_float(float flo, factor_vm *vm);
+VM_C_API cell from_float(float flo, factor_vm *vm);
 VM_C_API float to_float(cell value, factor_vm *vm);
-VM_C_API void box_double(double flo, factor_vm *vm);
+VM_C_API cell from_double(double flo, factor_vm *vm);
 VM_C_API double to_double(cell value, factor_vm *vm);
 
-VM_C_API void box_signed_1(s8 n, factor_vm *vm);
-VM_C_API void box_unsigned_1(u8 n, factor_vm *vm);
-VM_C_API void box_signed_2(s16 n, factor_vm *vm);
-VM_C_API void box_unsigned_2(u16 n, factor_vm *vm);
-VM_C_API void box_signed_4(s32 n, factor_vm *vm);
-VM_C_API void box_unsigned_4(u32 n, factor_vm *vm);
-VM_C_API void box_signed_cell(fixnum integer, factor_vm *vm);
-VM_C_API void box_unsigned_cell(cell cell, factor_vm *vm);
-VM_C_API void box_signed_8(s64 n, factor_vm *vm);
-VM_C_API void box_unsigned_8(u64 n, factor_vm *vm);
+VM_C_API cell from_signed_1(s8 n, factor_vm *vm);
+VM_C_API cell from_unsigned_1(u8 n, factor_vm *vm);
+VM_C_API cell from_signed_2(s16 n, factor_vm *vm);
+VM_C_API cell from_unsigned_2(u16 n, factor_vm *vm);
+VM_C_API cell from_signed_4(s32 n, factor_vm *vm);
+VM_C_API cell from_unsigned_4(u32 n, factor_vm *vm);
+VM_C_API cell from_signed_cell(fixnum integer, factor_vm *vm);
+VM_C_API cell from_unsigned_cell(cell integer, factor_vm *vm);
+VM_C_API cell from_signed_8(s64 n, factor_vm *vm);
+VM_C_API cell from_unsigned_8(u64 n, factor_vm *vm);
 
 VM_C_API s64 to_signed_8(cell obj, factor_vm *vm);
 VM_C_API u64 to_unsigned_8(cell obj, factor_vm *vm);
@@ -96,8 +96,8 @@ VM_C_API u64 to_unsigned_8(cell obj, factor_vm *vm);
 VM_C_API fixnum to_fixnum(cell tagged, factor_vm *vm);
 VM_C_API cell to_cell(cell tagged, factor_vm *vm);
 
-VM_ASM_API void overflow_fixnum_add(fixnum x, fixnum y, factor_vm *vm);
-VM_ASM_API void overflow_fixnum_subtract(fixnum x, fixnum y, factor_vm *vm);
-VM_ASM_API void overflow_fixnum_multiply(fixnum x, fixnum y, factor_vm *vm);
+VM_C_API void overflow_fixnum_add(fixnum x, fixnum y, factor_vm *parent);
+VM_C_API void overflow_fixnum_subtract(fixnum x, fixnum y, factor_vm *parent);
+VM_C_API void overflow_fixnum_multiply(fixnum x, fixnum y, factor_vm *parent);
 
 }
diff --git a/vm/nursery_collector.cpp b/vm/nursery_collector.cpp
index 155da243d4..062aa6aed3 100644
--- a/vm/nursery_collector.cpp
+++ b/vm/nursery_collector.cpp
@@ -22,9 +22,12 @@ void factor_vm::collect_nursery()
 	collector.trace_cards(data->tenured,
 		card_points_to_nursery,
 		simple_unmarker(card_points_to_nursery));
-	collector.trace_cards(data->aging,
-		card_points_to_nursery,
-		full_unmarker());
+	if(data->aging->here != data->aging->start)
+	{
+		collector.trace_cards(data->aging,
+			card_points_to_nursery,
+			full_unmarker());
+	}
 	current_gc->event->ended_card_scan(collector.cards_scanned,collector.decks_scanned);
 
 	current_gc->event->started_code_scan();
@@ -33,10 +36,6 @@ void factor_vm::collect_nursery()
 
 	collector.cheneys_algorithm();
 
-	current_gc->event->started_code_sweep();
-	update_code_heap_for_minor_gc(&code->points_to_nursery);
-	current_gc->event->ended_code_sweep();
-
 	data->reset_generation(&nursery);
 	code->points_to_nursery.clear();
 }
diff --git a/vm/object_start_map.cpp b/vm/object_start_map.cpp
index 724f365e79..6b5b5139b9 100644
--- a/vm/object_start_map.cpp
+++ b/vm/object_start_map.cpp
@@ -60,7 +60,7 @@ void object_start_map::update_card_for_sweep(cell index, u16 mask)
 	cell offset = object_start_offsets[index];
 	if(offset != card_starts_inside_object)
 	{
-		mask >>= (offset / block_granularity);
+		mask >>= (offset / data_alignment);
 
 		if(mask == 0)
 		{
@@ -70,7 +70,7 @@ void object_start_map::update_card_for_sweep(cell index, u16 mask)
 		else
 		{
 			/* Move the object start forward if necessary */
-			object_start_offsets[index] = offset + (rightmost_set_bit(mask) * block_granularity);
+			object_start_offsets[index] = (card)(offset + (rightmost_set_bit(mask) * data_alignment));
 		}
 	}
 }
@@ -79,11 +79,16 @@ void object_start_map::update_for_sweep(mark_bits *state)
 {
 	for(cell index = 0; index < state->bits_size; index++)
 	{
-		u64 mask = state->marked[index];
+		cell mask = state->marked[index];
+#ifdef FACTOR_64
 		update_card_for_sweep(index * 4,      mask        & 0xffff);
 		update_card_for_sweep(index * 4 + 1, (mask >> 16) & 0xffff);
 		update_card_for_sweep(index * 4 + 2, (mask >> 32) & 0xffff);
 		update_card_for_sweep(index * 4 + 3, (mask >> 48) & 0xffff);
+#else
+		update_card_for_sweep(index * 2,      mask        & 0xffff);
+		update_card_for_sweep(index * 2 + 1, (mask >> 16) & 0xffff);
+#endif
 	}
 }
 
diff --git a/vm/objects.cpp b/vm/objects.cpp
new file mode 100644
index 0000000000..21948e5e7a
--- /dev/null
+++ b/vm/objects.cpp
@@ -0,0 +1,150 @@
+#include "master.hpp"
+
+namespace factor
+{
+
+void factor_vm::primitive_special_object()
+{
+	fixnum e = untag_fixnum(ctx->peek());
+	ctx->replace(special_objects[e]);
+}
+
+void factor_vm::primitive_set_special_object()
+{
+	fixnum e = untag_fixnum(ctx->pop());
+	cell value = ctx->pop();
+	special_objects[e] = value;
+}
+
+void factor_vm::primitive_identity_hashcode()
+{
+	cell tagged = ctx->peek();
+	object *obj = untag(tagged);
+	ctx->replace(tag_fixnum(obj->hashcode()));
+}
+
+void factor_vm::compute_identity_hashcode(object *obj)
+{
+	object_counter++;
+	if(object_counter == 0) object_counter++;
+	obj->set_hashcode((cell)obj ^ object_counter);
+}
+
+void factor_vm::primitive_compute_identity_hashcode()
+{
+	object *obj = untag(ctx->pop());
+	compute_identity_hashcode(obj);
+}
+
+void factor_vm::primitive_set_slot()
+{
+	fixnum slot = untag_fixnum(ctx->pop());
+	object *obj = untag(ctx->pop());
+	cell value = ctx->pop();
+
+	cell *slot_ptr = &obj->slots()[slot];
+	*slot_ptr = value;
+	write_barrier(slot_ptr);
+}
+
+cell factor_vm::clone_object(cell obj_)
+{
+	data_root obj(obj_,this);
+
+	if(immediate_p(obj.value()))
+		return obj.value();
+	else
+	{
+		cell size = object_size(obj.value());
+		object *new_obj = allot_object(obj.type(),size);
+		memcpy(new_obj,obj.untagged(),size);
+		new_obj->set_hashcode(0);
+		return tag_dynamic(new_obj);
+	}
+}
+
+void factor_vm::primitive_clone()
+{
+	ctx->replace(clone_object(ctx->peek()));
+}
+
+/* Size of the object pointed to by a tagged pointer */
+cell factor_vm::object_size(cell tagged)
+{
+	if(immediate_p(tagged))
+		return 0;
+	else
+		return untag(tagged)->size();
+}
+
+void factor_vm::primitive_size()
+{
+	ctx->push(allot_cell(object_size(ctx->pop())));
+}
+
+struct slot_become_visitor {
+	std::map *become_map;
+
+	explicit slot_become_visitor(std::map *become_map_) :
+		become_map(become_map_) {}
+
+	object *operator()(object *old)
+	{
+		std::map::const_iterator iter = become_map->find(old);
+		if(iter != become_map->end())
+			return iter->second;
+		else
+			return old;
+	}
+};
+
+struct object_become_visitor {
+	slot_visitor *workhorse;
+
+	explicit object_become_visitor(slot_visitor *workhorse_) :
+		workhorse(workhorse_) {}
+
+	void operator()(object *obj)
+	{
+		workhorse->visit_slots(obj);
+	}
+};
+
+/* classes.tuple uses this to reshape tuples; tools.deploy.shaker uses this
+   to coalesce equal but distinct quotations and wrappers. */
+void factor_vm::primitive_become()
+{
+	array *new_objects = untag_check(ctx->pop());
+	array *old_objects = untag_check(ctx->pop());
+
+	cell capacity = array_capacity(new_objects);
+	if(capacity != array_capacity(old_objects))
+		critical_error("bad parameters to become",0);
+
+	/* Build the forwarding map */
+	std::map become_map;
+
+	for(cell i = 0; i < capacity; i++)
+	{
+		tagged old_obj(array_nth(old_objects,i));
+		tagged new_obj(array_nth(new_objects,i));
+
+		if(old_obj != new_obj)
+			become_map[old_obj.untagged()] = new_obj.untagged();
+	}
+
+	/* Update all references to old objects to point to new objects */
+	slot_visitor workhorse(this,slot_become_visitor(&become_map));
+	workhorse.visit_roots();
+	workhorse.visit_contexts();
+
+	object_become_visitor object_visitor(&workhorse);
+	each_object(object_visitor);
+
+	/* Since we may have introduced old->new references, need to revisit
+	all objects on a minor GC. */
+	data->mark_all_cards();
+	primitive_minor_gc();
+}
+
+}
diff --git a/vm/objects.hpp b/vm/objects.hpp
new file mode 100644
index 0000000000..fdc5758a8d
--- /dev/null
+++ b/vm/objects.hpp
@@ -0,0 +1,125 @@
+namespace factor
+{
+
+static const cell special_object_count = 70;
+
+enum special_object {
+	OBJ_NAMESTACK,             /* used by library only */
+	OBJ_CATCHSTACK,            /* used by library only, per-callback */
+
+	OBJ_CURRENT_CALLBACK = 2,  /* used by library only, per-callback */
+	OBJ_WALKER_HOOK,           /* non-local exit hook, used by library only */
+	OBJ_CALLCC_1,              /* used to pass the value in callcc1 */
+
+	ERROR_HANDLER_QUOT = 5,    /* quotation called when VM throws an error */
+	OBJ_ERROR,                 /* a marker consed onto kernel errors */
+
+	OBJ_CELL_SIZE = 7,         /* sizeof(cell) */
+	OBJ_CPU,                   /* CPU architecture */
+	OBJ_OS,                    /* operating system name */
+
+	OBJ_ARGS = 10,             /* command line arguments */
+	OBJ_STDIN,                 /* stdin FILE* handle */
+	OBJ_STDOUT,                /* stdout FILE* handle */
+
+	OBJ_IMAGE = 13,            /* image path name */
+	OBJ_EXECUTABLE,            /* runtime executable path name */
+
+	OBJ_EMBEDDED = 15,         /* are we embedded in another app? */
+	OBJ_EVAL_CALLBACK,         /* used when Factor is embedded in a C app */
+	OBJ_YIELD_CALLBACK,        /* used when Factor is embedded in a C app */
+	OBJ_SLEEP_CALLBACK,        /* used when Factor is embedded in a C app */
+
+	OBJ_COCOA_EXCEPTION = 19,  /* Cocoa exception handler quotation */
+
+	OBJ_STARTUP_QUOT = 20,     /* startup quotation */
+	OBJ_GLOBAL,                /* global namespace */
+	OBJ_SHUTDOWN_QUOT,         /* shutdown quotation */
+
+	/* Quotation compilation in quotations.c */
+	JIT_PROLOG = 23,
+	JIT_PRIMITIVE_WORD,
+	JIT_PRIMITIVE,
+	JIT_WORD_JUMP,
+	JIT_WORD_CALL,
+	JIT_IF_WORD,
+	JIT_IF,
+	JIT_EPILOG,
+	JIT_RETURN,
+	JIT_PROFILING,
+	JIT_PUSH_IMMEDIATE,
+	JIT_DIP_WORD,
+	JIT_DIP,
+	JIT_2DIP_WORD,
+	JIT_2DIP,
+	JIT_3DIP_WORD,
+	JIT_3DIP,
+	JIT_EXECUTE,
+	JIT_DECLARE_WORD,
+
+	/* External entry points */
+	C_TO_FACTOR_WORD,
+	LAZY_JIT_COMPILE_WORD,
+	UNWIND_NATIVE_FRAMES_WORD,
+
+	/* Incremented on every modify-code-heap call; invalidates call( inline
+	caching */
+	REDEFINITION_COUNTER = 47,
+
+	/* Callback stub generation in callbacks.c */
+	CALLBACK_STUB = 48,
+	
+	/* Polymorphic inline cache generation in inline_cache.c */
+	PIC_LOAD = 49,
+	PIC_TAG,
+	PIC_TUPLE,
+	PIC_CHECK_TAG,
+	PIC_CHECK_TUPLE,
+	PIC_HIT,
+	PIC_MISS_WORD,
+	PIC_MISS_TAIL_WORD,
+
+	/* Megamorphic cache generation in dispatch.c */
+	MEGA_LOOKUP = 57,
+	MEGA_LOOKUP_WORD,
+	MEGA_MISS_WORD,
+
+	OBJ_UNDEFINED = 60,       /* default quotation for undefined words */
+
+	OBJ_STDERR = 61,          /* stderr FILE* handle */
+
+	OBJ_STAGE2 = 62,          /* have we bootstrapped? */
+
+	OBJ_CURRENT_THREAD = 63,
+
+	OBJ_THREADS = 64,
+	OBJ_RUN_QUEUE = 65,
+	OBJ_SLEEP_QUEUE = 66,
+};
+
+/* save-image-and-exit discards special objects that are filled in on startup
+anyway, to reduce image size */
+#define OBJ_FIRST_SAVE OBJ_STARTUP_QUOT
+#define OBJ_LAST_SAVE OBJ_STAGE2
+
+inline static bool save_special_p(cell i)
+{
+	return (i >= OBJ_FIRST_SAVE && i <= OBJ_LAST_SAVE);
+}
+
+template void object::each_slot(Iterator &iter)
+{
+	cell scan = (cell)this;
+	cell payload_start = binary_payload_start();
+	cell end = scan + payload_start;
+
+	scan += sizeof(cell);
+
+	while(scan < end)
+	{
+		iter((cell *)scan);
+		scan += sizeof(cell);
+	}
+}
+
+}
diff --git a/vm/os-genunix.cpp b/vm/os-genunix.cpp
index 065f0dfd40..301b68fb52 100644
--- a/vm/os-genunix.cpp
+++ b/vm/os-genunix.cpp
@@ -1,11 +1,12 @@
 #include "master.hpp"
+#include 
 
 namespace factor
 {
 
 void factor_vm::c_to_factor_toplevel(cell quot)
 {
-	c_to_factor(quot,this);
+	c_to_factor(quot);
 }
 
 void init_signals()
@@ -34,4 +35,14 @@ const char *default_image_path()
 	return new_path;
 }
 
+u64 nano_count()
+{
+	struct timespec t;
+	int ret;
+	ret = clock_gettime(CLOCK_MONOTONIC,&t);
+	if(ret != 0)
+		fatal_error("clock_gettime failed", 0);
+	return (u64)t.tv_sec * 1000000000 + t.tv_nsec;
+}
+
 }
diff --git a/vm/os-macosx.mm b/vm/os-macosx.mm
index 438957bd04..92694a4599 100644
--- a/vm/os-macosx.mm
+++ b/vm/os-macosx.mm
@@ -1,5 +1,6 @@
 #import 
 
+#include 
 #include "master.hpp"
 
 namespace factor
@@ -10,15 +11,15 @@ void factor_vm::c_to_factor_toplevel(cell quot)
 	for(;;)
 	{
 NS_DURING
-		c_to_factor(quot,this);
+		c_to_factor(quot);
 		NS_VOIDRETURN;
 NS_HANDLER
-		dpush(allot_alien(false_object,(cell)localException));
+		ctx->push(allot_alien(false_object,(cell)localException));
 		quot = special_objects[OBJ_COCOA_EXCEPTION];
 		if(!tagged(quot).type_p(QUOTATION_TYPE))
 		{
 			/* No Cocoa exception handler was registered, so
-			extra/cocoa/ is not loaded. So we pass the exception
+			basis/cocoa/ is not loaded. So we pass the exception
 			along. */
 			[localException raise];
 		}
@@ -30,7 +31,7 @@ void early_init(void)
 {
 	SInt32 version;
 	Gestalt(gestaltSystemVersion,&version);
-	if(version <= 0x1050)
+	if(version < 0x1050)
 	{
 		printf("Factor requires Mac OS X 10.5 or later.\n");
 		exit(1);
@@ -84,4 +85,16 @@ Protocol *objc_getProtocol(char *name)
 		return nil;
 }
 
+u64 nano_count()
+{
+	u64 t;
+	mach_timebase_info_data_t info;
+	kern_return_t ret;
+	t = mach_absolute_time();
+	ret = mach_timebase_info(&info);
+	if(ret != 0)
+		fatal_error("mach_timebase_info failed",ret);
+	return t * (info.numer/info.denom);
+}
+
 }
diff --git a/vm/os-unix.cpp b/vm/os-unix.cpp
index cd88541136..4b5040ab8b 100644
--- a/vm/os-unix.cpp
+++ b/vm/os-unix.cpp
@@ -40,16 +40,29 @@ factor_vm *tls_vm()
 
 static void *null_dll;
 
-s64 current_micros()
+u64 system_micros()
 {
 	struct timeval t;
 	gettimeofday(&t,NULL);
-	return (s64)t.tv_sec * 1000000 + t.tv_usec;
+	return (u64)t.tv_sec * 1000000 + t.tv_usec;
 }
 
-void sleep_micros(cell usec)
+void sleep_nanos(u64 nsec)
 {
-	usleep(usec);
+	timespec ts;
+	timespec ts_rem;
+	int ret;
+	ts.tv_sec = nsec / 1000000000;
+	ts.tv_nsec = nsec % 1000000000;
+	ret = nanosleep(&ts,&ts_rem);
+	while(ret == -1 && errno == EINTR)
+	{
+		memcpy(&ts, &ts_rem, sizeof(ts));
+		ret = nanosleep(&ts, &ts_rem);
+	}
+
+	if(ret == -1)
+		fatal_error("nanosleep failed", 0);
 }
 
 void factor_vm::init_ffi()
@@ -60,27 +73,27 @@ void factor_vm::init_ffi()
 
 void factor_vm::ffi_dlopen(dll *dll)
 {
-	dll->dll = dlopen(alien_offset(dll->path), RTLD_LAZY);
+	dll->handle = dlopen(alien_offset(dll->path), RTLD_LAZY);
 }
 
 void *factor_vm::ffi_dlsym(dll *dll, symbol_char *symbol)
 {
-	void *handle = (dll == NULL ? null_dll : dll->dll);
+	void *handle = (dll == NULL ? null_dll : dll->handle);
 	return dlsym(handle,symbol);
 }
 
 void factor_vm::ffi_dlclose(dll *dll)
 {
-	if(dlclose(dll->dll))
+	if(dlclose(dll->handle))
 		general_error(ERROR_FFI,false_object,false_object,NULL);
-	dll->dll = NULL;
+	dll->handle = NULL;
 }
 
 void factor_vm::primitive_existsp()
 {
 	struct stat sb;
-	char *path = (char *)(untag_check(dpop()) + 1);
-	box_boolean(stat(path,&sb) >= 0);
+	char *path = (char *)(untag_check(ctx->pop()) + 1);
+	ctx->push(tag_boolean(stat(path,&sb) >= 0));
 }
 
 segment::segment(cell size_, bool executable_p)
diff --git a/vm/os-unix.hpp b/vm/os-unix.hpp
index 05ab8b1120..7faab4d8b8 100644
--- a/vm/os-unix.hpp
+++ b/vm/os-unix.hpp
@@ -22,22 +22,13 @@ typedef char symbol_char;
 #define STRCMP strcmp
 #define STRNCMP strncmp
 #define STRDUP strdup
+#define SNPRINTF snprintf
 
 #define FTELL ftello
 #define FSEEK fseeko
 
-#define FIXNUM_FORMAT "%ld"
-#define CELL_FORMAT "%lu"
 #define CELL_HEX_FORMAT "%lx"
 
-#ifdef FACTOR_64
-	#define CELL_HEX_PAD_FORMAT "%016lx"
-#else
-	#define CELL_HEX_PAD_FORMAT "%08lx"
-#endif
-
-#define FIXNUM_FORMAT "%ld"
-
 #define OPEN_READ(path) fopen(path,"rb")
 #define OPEN_WRITE(path) fopen(path,"wb")
 
@@ -52,8 +43,9 @@ void unix_init_signals();
 void signal_handler(int signal, siginfo_t* siginfo, void* uap);
 void dump_stack_signal(int signal, siginfo_t* siginfo, void* uap);
 
-s64 current_micros();
-void sleep_micros(cell usec);
+u64 system_micros();
+u64 nano_count();
+void sleep_nanos(u64 nsec);
 
 void init_platform_globals();
 
diff --git a/vm/os-windows-ce.cpp b/vm/os-windows-ce.cpp
index f51953e6eb..a57db667c4 100644
--- a/vm/os-windows-ce.cpp
+++ b/vm/os-windows-ce.cpp
@@ -3,7 +3,7 @@
 namespace factor
 {
 
-s64 current_micros()
+u64 system_micros()
 {
 	SYSTEMTIME st;
 	FILETIME ft;
diff --git a/vm/os-windows-ce.hpp b/vm/os-windows-ce.hpp
old mode 100644
new mode 100755
index f41262e54b..02de1cd4a8
--- a/vm/os-windows-ce.hpp
+++ b/vm/os-windows-ce.hpp
@@ -12,7 +12,6 @@ typedef wchar_t symbol_char;
 
 #define FACTOR_OS_STRING "wince"
 #define FACTOR_DLL L"factor-ce.dll"
-#define FACTOR_DLL_NAME "factor-ce.dll"
 
 int errno;
 char *strerror(int err);
@@ -22,7 +21,7 @@ char *getenv(char *name);
 #define snprintf _snprintf
 #define snwprintf _snwprintf
 
-s64 current_micros();
+u64 system_micros();
 void c_to_factor_toplevel(cell quot);
 void open_console();
 
diff --git a/vm/os-windows-nt.cpp b/vm/os-windows-nt.cpp
index 0c5ddd99e1..2fceb130f4 100755
--- a/vm/os-windows-nt.cpp
+++ b/vm/os-windows-nt.cpp
@@ -3,8 +3,9 @@
 namespace factor
 {
 
-THREADHANDLE start_thread(void *(*start_routine)(void *),void *args){
-    return (void*) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, args, 0, 0); 
+THREADHANDLE start_thread(void *(*start_routine)(void *), void *args)
+{
+	return (void *)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, args, 0, 0);
 }
 
 DWORD dwTlsIndex; 
@@ -28,14 +29,42 @@ factor_vm *tls_vm()
 	return vm;
 }
 
-s64 current_micros()
+u64 system_micros()
 {
 	FILETIME t;
 	GetSystemTimeAsFileTime(&t);
-	return (((s64)t.dwLowDateTime | (s64)t.dwHighDateTime<<32)
+	return (((u64)t.dwLowDateTime | (u64)t.dwHighDateTime<<32)
 		- EPOCH_OFFSET) / 10;
 }
 
+/* On VirtualBox, QueryPerformanceCounter does not increment
+the high part every time the low part overflows.  Workaround. */
+u64 nano_count()
+{
+	LARGE_INTEGER count;
+	LARGE_INTEGER frequency;
+	static u32 hi = 0;
+	static u32 lo = 0;
+	BOOL ret;
+	ret = QueryPerformanceCounter(&count);
+	if(ret == 0)
+		fatal_error("QueryPerformanceCounter", 0);
+	ret = QueryPerformanceFrequency(&frequency);
+	if(ret == 0)
+		fatal_error("QueryPerformanceFrequency", 0);
+
+	if(count.LowPart < lo)
+		hi += 1;
+	lo = count.LowPart;
+
+	return (u64)((((u64)hi << 32) | (u64)lo)*(1000000000.0/frequency.QuadPart));
+}
+
+void sleep_nanos(u64 nsec)
+{
+	Sleep((DWORD)(nsec/1000000));
+}
+
 LONG factor_vm::exception_handler(PEXCEPTION_POINTERS pe)
 {
 	PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)pe->ExceptionRecord;
@@ -83,21 +112,18 @@ LONG factor_vm::exception_handler(PEXCEPTION_POINTERS pe)
 	return EXCEPTION_CONTINUE_EXECUTION;
 }
 
-FACTOR_STDCALL LONG exception_handler(PEXCEPTION_POINTERS pe)
+FACTOR_STDCALL(LONG) exception_handler(PEXCEPTION_POINTERS pe)
 {
 	return tls_vm()->exception_handler(pe);
 }
 
-bool handler_added = 0;
-
 void factor_vm::c_to_factor_toplevel(cell quot)
 {
-	if(!handler_added){
-		if(!AddVectoredExceptionHandler(0, (PVECTORED_EXCEPTION_HANDLER)factor::exception_handler))
-			fatal_error("AddVectoredExceptionHandler failed", 0);
-		handler_added = 1;
-	}
-	c_to_factor(quot,this);
+	if(!AddVectoredExceptionHandler(0, (PVECTORED_EXCEPTION_HANDLER)factor::exception_handler))
+		fatal_error("AddVectoredExceptionHandler failed", 0);
+
+	c_to_factor(quot);
+
  	RemoveVectoredExceptionHandler((void *)factor::exception_handler);
 }
 
diff --git a/vm/os-windows-nt.hpp b/vm/os-windows-nt.hpp
index 5b55ce1f2b..8ad34ed147 100755
--- a/vm/os-windows-nt.hpp
+++ b/vm/os-windows-nt.hpp
@@ -8,23 +8,37 @@
 #include 
 #include 
 
+#ifdef _MSC_VER
+	#undef min
+	#undef max
+#endif
+
 namespace factor
 {
 
 typedef char symbol_char;
 
 #define FACTOR_OS_STRING "winnt"
+
 #define FACTOR_DLL L"factor.dll"
-#define FACTOR_DLL_NAME "factor.dll"
 
-#define FACTOR_STDCALL __attribute__((stdcall))
+#ifdef _MSC_VER
+	#define FACTOR_STDCALL(return_type) return_type __stdcall
+#else
+	#define FACTOR_STDCALL(return_type) __attribute__((stdcall)) return_type
+#endif
 
-FACTOR_STDCALL LONG exception_handler(PEXCEPTION_POINTERS pe);
+FACTOR_STDCALL(LONG) exception_handler(PEXCEPTION_POINTERS pe);
 
 // SSE traps raise these exception codes, which are defined in internal NT headers
 // but not winbase.h
+#ifndef STATUS_FLOAT_MULTIPLE_FAULTS
 #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4
+#endif
+
+#ifndef STATUS_FLOAT_MULTIPLE_TRAPS
 #define STATUS_FLOAT_MULTIPLE_TRAPS  0xC00002B5
+#endif
 
 typedef HANDLE THREADHANDLE;
 
diff --git a/vm/os-windows.cpp b/vm/os-windows.cpp
index 48745584d3..df2a57f2e8 100755
--- a/vm/os-windows.cpp
+++ b/vm/os-windows.cpp
@@ -9,26 +9,26 @@ void factor_vm::init_ffi()
 {
 	hFactorDll = GetModuleHandle(FACTOR_DLL);
 	if(!hFactorDll)
-		fatal_error("GetModuleHandle(\"" FACTOR_DLL_NAME "\") failed", 0);
+		fatal_error("GetModuleHandle() failed", 0);
 }
 
 void factor_vm::ffi_dlopen(dll *dll)
 {
-	dll->dll = LoadLibraryEx((WCHAR *)alien_offset(dll->path), NULL, 0);
+	dll->handle = LoadLibraryEx((WCHAR *)alien_offset(dll->path), NULL, 0);
 }
 
 void *factor_vm::ffi_dlsym(dll *dll, symbol_char *symbol)
 {
-	return (void *)GetProcAddress(dll ? (HMODULE)dll->dll : hFactorDll, symbol);
+	return (void *)GetProcAddress(dll ? (HMODULE)dll->handle : hFactorDll, symbol);
 }
 
 void factor_vm::ffi_dlclose(dll *dll)
 {
-	FreeLibrary((HMODULE)dll->dll);
-	dll->dll = NULL;
+	FreeLibrary((HMODULE)dll->handle);
+	dll->handle = NULL;
 }
 
-bool factor_vm::windows_stat(vm_char *path)
+BOOL factor_vm::windows_stat(vm_char *path)
 {
 	BY_HANDLE_FILE_INFORMATION bhfi;
 	HANDLE h = CreateFileW(path,
@@ -50,15 +50,14 @@ bool factor_vm::windows_stat(vm_char *path)
 		FindClose(h);
 		return true;
 	}
-	bool ret;
-	ret = GetFileInformationByHandle(h, &bhfi);
+	BOOL ret = GetFileInformationByHandle(h, &bhfi);
 	CloseHandle(h);
 	return ret;
 }
 
 void factor_vm::windows_image_path(vm_char *full_path, vm_char *temp_path, unsigned int length)
 {
-	snwprintf(temp_path, length-1, L"%s.image", full_path); 
+	SNWPRINTF(temp_path, length-1, L"%s.image", full_path); 
 	temp_path[length - 1] = 0;
 }
 
@@ -75,7 +74,7 @@ const vm_char *factor_vm::default_image_path()
 	if((ptr = wcsrchr(full_path, '.')))
 		*ptr = 0;
 
-	snwprintf(temp_path, MAX_UNICODE_PATH-1, L"%s.image", full_path); 
+	SNWPRINTF(temp_path, MAX_UNICODE_PATH-1, L"%s.image", full_path); 
 	temp_path[MAX_UNICODE_PATH - 1] = 0;
 
 	return safe_strdup(temp_path);
@@ -92,8 +91,8 @@ const vm_char *factor_vm::vm_executable_path()
 
 void factor_vm::primitive_existsp()
 {
-	vm_char *path = untag_check(dpop())->data();
-	box_boolean(windows_stat(path));
+	vm_char *path = untag_check(ctx->pop())->data();
+	ctx->push(tag_boolean(windows_stat(path)));
 }
 
 segment::segment(cell size_, bool executable_p)
@@ -126,11 +125,6 @@ segment::~segment()
 		fatal_error("Segment deallocation failed",0);
 }
 
-void factor_vm::sleep_micros(u64 usec)
-{
-	Sleep((DWORD)(usec / 1000));
-}
-
 long getpagesize()
 {
 	static long g_pagesize = 0;
diff --git a/vm/os-windows.hpp b/vm/os-windows.hpp
old mode 100644
new mode 100755
index 403842b2cb..8a2dfe38f5
--- a/vm/os-windows.hpp
+++ b/vm/os-windows.hpp
@@ -1,8 +1,8 @@
 #include 
 
 #ifndef wcslen
-  /* for cygwin */
-  #include 
+	/* for cygwin */
+	#include 
 #endif
 
 namespace factor
@@ -18,20 +18,23 @@ typedef wchar_t vm_char;
 #define STRCMP wcscmp
 #define STRNCMP wcsncmp
 #define STRDUP _wcsdup
-#define MIN(a,b) ((a)>(b)?(b):(a))
-#define FTELL ftello64
-#define FSEEK fseeko64
+
+#ifdef _MSC_VER
+	#define FTELL ftell
+	#define FSEEK fseek
+	#define SNPRINTF _snprintf
+	#define SNWPRINTF _snwprintf
+#else
+	#define FTELL ftello64
+	#define FSEEK fseeko64
+	#define SNPRINTF snprintf
+	#define SNWPRINTF snwprintf
+#endif
 
 #ifdef WIN64
-	#define CELL_FORMAT "%Iu"
 	#define CELL_HEX_FORMAT "%Ix"
-	#define CELL_HEX_PAD_FORMAT "%016Ix"
-	#define FIXNUM_FORMAT "%Id"
 #else
-	#define CELL_FORMAT "%lu"
 	#define CELL_HEX_FORMAT "%lx"
-	#define CELL_HEX_PAD_FORMAT "%08lx"
-	#define FIXNUM_FORMAT "%ld"
 #endif
 
 #define OPEN_READ(path) _wfopen(path,L"rb")
@@ -43,7 +46,9 @@ typedef wchar_t vm_char;
 inline static void init_signals() {}
 inline static void early_init() {}
 
-s64 current_micros();
+u64 system_micros();
+u64 nano_count();
+void sleep_nanos(u64 nsec);
 long getpagesize();
 
 }
diff --git a/vm/platform.hpp b/vm/platform.hpp
old mode 100644
new mode 100755
index 7b4356af56..2a38c91171
--- a/vm/platform.hpp
+++ b/vm/platform.hpp
@@ -1,27 +1,20 @@
-#if defined(__arm__)
-	#define FACTOR_ARM
-#elif defined(__amd64__) || defined(__x86_64__)
-	#define FACTOR_AMD64
-#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(WIN32)
-	#define FACTOR_X86
-#elif defined(__POWERPC__) || defined(__ppc__) || defined(_ARCH_PPC)
-	#define FACTOR_PPC
-#else
-	#error "Unsupported architecture"
-#endif
-
 #if defined(WINDOWS)
 	#if defined(WINCE)
 		#include "os-windows-ce.hpp"
-	#else
+		#include "os-windows.hpp"
+	#elif defined(WINNT)
 		#include "os-windows-nt.hpp"
-	#endif
+		#include "os-windows.hpp"
 
-	#include "os-windows.hpp"
-	#if defined(FACTOR_AMD64)
-		#include "os-windows-nt.64.hpp"
-	#elif defined(FACTOR_X86)
-		#include "os-windows-nt.32.hpp"
+		#if defined(FACTOR_AMD64)
+			#include "os-windows-nt.64.hpp"
+		#elif defined(FACTOR_X86)
+			#include "os-windows-nt.32.hpp"
+		#else
+			#error "Unsupported Windows flavor"
+		#endif
+	#else
+		#error "Unsupported Windows flavor"
 	#endif
 #else
 	#include "os-unix.hpp"
diff --git a/vm/primitives.cpp b/vm/primitives.cpp
index 957e6128ed..f288a796c2 100644
--- a/vm/primitives.cpp
+++ b/vm/primitives.cpp
@@ -3,295 +3,134 @@
 namespace factor
 {
 
-PRIMITIVE_FORWARD(bignum_to_fixnum)
-PRIMITIVE_FORWARD(float_to_fixnum)
-PRIMITIVE_FORWARD(fixnum_to_bignum)
-PRIMITIVE_FORWARD(float_to_bignum)
-PRIMITIVE_FORWARD(fixnum_to_float)
-PRIMITIVE_FORWARD(bignum_to_float)
-PRIMITIVE_FORWARD(str_to_float)
-PRIMITIVE_FORWARD(float_to_str)
-PRIMITIVE_FORWARD(float_bits)
-PRIMITIVE_FORWARD(double_bits)
-PRIMITIVE_FORWARD(bits_float)
-PRIMITIVE_FORWARD(bits_double)
-PRIMITIVE_FORWARD(fixnum_divint)
-PRIMITIVE_FORWARD(fixnum_divmod)
-PRIMITIVE_FORWARD(fixnum_shift)
-PRIMITIVE_FORWARD(bignum_eq)
-PRIMITIVE_FORWARD(bignum_add)
-PRIMITIVE_FORWARD(bignum_subtract)
-PRIMITIVE_FORWARD(bignum_multiply)
-PRIMITIVE_FORWARD(bignum_divint)
-PRIMITIVE_FORWARD(bignum_mod)
-PRIMITIVE_FORWARD(bignum_divmod)
-PRIMITIVE_FORWARD(bignum_and)
-PRIMITIVE_FORWARD(bignum_or)
-PRIMITIVE_FORWARD(bignum_xor)
-PRIMITIVE_FORWARD(bignum_not)
-PRIMITIVE_FORWARD(bignum_shift)
-PRIMITIVE_FORWARD(bignum_less)
-PRIMITIVE_FORWARD(bignum_lesseq)
-PRIMITIVE_FORWARD(bignum_greater)
-PRIMITIVE_FORWARD(bignum_greatereq)
-PRIMITIVE_FORWARD(bignum_bitp)
-PRIMITIVE_FORWARD(bignum_log2)
-PRIMITIVE_FORWARD(byte_array_to_bignum)
-PRIMITIVE_FORWARD(float_eq)
-PRIMITIVE_FORWARD(float_add)
-PRIMITIVE_FORWARD(float_subtract)
-PRIMITIVE_FORWARD(float_multiply)
-PRIMITIVE_FORWARD(float_divfloat)
-PRIMITIVE_FORWARD(float_mod)
-PRIMITIVE_FORWARD(float_less)
-PRIMITIVE_FORWARD(float_lesseq)
-PRIMITIVE_FORWARD(float_greater)
-PRIMITIVE_FORWARD(float_greatereq)
-PRIMITIVE_FORWARD(word)
-PRIMITIVE_FORWARD(word_xt)
-PRIMITIVE_FORWARD(getenv)
-PRIMITIVE_FORWARD(setenv)
-PRIMITIVE_FORWARD(existsp)
-PRIMITIVE_FORWARD(minor_gc)
-PRIMITIVE_FORWARD(full_gc)
-PRIMITIVE_FORWARD(compact_gc)
-PRIMITIVE_FORWARD(save_image)
-PRIMITIVE_FORWARD(save_image_and_exit)
-PRIMITIVE_FORWARD(datastack)
-PRIMITIVE_FORWARD(retainstack)
-PRIMITIVE_FORWARD(callstack)
-PRIMITIVE_FORWARD(set_datastack)
-PRIMITIVE_FORWARD(set_retainstack)
-PRIMITIVE_FORWARD(set_callstack)
-PRIMITIVE_FORWARD(exit)
-PRIMITIVE_FORWARD(data_room)
-PRIMITIVE_FORWARD(code_room)
-PRIMITIVE_FORWARD(micros)
-PRIMITIVE_FORWARD(modify_code_heap)
-PRIMITIVE_FORWARD(dlopen)
-PRIMITIVE_FORWARD(dlsym)
-PRIMITIVE_FORWARD(dlclose)
-PRIMITIVE_FORWARD(byte_array)
-PRIMITIVE_FORWARD(uninitialized_byte_array)
-PRIMITIVE_FORWARD(displaced_alien)
-PRIMITIVE_FORWARD(alien_address)
-PRIMITIVE_FORWARD(set_slot)
-PRIMITIVE_FORWARD(string_nth)
-PRIMITIVE_FORWARD(set_string_nth_fast)
-PRIMITIVE_FORWARD(set_string_nth_slow)
-PRIMITIVE_FORWARD(resize_array)
-PRIMITIVE_FORWARD(resize_string)
-PRIMITIVE_FORWARD(array)
-PRIMITIVE_FORWARD(begin_scan)
-PRIMITIVE_FORWARD(next_object)
-PRIMITIVE_FORWARD(end_scan)
-PRIMITIVE_FORWARD(size)
-PRIMITIVE_FORWARD(die)
-PRIMITIVE_FORWARD(fopen)
-PRIMITIVE_FORWARD(fgetc)
-PRIMITIVE_FORWARD(fread)
-PRIMITIVE_FORWARD(fputc)
-PRIMITIVE_FORWARD(fwrite)
-PRIMITIVE_FORWARD(fflush)
-PRIMITIVE_FORWARD(ftell)
-PRIMITIVE_FORWARD(fseek)
-PRIMITIVE_FORWARD(fclose)
-PRIMITIVE_FORWARD(wrapper)
-PRIMITIVE_FORWARD(clone)
-PRIMITIVE_FORWARD(string)
-PRIMITIVE_FORWARD(array_to_quotation)
-PRIMITIVE_FORWARD(quotation_xt)
-PRIMITIVE_FORWARD(tuple)
-PRIMITIVE_FORWARD(profiling)
-PRIMITIVE_FORWARD(become)
-PRIMITIVE_FORWARD(sleep)
-PRIMITIVE_FORWARD(tuple_boa)
-PRIMITIVE_FORWARD(callstack_to_array)
-PRIMITIVE_FORWARD(innermost_stack_frame_executing)
-PRIMITIVE_FORWARD(innermost_stack_frame_scan)
-PRIMITIVE_FORWARD(set_innermost_stack_frame_quot)
-PRIMITIVE_FORWARD(call_clear)
-PRIMITIVE_FORWARD(resize_byte_array)
-PRIMITIVE_FORWARD(dll_validp)
-PRIMITIVE_FORWARD(unimplemented)
-PRIMITIVE_FORWARD(jit_compile)
-PRIMITIVE_FORWARD(load_locals)
-PRIMITIVE_FORWARD(check_datastack)
-PRIMITIVE_FORWARD(mega_cache_miss)
-PRIMITIVE_FORWARD(lookup_method)
-PRIMITIVE_FORWARD(reset_dispatch_stats)
-PRIMITIVE_FORWARD(dispatch_stats)
-PRIMITIVE_FORWARD(optimized_p)
-PRIMITIVE_FORWARD(quot_compiled_p)
-PRIMITIVE_FORWARD(vm_ptr)
-PRIMITIVE_FORWARD(strip_stack_traces)
-PRIMITIVE_FORWARD(callback)
-PRIMITIVE_FORWARD(enable_gc_events)
-PRIMITIVE_FORWARD(disable_gc_events)
+#define PRIMITIVE(name) VM_C_API void primitive_##name(factor_vm *parent) \
+{ \
+	parent->primitive_##name(); \
+}
 
-const primitive_type primitives[] = {
-	primitive_bignum_to_fixnum,
-	primitive_float_to_fixnum,
-	primitive_fixnum_to_bignum,
-	primitive_float_to_bignum,
-	primitive_fixnum_to_float,
-	primitive_bignum_to_float,
-	primitive_str_to_float,
-	primitive_float_to_str,
-	primitive_float_bits,
-	primitive_double_bits,
-	primitive_bits_float,
-	primitive_bits_double,
-	primitive_fixnum_add,
-	primitive_fixnum_subtract,
-	primitive_fixnum_multiply,
-	primitive_fixnum_divint,
-	primitive_fixnum_divmod,
-	primitive_fixnum_shift,
-	primitive_bignum_eq,
-	primitive_bignum_add,
-	primitive_bignum_subtract,
-	primitive_bignum_multiply,
-	primitive_bignum_divint,
-	primitive_bignum_mod,
-	primitive_bignum_divmod,
-	primitive_bignum_and,
-	primitive_bignum_or,
-	primitive_bignum_xor,
-	primitive_bignum_not,
-	primitive_bignum_shift,
-	primitive_bignum_less,
-	primitive_bignum_lesseq,
-	primitive_bignum_greater,
-	primitive_bignum_greatereq,
-	primitive_bignum_bitp,
-	primitive_bignum_log2,
-	primitive_byte_array_to_bignum,
-	primitive_float_eq,
-	primitive_float_add,
-	primitive_float_subtract,
-	primitive_float_multiply,
-	primitive_float_divfloat,
-	primitive_float_mod,
-	primitive_float_less,
-	primitive_float_lesseq,
-	primitive_float_greater,
-	primitive_float_greatereq,
-	/* The unordered comparison primitives don't have a non-optimizing
-	compiler implementation */
-	primitive_float_less,
-	primitive_float_lesseq,
-	primitive_float_greater,
-	primitive_float_greatereq,
-	primitive_word,
-	primitive_word_xt,
-	primitive_getenv,
-	primitive_setenv,
-	primitive_existsp,
-	primitive_minor_gc,
-	primitive_full_gc,
-	primitive_compact_gc,
-	primitive_save_image,
-	primitive_save_image_and_exit,
-	primitive_datastack,
-	primitive_retainstack,
-	primitive_callstack,
-	primitive_set_datastack,
-	primitive_set_retainstack,
-	primitive_set_callstack,
-	primitive_exit,
-	primitive_data_room,
-	primitive_code_room,
-	primitive_micros,
-	primitive_modify_code_heap,
-	primitive_dlopen,
-	primitive_dlsym,
-	primitive_dlclose,
-	primitive_byte_array,
-	primitive_uninitialized_byte_array,
-	primitive_displaced_alien,
-	primitive_alien_signed_cell,
-	primitive_set_alien_signed_cell,
-	primitive_alien_unsigned_cell,
-	primitive_set_alien_unsigned_cell,
-	primitive_alien_signed_8,
-	primitive_set_alien_signed_8,
-	primitive_alien_unsigned_8,
-	primitive_set_alien_unsigned_8,
-	primitive_alien_signed_4,
-	primitive_set_alien_signed_4,
-	primitive_alien_unsigned_4,
-	primitive_set_alien_unsigned_4,
-	primitive_alien_signed_2,
-	primitive_set_alien_signed_2,
-	primitive_alien_unsigned_2,
-	primitive_set_alien_unsigned_2,
-	primitive_alien_signed_1,
-	primitive_set_alien_signed_1,
-	primitive_alien_unsigned_1,
-	primitive_set_alien_unsigned_1,
-	primitive_alien_float,
-	primitive_set_alien_float,
-	primitive_alien_double,
-	primitive_set_alien_double,
-	primitive_alien_cell,
-	primitive_set_alien_cell,
-	primitive_alien_address,
-	primitive_set_slot,
-	primitive_string_nth,
-	primitive_set_string_nth_fast,
-	primitive_set_string_nth_slow,
-	primitive_resize_array,
-	primitive_resize_string,
-	primitive_array,
-	primitive_begin_scan,
-	primitive_next_object,
-	primitive_end_scan,
-	primitive_size,
-	primitive_die,
-	primitive_fopen,
-	primitive_fgetc,
-	primitive_fread,
-	primitive_fputc,
-	primitive_fwrite,
-	primitive_fflush,
-	primitive_ftell,
-	primitive_fseek,
-	primitive_fclose,
-	primitive_wrapper,
-	primitive_clone,
-	primitive_string,
-	primitive_array_to_quotation,
-	primitive_quotation_xt,
-	primitive_tuple,
-	primitive_profiling,
-	primitive_become,
-	primitive_sleep,
-	primitive_tuple_boa,
-	primitive_callstack_to_array,
-	primitive_innermost_stack_frame_executing,
-	primitive_innermost_stack_frame_scan,
-	primitive_set_innermost_stack_frame_quot,
-	primitive_call_clear,
-	primitive_resize_byte_array,
-	primitive_dll_validp,
-	primitive_unimplemented,
-	primitive_jit_compile,
-	primitive_load_locals,
-	primitive_check_datastack,
-	primitive_inline_cache_miss,
-	primitive_inline_cache_miss_tail,
-	primitive_mega_cache_miss,
-	primitive_lookup_method,
-	primitive_reset_dispatch_stats,
-	primitive_dispatch_stats,
-	primitive_optimized_p,
-	primitive_quot_compiled_p,
-	primitive_vm_ptr,
-	primitive_strip_stack_traces,
-	primitive_callback,
-	primitive_enable_gc_events,
-	primitive_disable_gc_events,
-};
+PRIMITIVE(alien_address)
+PRIMITIVE(all_instances)
+PRIMITIVE(array)
+PRIMITIVE(array_to_quotation)
+PRIMITIVE(become)
+PRIMITIVE(bignum_add)
+PRIMITIVE(bignum_and)
+PRIMITIVE(bignum_bitp)
+PRIMITIVE(bignum_divint)
+PRIMITIVE(bignum_divmod)
+PRIMITIVE(bignum_eq)
+PRIMITIVE(bignum_greater)
+PRIMITIVE(bignum_greatereq)
+PRIMITIVE(bignum_less)
+PRIMITIVE(bignum_lesseq)
+PRIMITIVE(bignum_log2)
+PRIMITIVE(bignum_mod)
+PRIMITIVE(bignum_multiply)
+PRIMITIVE(bignum_not)
+PRIMITIVE(bignum_or)
+PRIMITIVE(bignum_shift)
+PRIMITIVE(bignum_subtract)
+PRIMITIVE(bignum_to_fixnum)
+PRIMITIVE(bignum_to_float)
+PRIMITIVE(bignum_xor)
+PRIMITIVE(bits_double)
+PRIMITIVE(bits_float)
+PRIMITIVE(byte_array)
+PRIMITIVE(byte_array_to_bignum)
+PRIMITIVE(call_clear)
+PRIMITIVE(callback)
+PRIMITIVE(callstack)
+PRIMITIVE(callstack_to_array)
+PRIMITIVE(check_datastack)
+PRIMITIVE(clone)
+PRIMITIVE(code_room)
+PRIMITIVE(compact_gc)
+PRIMITIVE(compute_identity_hashcode)
+PRIMITIVE(data_room)
+PRIMITIVE(datastack)
+PRIMITIVE(die)
+PRIMITIVE(disable_gc_events)
+PRIMITIVE(dispatch_stats)
+PRIMITIVE(displaced_alien)
+PRIMITIVE(dlclose)
+PRIMITIVE(dll_validp)
+PRIMITIVE(dlopen)
+PRIMITIVE(dlsym)
+PRIMITIVE(double_bits)
+PRIMITIVE(enable_gc_events)
+PRIMITIVE(existsp)
+PRIMITIVE(exit)
+PRIMITIVE(fclose)
+PRIMITIVE(fflush)
+PRIMITIVE(fgetc)
+PRIMITIVE(fixnum_divint)
+PRIMITIVE(fixnum_divmod)
+PRIMITIVE(fixnum_shift)
+PRIMITIVE(fixnum_to_bignum)
+PRIMITIVE(fixnum_to_float)
+PRIMITIVE(float_add)
+PRIMITIVE(float_bits)
+PRIMITIVE(float_divfloat)
+PRIMITIVE(float_eq)
+PRIMITIVE(float_greater)
+PRIMITIVE(float_greatereq)
+PRIMITIVE(float_less)
+PRIMITIVE(float_lesseq)
+PRIMITIVE(float_mod)
+PRIMITIVE(float_multiply)
+PRIMITIVE(float_subtract)
+PRIMITIVE(float_to_bignum)
+PRIMITIVE(float_to_fixnum)
+PRIMITIVE(float_to_str)
+PRIMITIVE(fopen)
+PRIMITIVE(fputc)
+PRIMITIVE(fread)
+PRIMITIVE(fseek)
+PRIMITIVE(ftell)
+PRIMITIVE(full_gc)
+PRIMITIVE(fwrite)
+PRIMITIVE(identity_hashcode)
+PRIMITIVE(innermost_stack_frame_executing)
+PRIMITIVE(innermost_stack_frame_scan)
+PRIMITIVE(jit_compile)
+PRIMITIVE(load_locals)
+PRIMITIVE(lookup_method)
+PRIMITIVE(mega_cache_miss)
+PRIMITIVE(minor_gc)
+PRIMITIVE(modify_code_heap)
+PRIMITIVE(nano_count)
+PRIMITIVE(optimized_p)
+PRIMITIVE(profiling)
+PRIMITIVE(quot_compiled_p)
+PRIMITIVE(quotation_code)
+PRIMITIVE(reset_dispatch_stats)
+PRIMITIVE(resize_array)
+PRIMITIVE(resize_byte_array)
+PRIMITIVE(resize_string)
+PRIMITIVE(retainstack)
+PRIMITIVE(save_image)
+PRIMITIVE(save_image_and_exit)
+PRIMITIVE(set_datastack)
+PRIMITIVE(set_innermost_stack_frame_quot)
+PRIMITIVE(set_retainstack)
+PRIMITIVE(set_slot)
+PRIMITIVE(set_special_object)
+PRIMITIVE(set_string_nth_fast)
+PRIMITIVE(set_string_nth_slow)
+PRIMITIVE(size)
+PRIMITIVE(sleep)
+PRIMITIVE(special_object)
+PRIMITIVE(str_to_float)
+PRIMITIVE(string)
+PRIMITIVE(string_nth)
+PRIMITIVE(strip_stack_traces)
+PRIMITIVE(system_micros)
+PRIMITIVE(tuple)
+PRIMITIVE(tuple_boa)
+PRIMITIVE(unimplemented)
+PRIMITIVE(uninitialized_byte_array)
+PRIMITIVE(word)
+PRIMITIVE(word_code)
+PRIMITIVE(wrapper)
 
 }
diff --git a/vm/primitives.hpp b/vm/primitives.hpp
index 8e4efd8d14..1ace3c0f7e 100644
--- a/vm/primitives.hpp
+++ b/vm/primitives.hpp
@@ -1,56 +1,161 @@
 namespace factor
 {
 
-#if defined(FACTOR_X86)
-  extern "C" __attribute__ ((regparm (1))) typedef void (*primitive_type)(factor_vm *parent);
-  #define PRIMITIVE(name) extern "C" __attribute__ ((regparm (1)))  void primitive_##name(factor_vm *parent)
-  #define PRIMITIVE_FORWARD(name) extern "C" __attribute__ ((regparm (1)))  void primitive_##name(factor_vm *parent) \
-  { \
-	parent->primitive_##name(); \
-  }
-#else
-  extern "C" typedef void (*primitive_type)(factor_vm *parent);
-  #define PRIMITIVE(name) extern "C" void primitive_##name(factor_vm *parent)
-  #define PRIMITIVE_FORWARD(name) extern "C" void primitive_##name(factor_vm *parent) \
-  { \
-	parent->primitive_##name(); \
-  }
-#endif
-extern const primitive_type primitives[];
+#define DECLARE_PRIMITIVE(name) VM_C_API void primitive_##name(factor_vm *parent);
 
-/* These are defined in assembly */
-PRIMITIVE(fixnum_add);
-PRIMITIVE(fixnum_subtract);
-PRIMITIVE(fixnum_multiply);
-PRIMITIVE(inline_cache_miss);
-PRIMITIVE(inline_cache_miss_tail);
+/* Generated with PRIMITIVE in primitives.cpp */
+DECLARE_PRIMITIVE(alien_address)
+DECLARE_PRIMITIVE(all_instances)
+DECLARE_PRIMITIVE(array)
+DECLARE_PRIMITIVE(array_to_quotation)
+DECLARE_PRIMITIVE(become)
+DECLARE_PRIMITIVE(bignum_add)
+DECLARE_PRIMITIVE(bignum_and)
+DECLARE_PRIMITIVE(bignum_bitp)
+DECLARE_PRIMITIVE(bignum_divint)
+DECLARE_PRIMITIVE(bignum_divmod)
+DECLARE_PRIMITIVE(bignum_eq)
+DECLARE_PRIMITIVE(bignum_greater)
+DECLARE_PRIMITIVE(bignum_greatereq)
+DECLARE_PRIMITIVE(bignum_less)
+DECLARE_PRIMITIVE(bignum_lesseq)
+DECLARE_PRIMITIVE(bignum_log2)
+DECLARE_PRIMITIVE(bignum_mod)
+DECLARE_PRIMITIVE(bignum_multiply)
+DECLARE_PRIMITIVE(bignum_not)
+DECLARE_PRIMITIVE(bignum_or)
+DECLARE_PRIMITIVE(bignum_shift)
+DECLARE_PRIMITIVE(bignum_subtract)
+DECLARE_PRIMITIVE(bignum_to_fixnum)
+DECLARE_PRIMITIVE(bignum_to_float)
+DECLARE_PRIMITIVE(bignum_xor)
+DECLARE_PRIMITIVE(bits_double)
+DECLARE_PRIMITIVE(bits_float)
+DECLARE_PRIMITIVE(byte_array)
+DECLARE_PRIMITIVE(byte_array_to_bignum)
+DECLARE_PRIMITIVE(call_clear)
+DECLARE_PRIMITIVE(callback)
+DECLARE_PRIMITIVE(callstack)
+DECLARE_PRIMITIVE(callstack_to_array)
+DECLARE_PRIMITIVE(check_datastack)
+DECLARE_PRIMITIVE(clone)
+DECLARE_PRIMITIVE(code_room)
+DECLARE_PRIMITIVE(compact_gc)
+DECLARE_PRIMITIVE(compute_identity_hashcode)
+DECLARE_PRIMITIVE(data_room)
+DECLARE_PRIMITIVE(datastack)
+DECLARE_PRIMITIVE(die)
+DECLARE_PRIMITIVE(disable_gc_events)
+DECLARE_PRIMITIVE(dispatch_stats)
+DECLARE_PRIMITIVE(displaced_alien)
+DECLARE_PRIMITIVE(dlclose)
+DECLARE_PRIMITIVE(dll_validp)
+DECLARE_PRIMITIVE(dlopen)
+DECLARE_PRIMITIVE(dlsym)
+DECLARE_PRIMITIVE(double_bits)
+DECLARE_PRIMITIVE(enable_gc_events)
+DECLARE_PRIMITIVE(existsp)
+DECLARE_PRIMITIVE(exit)
+DECLARE_PRIMITIVE(fclose)
+DECLARE_PRIMITIVE(fflush)
+DECLARE_PRIMITIVE(fgetc)
+DECLARE_PRIMITIVE(fixnum_divint)
+DECLARE_PRIMITIVE(fixnum_divmod)
+DECLARE_PRIMITIVE(fixnum_shift)
+DECLARE_PRIMITIVE(fixnum_to_bignum)
+DECLARE_PRIMITIVE(fixnum_to_float)
+DECLARE_PRIMITIVE(float_add)
+DECLARE_PRIMITIVE(float_bits)
+DECLARE_PRIMITIVE(float_divfloat)
+DECLARE_PRIMITIVE(float_eq)
+DECLARE_PRIMITIVE(float_greater)
+DECLARE_PRIMITIVE(float_greatereq)
+DECLARE_PRIMITIVE(float_less)
+DECLARE_PRIMITIVE(float_lesseq)
+DECLARE_PRIMITIVE(float_mod)
+DECLARE_PRIMITIVE(float_multiply)
+DECLARE_PRIMITIVE(float_subtract)
+DECLARE_PRIMITIVE(float_to_bignum)
+DECLARE_PRIMITIVE(float_to_fixnum)
+DECLARE_PRIMITIVE(float_to_str)
+DECLARE_PRIMITIVE(fopen)
+DECLARE_PRIMITIVE(fputc)
+DECLARE_PRIMITIVE(fread)
+DECLARE_PRIMITIVE(fseek)
+DECLARE_PRIMITIVE(ftell)
+DECLARE_PRIMITIVE(full_gc)
+DECLARE_PRIMITIVE(fwrite)
+DECLARE_PRIMITIVE(identity_hashcode)
+DECLARE_PRIMITIVE(innermost_stack_frame_executing)
+DECLARE_PRIMITIVE(innermost_stack_frame_scan)
+DECLARE_PRIMITIVE(jit_compile)
+DECLARE_PRIMITIVE(load_locals)
+DECLARE_PRIMITIVE(lookup_method)
+DECLARE_PRIMITIVE(mega_cache_miss)
+DECLARE_PRIMITIVE(minor_gc)
+DECLARE_PRIMITIVE(modify_code_heap)
+DECLARE_PRIMITIVE(nano_count)
+DECLARE_PRIMITIVE(optimized_p)
+DECLARE_PRIMITIVE(profiling)
+DECLARE_PRIMITIVE(quot_compiled_p)
+DECLARE_PRIMITIVE(quotation_code)
+DECLARE_PRIMITIVE(reset_dispatch_stats)
+DECLARE_PRIMITIVE(resize_array)
+DECLARE_PRIMITIVE(resize_byte_array)
+DECLARE_PRIMITIVE(resize_string)
+DECLARE_PRIMITIVE(retainstack)
+DECLARE_PRIMITIVE(save_image)
+DECLARE_PRIMITIVE(save_image_and_exit)
+DECLARE_PRIMITIVE(set_datastack)
+DECLARE_PRIMITIVE(set_innermost_stack_frame_quot)
+DECLARE_PRIMITIVE(set_retainstack)
+DECLARE_PRIMITIVE(set_slot)
+DECLARE_PRIMITIVE(set_special_object)
+DECLARE_PRIMITIVE(set_string_nth_fast)
+DECLARE_PRIMITIVE(set_string_nth_slow)
+DECLARE_PRIMITIVE(size)
+DECLARE_PRIMITIVE(sleep)
+DECLARE_PRIMITIVE(special_object)
+DECLARE_PRIMITIVE(str_to_float)
+DECLARE_PRIMITIVE(string)
+DECLARE_PRIMITIVE(string_nth)
+DECLARE_PRIMITIVE(strip_stack_traces)
+DECLARE_PRIMITIVE(system_micros)
+DECLARE_PRIMITIVE(tuple)
+DECLARE_PRIMITIVE(tuple_boa)
+DECLARE_PRIMITIVE(unimplemented)
+DECLARE_PRIMITIVE(uninitialized_byte_array)
+DECLARE_PRIMITIVE(word)
+DECLARE_PRIMITIVE(word_code)
+DECLARE_PRIMITIVE(wrapper)
 
-/* These are generated with macros in alien.c */
-PRIMITIVE(alien_signed_cell);
-PRIMITIVE(set_alien_signed_cell);
-PRIMITIVE(alien_unsigned_cell);
-PRIMITIVE(set_alien_unsigned_cell);
-PRIMITIVE(alien_signed_8);
-PRIMITIVE(set_alien_signed_8);
-PRIMITIVE(alien_unsigned_8);
-PRIMITIVE(set_alien_unsigned_8);
-PRIMITIVE(alien_signed_4);
-PRIMITIVE(set_alien_signed_4);
-PRIMITIVE(alien_unsigned_4);
-PRIMITIVE(set_alien_unsigned_4);
-PRIMITIVE(alien_signed_2);
-PRIMITIVE(set_alien_signed_2);
-PRIMITIVE(alien_unsigned_2);
-PRIMITIVE(set_alien_unsigned_2);
-PRIMITIVE(alien_signed_1);
-PRIMITIVE(set_alien_signed_1);
-PRIMITIVE(alien_unsigned_1);
-PRIMITIVE(set_alien_unsigned_1);
-PRIMITIVE(alien_float);
-PRIMITIVE(set_alien_float);
-PRIMITIVE(alien_double);
-PRIMITIVE(set_alien_double);
-PRIMITIVE(alien_cell);
-PRIMITIVE(set_alien_cell);
+/* These are generated with macros in alien.cpp, and not with PRIMIIVE in
+primitives.cpp */
+DECLARE_PRIMITIVE(alien_signed_cell)
+DECLARE_PRIMITIVE(set_alien_signed_cell)
+DECLARE_PRIMITIVE(alien_unsigned_cell)
+DECLARE_PRIMITIVE(set_alien_unsigned_cell)
+DECLARE_PRIMITIVE(alien_signed_8)
+DECLARE_PRIMITIVE(set_alien_signed_8)
+DECLARE_PRIMITIVE(alien_unsigned_8)
+DECLARE_PRIMITIVE(set_alien_unsigned_8)
+DECLARE_PRIMITIVE(alien_signed_4)
+DECLARE_PRIMITIVE(set_alien_signed_4)
+DECLARE_PRIMITIVE(alien_unsigned_4)
+DECLARE_PRIMITIVE(set_alien_unsigned_4)
+DECLARE_PRIMITIVE(alien_signed_2)
+DECLARE_PRIMITIVE(set_alien_signed_2)
+DECLARE_PRIMITIVE(alien_unsigned_2)
+DECLARE_PRIMITIVE(set_alien_unsigned_2)
+DECLARE_PRIMITIVE(alien_signed_1)
+DECLARE_PRIMITIVE(set_alien_signed_1)
+DECLARE_PRIMITIVE(alien_unsigned_1)
+DECLARE_PRIMITIVE(set_alien_unsigned_1)
+DECLARE_PRIMITIVE(alien_float)
+DECLARE_PRIMITIVE(set_alien_float)
+DECLARE_PRIMITIVE(alien_double)
+DECLARE_PRIMITIVE(set_alien_double)
+DECLARE_PRIMITIVE(alien_cell)
+DECLARE_PRIMITIVE(set_alien_cell)
 
 }
diff --git a/vm/profiler.cpp b/vm/profiler.cpp
index 50e88cc57a..fea78692ea 100755
--- a/vm/profiler.cpp
+++ b/vm/profiler.cpp
@@ -14,7 +14,7 @@ code_block *factor_vm::compile_profiling_stub(cell word_)
 	data_root word(word_,this);
 
 	jit jit(code_block_profiling,word.value(),this);
-	jit.emit_with(special_objects[JIT_PROFILING],word.value());
+	jit.emit_with_literal(special_objects[JIT_PROFILING],word.value());
 
 	return jit.to_code_block();
 }
@@ -25,22 +25,34 @@ void factor_vm::set_profiling(bool profiling)
 	if(profiling == profiling_p)
 		return;
 
-	profiling_p = profiling;
-
 	/* Push everything to tenured space so that we can heap scan
 	and allocate profiling blocks if necessary */
 	primitive_full_gc();
 
 	data_root words(find_all_words(),this);
 
-	cell i;
+	profiling_p = profiling;
+
 	cell length = array_capacity(words.untagged());
-	for(i = 0; i < length; i++)
+	for(cell i = 0; i < length; i++)
 	{
 		tagged word(array_nth(words.untagged(),i));
+
+		/* Note: can't do w->profiling = ... since LHS evaluates
+		before RHS, and if RHS does a GC, we will have an
+		invalid pointer on the LHS */
 		if(profiling)
+		{
+			if(!word->profiling)
+			{
+				code_block *profiling_block = compile_profiling_stub(word.value());
+				word->profiling = profiling_block;
+			}
+
 			word->counter = tag_fixnum(0);
-		update_word_xt(word.untagged());
+		}
+
+		update_word_entry_point(word.untagged());
 	}
 
 	update_code_heap_words();
@@ -48,7 +60,7 @@ void factor_vm::set_profiling(bool profiling)
 
 void factor_vm::primitive_profiling()
 {
-	set_profiling(to_boolean(dpop()));
+	set_profiling(to_boolean(ctx->pop()));
 }
 
 }
diff --git a/vm/quotations.cpp b/vm/quotations.cpp
index fc19266cee..faa770c512 100755
--- a/vm/quotations.cpp
+++ b/vm/quotations.cpp
@@ -36,9 +36,14 @@ includes stack shufflers, some fixnum arithmetic words, and words such as tag,
 slot and eq?. A primitive call is relatively expensive (two subroutine calls)
 so this results in a big speedup for relatively little effort. */
 
+void quotation_jit::init_quotation(cell quot)
+{
+	elements = untag(quot)->array;
+}
+
 bool quotation_jit::primitive_call_p(cell i, cell length)
 {
-	return (i + 2) == length && array_nth(elements.untagged(),i + 1) == parent->special_objects[JIT_PRIMITIVE_WORD];
+	return (i + 2) <= length && array_nth(elements.untagged(),i + 1) == parent->special_objects[JIT_PRIMITIVE_WORD];
 }
 
 bool quotation_jit::fast_if_p(cell i, cell length)
@@ -77,18 +82,23 @@ bool quotation_jit::declare_p(cell i, cell length)
 		&& array_nth(elements.untagged(),i + 1) == parent->special_objects[JIT_DECLARE_WORD];
 }
 
+bool quotation_jit::word_stack_frame_p(cell obj)
+{
+	return to_boolean(untag(obj)->subprimitive)
+		|| obj == parent->special_objects[JIT_PRIMITIVE_WORD];
+}
+
 bool quotation_jit::stack_frame_p()
 {
 	fixnum length = array_capacity(elements.untagged());
-	fixnum i;
 
-	for(i = 0; i < length - 1; i++)
+	for(fixnum i = 0; i < length; i++)
 	{
 		cell obj = array_nth(elements.untagged(),i);
 		switch(tagged(obj).type())
 		{
 		case WORD_TYPE:
-			if(!parent->to_boolean(untag(obj)->subprimitive))
+			if(i != length - 1 || word_stack_frame_p(obj))
 				return true;
 			break;
 		case QUOTATION_TYPE:
@@ -120,7 +130,7 @@ void quotation_jit::emit_quot(cell quot_)
 		literal(array_nth(elements,0));
 	else
 	{
-		if(compiling) parent->jit_compile(quot.value(),relocate);
+		if(compiling) parent->jit_compile_quot(quot.value(),relocate);
 		literal(quot.value());
 	}
 }
@@ -148,64 +158,41 @@ void quotation_jit::iterate_quotation()
 		switch(obj.type())
 		{
 		case WORD_TYPE:
-			/* Intrinsics */
-			if(parent->to_boolean(obj.as()->subprimitive))
-				emit_subprimitive(obj.value());
-			/* The (execute) primitive is special-cased */
-			else if(obj.value() == parent->special_objects[JIT_EXECUTE_WORD])
+			/* Sub-primitives */
+			if(to_boolean(obj.as()->subprimitive))
 			{
-				if(i == length - 1)
-				{
-					if(stack_frame) emit(parent->special_objects[JIT_EPILOG]);
-					tail_call = true;
-					emit(parent->special_objects[JIT_EXECUTE_JUMP]);
-				}
-				else
-					emit(parent->special_objects[JIT_EXECUTE_CALL]);
+				tail_call = emit_subprimitive(obj.value(), /* word */
+					i == length - 1, /* tail_call_p */
+					stack_frame); /* stack_frame_p */
 			}
 			/* Everything else */
-			else
+			else if(i == length - 1)
 			{
-				if(i == length - 1)
-				{
-					if(stack_frame) emit(parent->special_objects[JIT_EPILOG]);
-					tail_call = true;
-					/* Inline cache misses are special-cased.
-					   The calling convention for tail
-					   calls stores the address of the next
-					   instruction in a register. However,
-					   PIC miss stubs themselves tail-call
-					   the inline cache miss primitive, and
-					   we don't want to clobber the saved
-					   address. */
-					if(obj.value() == parent->special_objects[PIC_MISS_WORD]
-					   || obj.value() == parent->special_objects[PIC_MISS_TAIL_WORD])
-					{
-						word_special(obj.value());
-					}
-					else
-					{
-						word_jump(obj.value());
-					}
-				}
-				else
-					word_call(obj.value());
+				if(stack_frame) emit(parent->special_objects[JIT_EPILOG]);
+				tail_call = true;
+				word_jump(obj.value());
 			}
+			else
+				word_call(obj.value());
 			break;
 		case WRAPPER_TYPE:
 			push(obj.as()->object);
 			break;
-		case FIXNUM_TYPE:
+		case BYTE_ARRAY_TYPE:
 			/* Primitive calls */
 			if(primitive_call_p(i,length))
 			{
-				literal(tag_fixnum(0));
-				literal(obj.value());
+				/* On x86-64 and PowerPC, the VM pointer is stored in
+				a register; on other platforms, the RT_VM relocation
+				is used and it needs an offset parameter */
+#ifdef FACTOR_X86
+				parameter(tag_fixnum(0));
+#endif
+				parameter(obj.value());
+				parameter(false_object);
 				emit(parent->special_objects[JIT_PRIMITIVE]);
 
 				i++;
-
-				tail_call = true;
 			}
 			else
 				push(obj.value());
@@ -252,12 +239,13 @@ void quotation_jit::iterate_quotation()
 			/* Method dispatch */
 			if(mega_lookup_p(i,length))
 			{
+				if(stack_frame) emit(parent->special_objects[JIT_EPILOG]);
+				tail_call = true;
 				emit_mega_cache_lookup(
 					array_nth(elements.untagged(),i),
 					untag_fixnum(array_nth(elements.untagged(),i + 1)),
 					array_nth(elements.untagged(),i + 2));
 				i += 3;
-				tail_call = true;
 			}
 			/* Non-optimizing compiler ignores declarations */
 			else if(declare_p(i,length))
@@ -275,74 +263,73 @@ void quotation_jit::iterate_quotation()
 	{
 		set_position(length);
 
-		if(stack_frame)
-			emit(parent->special_objects[JIT_EPILOG]);
+		if(stack_frame) emit(parent->special_objects[JIT_EPILOG]);
 		emit(parent->special_objects[JIT_RETURN]);
 	}
 }
 
-void factor_vm::set_quot_xt(quotation *quot, code_block *code)
+void factor_vm::set_quot_entry_point(quotation *quot, code_block *code)
 {
 	quot->code = code;
-	quot->xt = code->xt();
+	quot->entry_point = code->entry_point();
 }
 
 /* Allocates memory */
-void factor_vm::jit_compile(cell quot_, bool relocating)
+code_block *factor_vm::jit_compile_quot(cell owner_, cell quot_, bool relocating)
 {
+	data_root owner(owner_,this);
 	data_root quot(quot_,this);
-	if(quot->code) return;
 
-	quotation_jit compiler(quot.value(),true,relocating,this);
+	quotation_jit compiler(owner.value(),true,relocating,this);
+	compiler.init_quotation(quot.value());
 	compiler.iterate_quotation();
 
 	code_block *compiled = compiler.to_code_block();
-	set_quot_xt(quot.untagged(),compiled);
 
-	if(relocating) relocate_code_block(compiled);
+	if(relocating) initialize_code_block(compiled);
+
+	return compiled;
+}
+
+void factor_vm::jit_compile_quot(cell quot_, bool relocating)
+{
+	data_root quot(quot_,this);
+	if(!quot_compiled_p(quot.untagged()))
+	{
+		code_block *compiled = jit_compile_quot(quot.value(),quot.value(),relocating);
+		set_quot_entry_point(quot.untagged(),compiled);
+	}
 }
 
 void factor_vm::primitive_jit_compile()
 {
-	jit_compile(dpop(),true);
+	jit_compile_quot(ctx->pop(),true);
+}
+
+code_block *factor_vm::lazy_jit_compile_block()
+{
+	return untag(special_objects[LAZY_JIT_COMPILE_WORD])->code;
 }
 
 /* push a new quotation on the stack */
 void factor_vm::primitive_array_to_quotation()
 {
 	quotation *quot = allot(sizeof(quotation));
-	quot->array = dpeek();
+
+	quot->array = ctx->peek();
 	quot->cached_effect = false_object;
 	quot->cache_counter = false_object;
-	quot->xt = (void *)lazy_jit_compile;
-	quot->code = NULL;
-	drepl(tag(quot));
+	set_quot_entry_point(quot,lazy_jit_compile_block());
+
+	ctx->replace(tag(quot));
 }
 
-void factor_vm::primitive_quotation_xt()
+void factor_vm::primitive_quotation_code()
 {
-	quotation *quot = untag_check(dpeek());
-	drepl(allot_cell((cell)quot->xt));
-}
+	quotation *quot = untag_check(ctx->pop());
 
-void factor_vm::compile_all_words()
-{
-	data_root words(find_all_words(),this);
-
-	cell i;
-	cell length = array_capacity(words.untagged());
-	for(i = 0; i < length; i++)
-	{
-		data_root word(array_nth(words.untagged(),i),this);
-
-		if(!word->code || !word->code->optimized_p())
-			jit_compile_word(word.value(),word->def,false);
-
-		update_word_xt(word.untagged());
-
-	}
-
-	update_code_heap_words();
+	ctx->push(allot_cell((cell)quot->code->entry_point()));
+	ctx->push(allot_cell((cell)quot->code + quot->code->size()));
 }
 
 /* Allocates memory */
@@ -352,30 +339,58 @@ fixnum factor_vm::quot_code_offset_to_scan(cell quot_, cell offset)
 	data_root array(quot->array,this);
 
 	quotation_jit compiler(quot.value(),false,false,this);
+	compiler.init_quotation(quot.value());
 	compiler.compute_position(offset);
 	compiler.iterate_quotation();
 
 	return compiler.get_position();
 }
 
-cell factor_vm::lazy_jit_compile_impl(cell quot_, stack_frame *stack)
+cell factor_vm::lazy_jit_compile(cell quot_)
 {
 	data_root quot(quot_,this);
-	ctx->callstack_top = stack;
-	jit_compile(quot.value(),true);
+
+	assert(!quot_compiled_p(quot.untagged()));
+
+	code_block *compiled = jit_compile_quot(quot.value(),quot.value(),true);
+	set_quot_entry_point(quot.untagged(),compiled);
+
 	return quot.value();
 }
 
-VM_ASM_API cell lazy_jit_compile_impl(cell quot_, stack_frame *stack, factor_vm *parent)
+VM_C_API cell lazy_jit_compile(cell quot, factor_vm *parent)
 {
-	return parent->lazy_jit_compile_impl(quot_,stack);
+	return parent->lazy_jit_compile(quot);
+}
+
+bool factor_vm::quot_compiled_p(quotation *quot)
+{
+	return quot->code != NULL && quot->code != lazy_jit_compile_block();
 }
 
 void factor_vm::primitive_quot_compiled_p()
 {
-	tagged quot(dpop());
+	tagged quot(ctx->pop());
 	quot.untag_check(this);
-	dpush(tag_boolean(quot->code != NULL));
+	ctx->push(tag_boolean(quot_compiled_p(quot.untagged())));
+}
+
+cell factor_vm::find_all_quotations()
+{
+	return instances(QUOTATION_TYPE);
+}
+
+void factor_vm::initialize_all_quotations()
+{
+	data_root quotations(find_all_quotations(),this);
+
+	cell length = array_capacity(quotations.untagged());
+	for(cell i = 0; i < length; i++)
+	{
+		data_root quot(array_nth(quotations.untagged(),i),this);
+		if(!quot->code)
+			set_quot_entry_point(quot.untagged(),lazy_jit_compile_block());
+	}
 }
 
 }
diff --git a/vm/quotations.hpp b/vm/quotations.hpp
index 6d04d80de3..69755302ea 100755
--- a/vm/quotations.hpp
+++ b/vm/quotations.hpp
@@ -5,12 +5,13 @@ struct quotation_jit : public jit {
 	data_root elements;
 	bool compiling, relocate;
 
-	explicit quotation_jit(cell quot, bool compiling_, bool relocate_, factor_vm *vm)
-		: jit(code_block_unoptimized,quot,vm),
-		  elements(owner.as().untagged()->array,vm),
+	explicit quotation_jit(cell owner, bool compiling_, bool relocate_, factor_vm *vm)
+		: jit(code_block_unoptimized,owner,vm),
+		  elements(false_object,vm),
 		  compiling(compiling_),
 		  relocate(relocate_){};
 
+	void init_quotation(cell quot);
 	void emit_mega_cache_lookup(cell methods, fixnum index, cell cache);
 	bool primitive_call_p(cell i, cell length);
 	bool trivial_quotation_p(array *elements);
@@ -21,10 +22,11 @@ struct quotation_jit : public jit {
 	bool fast_3dip_p(cell i, cell length);
 	bool mega_lookup_p(cell i, cell length);
 	bool declare_p(cell i, cell length);
+	bool word_stack_frame_p(cell obj);
 	bool stack_frame_p();
 	void iterate_quotation();
 };
 
-VM_ASM_API cell lazy_jit_compile_impl(cell quot, stack_frame *stack, factor_vm *parent);
+VM_C_API cell lazy_jit_compile(cell quot, factor_vm *parent);
 
 }
diff --git a/vm/run.cpp b/vm/run.cpp
index 6d3e9f7374..dfff8f2f2d 100755
--- a/vm/run.cpp
+++ b/vm/run.cpp
@@ -3,71 +3,27 @@
 namespace factor
 {
 
-void factor_vm::primitive_getenv()
-{
-	fixnum e = untag_fixnum(dpeek());
-	drepl(special_objects[e]);
-}
-
-void factor_vm::primitive_setenv()
-{
-	fixnum e = untag_fixnum(dpop());
-	cell value = dpop();
-	special_objects[e] = value;
-}
-
 void factor_vm::primitive_exit()
 {
-	exit(to_fixnum(dpop()));
+	exit(to_fixnum(ctx->pop()));
 }
 
-void factor_vm::primitive_micros()
+void factor_vm::primitive_system_micros()
 {
-	box_unsigned_8(current_micros());
+	ctx->push(from_unsigned_8(system_micros()));
+}
+
+void factor_vm::primitive_nano_count()
+{
+	u64 nanos = nano_count();
+	if(nanos < last_nano_count) critical_error("Monotonic counter decreased",0);
+	last_nano_count = nanos;
+	ctx->push(from_unsigned_8(nanos));
 }
 
 void factor_vm::primitive_sleep()
 {
-	sleep_micros(to_cell(dpop()));
-}
-
-void factor_vm::primitive_set_slot()
-{
-	fixnum slot = untag_fixnum(dpop());
-	object *obj = untag(dpop());
-	cell value = dpop();
-
-	cell *slot_ptr = &obj->slots()[slot];
-	*slot_ptr = value;
-	write_barrier(slot_ptr);
-}
-
-void factor_vm::primitive_load_locals()
-{
-	fixnum count = untag_fixnum(dpop());
-	memcpy((cell *)(rs + sizeof(cell)),(cell *)(ds - sizeof(cell) * (count - 1)),sizeof(cell) * count);
-	ds -= sizeof(cell) * count;
-	rs += sizeof(cell) * count;
-}
-
-cell factor_vm::clone_object(cell obj_)
-{
-	data_root obj(obj_,this);
-
-	if(immediate_p(obj.value()))
-		return obj.value();
-	else
-	{
-		cell size = object_size(obj.value());
-		object *new_obj = allot_object(header(obj.type()),size);
-		memcpy(new_obj,obj.untagged(),size);
-		return tag_dynamic(new_obj);
-	}
-}
-
-void factor_vm::primitive_clone()
-{
-	drepl(clone_object(dpeek()));
+	sleep_nanos(to_unsigned_8(ctx->pop()));
 }
 
 }
diff --git a/vm/run.hpp b/vm/run.hpp
index 6ca2e50464..412ef35bb4 100755
--- a/vm/run.hpp
+++ b/vm/run.hpp
@@ -1,103 +1,4 @@
 namespace factor
 {
 
-static const cell special_object_count = 70;
-
-enum special_object {
-	OBJ_NAMESTACK,            /* used by library only */
-	OBJ_CATCHSTACK,           /* used by library only, per-callback */
-
-	OBJ_CURRENT_CALLBACK = 2, /* used by library only, per-callback */
-	OBJ_WALKER_HOOK,          /* non-local exit hook, used by library only */
-	OBJ_CALLCC_1,             /* used to pass the value in callcc1 */
-
-	OBJ_BREAK            = 5, /* quotation called by throw primitive */
-	OBJ_ERROR,                /* a marker consed onto kernel errors */
-
-	OBJ_CELL_SIZE        = 7, /* sizeof(cell) */
-	OBJ_CPU,                  /* CPU architecture */
-	OBJ_OS,                   /* operating system name */
-
-	OBJ_ARGS            = 10, /* command line arguments */
-	OBJ_STDIN,                /* stdin FILE* handle */
-	OBJ_STDOUT,               /* stdout FILE* handle */
-
-	OBJ_IMAGE           = 13, /* image path name */
-	OBJ_EXECUTABLE,		  /* runtime executable path name */
-
-	OBJ_EMBEDDED 	    = 15, /* are we embedded in another app? */
-	OBJ_EVAL_CALLBACK,        /* used when Factor is embedded in a C app */
-	OBJ_YIELD_CALLBACK,       /* used when Factor is embedded in a C app */
-	OBJ_SLEEP_CALLBACK,       /* used when Factor is embedded in a C app */
-
-	OBJ_COCOA_EXCEPTION = 19, /* Cocoa exception handler quotation */
-
-	OBJ_BOOT            = 20, /* boot quotation */
-	OBJ_GLOBAL,               /* global namespace */
-
-	/* Quotation compilation in quotations.c */
-	JIT_PROLOG          = 23,
-	JIT_PRIMITIVE_WORD,
-	JIT_PRIMITIVE,
-	JIT_WORD_JUMP,
-	JIT_WORD_CALL,
-	JIT_WORD_SPECIAL,
-	JIT_IF_WORD,
-	JIT_IF,
-	JIT_EPILOG,
-	JIT_RETURN,
-	JIT_PROFILING,
-	JIT_PUSH_IMMEDIATE,
-	JIT_DIP_WORD,
-	JIT_DIP,
-	JIT_2DIP_WORD,
-	JIT_2DIP,
-	JIT_3DIP_WORD,
-	JIT_3DIP,
-	JIT_EXECUTE_WORD,
-	JIT_EXECUTE_JUMP,
-	JIT_EXECUTE_CALL,
-	JIT_DECLARE_WORD,
-
-	/* Callback stub generation in callbacks.c */
-	CALLBACK_STUB       = 45,
-
-	/* Polymorphic inline cache generation in inline_cache.c */
-	PIC_LOAD            = 47,
-	PIC_TAG,
-	PIC_TUPLE,
-	PIC_CHECK_TAG,
-	PIC_CHECK_TUPLE,
-	PIC_HIT,
-	PIC_MISS_WORD,
-	PIC_MISS_TAIL_WORD,
-
-	/* Megamorphic cache generation in dispatch.c */
-	MEGA_LOOKUP         = 57,
-	MEGA_LOOKUP_WORD,
-	MEGA_MISS_WORD,
-
-	OBJ_UNDEFINED       = 60, /* default quotation for undefined words */
-
-	OBJ_STDERR          = 61, /* stderr FILE* handle */
-
-	OBJ_STAGE2          = 62, /* have we bootstrapped? */
-
-	OBJ_CURRENT_THREAD  = 63,
-
-	OBJ_THREADS         = 64,
-	OBJ_RUN_QUEUE       = 65,
-	OBJ_SLEEP_QUEUE     = 66,
-};
-
-#define OBJ_FIRST_SAVE OBJ_BOOT
-#define OBJ_LAST_SAVE OBJ_STAGE2
-
-inline static bool save_env_p(cell i)
-{
-	return (i >= OBJ_FIRST_SAVE && i <= OBJ_LAST_SAVE);
 }
-
-}
-
- 
diff --git a/vm/slot_visitor.hpp b/vm/slot_visitor.hpp
index e777347622..0ab9cc171d 100644
--- a/vm/slot_visitor.hpp
+++ b/vm/slot_visitor.hpp
@@ -1,6 +1,22 @@
 namespace factor
 {
 
+/* Slot visitors iterate over the slots of an object, applying a functor to
+each one that is a non-immediate slot. The pointer is untagged first. The
+functor returns a new untagged object pointer. The return value may or may not equal the old one,
+however the new pointer receives the same tag before being stored back to the
+original location.
+
+Slots storing immediate values are left unchanged and the visitor does inspect
+them.
+
+This is used by GC's copying, sweep and compact phases, and the implementation
+of the become primitive.
+
+Iteration is driven by visit_*() methods. Some of them define GC roots:
+- visit_roots()
+- visit_contexts() */
+
 template struct slot_visitor {
 	factor_vm *parent;
 	Visitor visitor;
@@ -8,99 +24,194 @@ template struct slot_visitor {
 	explicit slot_visitor(factor_vm *parent_, Visitor visitor_) :
 		parent(parent_), visitor(visitor_) {}
 
-	void visit_handle(cell *handle)
+	cell visit_pointer(cell pointer);
+	void visit_handle(cell *handle);
+	void visit_slots(object *ptr, cell payload_start);
+	void visit_slots(object *ptr);
+	void visit_stack_elements(segment *region, cell *top);
+	void visit_data_roots();
+	void visit_bignum_roots();
+	void visit_callback_roots();
+	void visit_literal_table_roots();
+	void visit_roots();
+	void visit_contexts();
+	void visit_code_block_objects(code_block *compiled);
+	void visit_embedded_literals(code_block *compiled);
+};
+
+template
+cell slot_visitor::visit_pointer(cell pointer)
+{
+	if(immediate_p(pointer)) return pointer;
+
+	object *untagged = untag(pointer);
+	untagged = visitor(untagged);
+	return RETAG(untagged,TAG(pointer));
+}
+
+template
+void slot_visitor::visit_handle(cell *handle)
+{
+	*handle = visit_pointer(*handle);
+}
+
+template
+void slot_visitor::visit_slots(object *ptr, cell payload_start)
+{
+	cell *slot = (cell *)ptr;
+	cell *end = (cell *)((cell)ptr + payload_start);
+
+	if(slot != end)
 	{
-		cell pointer = *handle;
-
-		if(immediate_p(pointer)) return;
-
-		object *untagged = untag(pointer);
-		untagged = visitor(untagged);
-		*handle = RETAG(untagged,TAG(pointer));
+		slot++;
+		for(; slot < end; slot++) visit_handle(slot);
 	}
+}
 
-	void visit_slots(object *ptr, cell payload_start)
+template
+void slot_visitor::visit_slots(object *ptr)
+{
+	visit_slots(ptr,ptr->binary_payload_start());
+}
+
+template
+void slot_visitor::visit_stack_elements(segment *region, cell *top)
+{
+	for(cell *ptr = (cell *)region->start; ptr <= top; ptr++)
+		visit_handle(ptr);
+}
+
+template
+void slot_visitor::visit_data_roots()
+{
+	std::vector::const_iterator iter = parent->data_roots.begin();
+	std::vector::const_iterator end = parent->data_roots.end();
+
+	for(; iter < end; iter++)
 	{
-		cell *slot = (cell *)ptr;
-		cell *end = (cell *)((cell)ptr + payload_start);
-
-		if(slot != end)
-		{
-			slot++;
-			for(; slot < end; slot++) visit_handle(slot);
-		}
+		data_root_range r = *iter;
+		for(cell index = 0; index < r.len; index++)
+			visit_handle(r.start + index);
 	}
+}
 
-	void visit_slots(object *ptr)
+template
+void slot_visitor::visit_bignum_roots()
+{
+	std::vector::const_iterator iter = parent->bignum_roots.begin();
+	std::vector::const_iterator end = parent->bignum_roots.end();
+
+	for(; iter < end; iter++)
 	{
-		visit_slots(ptr,ptr->binary_payload_start());
+		cell *handle = (cell *)(*iter);
+
+		if(*handle)
+			*handle = (cell)visitor(*(object **)handle);
 	}
+}
 
-	void visit_stack_elements(segment *region, cell *top)
+template
+struct callback_slot_visitor {
+	callback_heap *callbacks;
+	slot_visitor *visitor;
+
+	explicit callback_slot_visitor(callback_heap *callbacks_, slot_visitor *visitor_) :
+		callbacks(callbacks_), visitor(visitor_) {}
+
+	void operator()(code_block *stub)
 	{
-		for(cell *ptr = (cell *)region->start; ptr <= top; ptr++)
-			visit_handle(ptr);
-	}
-
-	void visit_data_roots()
-	{
-		std::vector::const_iterator iter = parent->data_roots.begin();
-		std::vector::const_iterator end = parent->data_roots.end();
-
-		for(; iter < end; iter++)
-			visit_handle((cell *)(*iter));
-	}
-
-	void visit_bignum_roots()
-	{
-		std::vector::const_iterator iter = parent->bignum_roots.begin();
-		std::vector::const_iterator end = parent->bignum_roots.end();
-
-		for(; iter < end; iter++)
-		{
-			cell *handle = (cell *)(*iter);
-
-			if(*handle)
-				*handle = (cell)visitor(*(object **)handle);
-		}
-	}
-
-	void visit_roots()
-	{
-		visit_handle(&parent->true_object);
-		visit_handle(&parent->bignum_zero);
-		visit_handle(&parent->bignum_pos_one);
-		visit_handle(&parent->bignum_neg_one);
-
-		visit_data_roots();
-		visit_bignum_roots();
-
-		for(cell i = 0; i < special_object_count; i++)
-			visit_handle(&parent->special_objects[i]);
-	}
-
-	void visit_contexts()
-	{
-		context *ctx = parent->ctx;
-
-		while(ctx)
-		{
-			visit_stack_elements(ctx->datastack_region,(cell *)ctx->datastack);
-			visit_stack_elements(ctx->retainstack_region,(cell *)ctx->retainstack);
-
-			visit_handle(&ctx->catchstack_save);
-			visit_handle(&ctx->current_callback_save);
-
-			ctx = ctx->next;
-		}
-	}
-
-	void visit_literal_references(code_block *compiled)
-	{
-		visit_handle(&compiled->owner);
-		visit_handle(&compiled->literals);
-		visit_handle(&compiled->relocation);
+		visitor->visit_handle(&stub->owner);
 	}
 };
 
+template
+void slot_visitor::visit_callback_roots()
+{
+	callback_slot_visitor callback_visitor(parent->callbacks,this);
+	parent->callbacks->each_callback(callback_visitor);
+}
+
+template
+void slot_visitor::visit_literal_table_roots()
+{
+	std::map *uninitialized_blocks = &parent->code->uninitialized_blocks;
+	std::map::const_iterator iter = uninitialized_blocks->begin();
+	std::map::const_iterator end = uninitialized_blocks->end();
+
+	std::map new_uninitialized_blocks;
+	for(; iter != end; iter++)
+	{
+		new_uninitialized_blocks.insert(std::make_pair(
+			iter->first,
+			visit_pointer(iter->second)));
+	}
+
+	parent->code->uninitialized_blocks = new_uninitialized_blocks;
+}
+
+template
+void slot_visitor::visit_roots()
+{
+	visit_handle(&parent->true_object);
+	visit_handle(&parent->bignum_zero);
+	visit_handle(&parent->bignum_pos_one);
+	visit_handle(&parent->bignum_neg_one);
+
+	visit_data_roots();
+	visit_bignum_roots();
+	visit_callback_roots();
+	visit_literal_table_roots();
+
+	for(cell i = 0; i < special_object_count; i++)
+		visit_handle(&parent->special_objects[i]);
+}
+
+template
+void slot_visitor::visit_contexts()
+{
+	context *ctx = parent->ctx;
+
+	while(ctx)
+	{
+		visit_stack_elements(ctx->datastack_region,(cell *)ctx->datastack);
+		visit_stack_elements(ctx->retainstack_region,(cell *)ctx->retainstack);
+
+		visit_handle(&ctx->catchstack_save);
+		visit_handle(&ctx->current_callback_save);
+
+		ctx = ctx->next;
+	}
+}
+
+template
+struct literal_references_visitor {
+	slot_visitor *visitor;
+
+	explicit literal_references_visitor(slot_visitor *visitor_) : visitor(visitor_) {}
+
+	void operator()(instruction_operand op)
+	{
+		if(op.rel_type() == RT_LITERAL)
+			op.store_value(visitor->visit_pointer(op.load_value()));
+	}
+};
+
+template
+void slot_visitor::visit_code_block_objects(code_block *compiled)
+{
+	visit_handle(&compiled->owner);
+	visit_handle(&compiled->parameters);
+	visit_handle(&compiled->relocation);
+}
+
+template
+void slot_visitor::visit_embedded_literals(code_block *compiled)
+{
+	if(!parent->code->uninitialized_p(compiled))
+	{
+		literal_references_visitor visitor(this);
+		compiled->each_instruction_operand(visitor);
+	}
+}
+
 }
diff --git a/vm/stacks.hpp b/vm/stacks.hpp
deleted file mode 100644
index 4906d107bc..0000000000
--- a/vm/stacks.hpp
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace factor
-{
-
-#define DEFPUSHPOP(prefix,ptr) \
-	inline cell prefix##peek() { return *(cell *)ptr; } \
-	inline void prefix##repl(cell tagged) { *(cell *)ptr = tagged; } \
-	inline cell prefix##pop() \
-	{ \
-		cell value = prefix##peek(); \
-		ptr -= sizeof(cell); \
-		return value; \
-	} \
-	inline void prefix##push(cell tagged) \
-	{ \
-		ptr += sizeof(cell); \
-		prefix##repl(tagged); \
-	}
-
-}
diff --git a/vm/strings.cpp b/vm/strings.cpp
index 9e135e6779..67e4fb4508 100644
--- a/vm/strings.cpp
+++ b/vm/strings.cpp
@@ -24,7 +24,7 @@ cell string::nth(cell index) const
 
 void factor_vm::set_string_nth_fast(string *str, cell index, cell ch)
 {
-	str->data()[index] = ch;
+	str->data()[index] = (u8)ch;
 }
 
 void factor_vm::set_string_nth_slow(string *str_, cell index, cell ch)
@@ -51,7 +51,7 @@ void factor_vm::set_string_nth_slow(string *str_, cell index, cell ch)
 		write_barrier(&str->aux);
 	}
 
-	aux->data()[index] = ((ch >> 7) ^ 1);
+	aux->data()[index] = (u16)((ch >> 7) ^ 1);
 }
 
 /* allocates memory */
@@ -101,9 +101,9 @@ string *factor_vm::allot_string(cell capacity, cell fill)
 
 void factor_vm::primitive_string()
 {
-	cell initial = to_cell(dpop());
+	cell initial = to_cell(ctx->pop());
 	cell length = unbox_array_size();
-	dpush(tag(allot_string(length,initial)));
+	ctx->push(tag(allot_string(length,initial)));
 }
 
 bool factor_vm::reallot_string_in_place_p(string *str, cell capacity)
@@ -157,31 +157,32 @@ string* factor_vm::reallot_string(string *str_, cell capacity)
 
 void factor_vm::primitive_resize_string()
 {
-	string* str = untag_check(dpop());
+	data_root str(ctx->pop(),this);
+	str.untag_check(this);
 	cell capacity = unbox_array_size();
-	dpush(tag(reallot_string(str,capacity)));
+	ctx->push(tag(reallot_string(str.untagged(),capacity)));
 }
 
 void factor_vm::primitive_string_nth()
 {
-	string *str = untag(dpop());
-	cell index = untag_fixnum(dpop());
-	dpush(tag_fixnum(str->nth(index)));
+	string *str = untag(ctx->pop());
+	cell index = untag_fixnum(ctx->pop());
+	ctx->push(tag_fixnum(str->nth(index)));
 }
 
 void factor_vm::primitive_set_string_nth_fast()
 {
-	string *str = untag(dpop());
-	cell index = untag_fixnum(dpop());
-	cell value = untag_fixnum(dpop());
+	string *str = untag(ctx->pop());
+	cell index = untag_fixnum(ctx->pop());
+	cell value = untag_fixnum(ctx->pop());
 	set_string_nth_fast(str,index,value);
 }
 
 void factor_vm::primitive_set_string_nth_slow()
 {
-	string *str = untag(dpop());
-	cell index = untag_fixnum(dpop());
-	cell value = untag_fixnum(dpop());
+	string *str = untag(ctx->pop());
+	cell index = untag_fixnum(ctx->pop());
+	cell value = untag_fixnum(ctx->pop());
 	set_string_nth_slow(str,index,value);
 }
 
diff --git a/vm/tagged.hpp b/vm/tagged.hpp
index e520e326fa..e9f89528bc 100755
--- a/vm/tagged.hpp
+++ b/vm/tagged.hpp
@@ -8,7 +8,7 @@ template cell tag(Type *value)
 
 inline static cell tag_dynamic(object *value)
 {
-	return RETAG(value,value->h.hi_tag());
+	return RETAG(value,value->type());
 }
 
 template
diff --git a/vm/tenured_space.hpp b/vm/tenured_space.hpp
index baab47e383..1b1ff5369c 100644
--- a/vm/tenured_space.hpp
+++ b/vm/tenured_space.hpp
@@ -3,7 +3,6 @@ namespace factor
 
 struct tenured_space : free_list_allocator {
 	object_start_map starts;
-	std::vector mark_stack;
 
 	explicit tenured_space(cell size, cell start) :
 		free_list_allocator(size,start), starts(size,start) {}
@@ -37,20 +36,14 @@ struct tenured_space : free_list_allocator {
 		state.clear_mark_bits();
 	}
 
-	void clear_mark_stack()
-	{
-		mark_stack.clear();
-	}
-
 	bool marked_p(object *obj)
 	{
 		return this->state.marked_p(obj);
 	}
 
-	void mark_and_push(object *obj)
+	void set_marked_p(object *obj)
 	{
 		this->state.set_marked_p(obj);
-		this->mark_stack.push_back(obj);
 	}
 
 	void sweep()
diff --git a/vm/to_tenured_collector.cpp b/vm/to_tenured_collector.cpp
index 0cee748205..b29affc480 100644
--- a/vm/to_tenured_collector.cpp
+++ b/vm/to_tenured_collector.cpp
@@ -3,20 +3,20 @@
 namespace factor
 {
 
-to_tenured_collector::to_tenured_collector(factor_vm *myvm_) :
+to_tenured_collector::to_tenured_collector(factor_vm *parent_) :
 	collector(
-		myvm_,
-		myvm_->data->tenured,
-		to_tenured_policy(myvm_)) {}
+		parent_,
+		parent_->data->tenured,
+		to_tenured_policy(parent_)) {}
 
 void to_tenured_collector::tenure_reachable_objects()
 {
-	std::vector *mark_stack = &this->target->mark_stack;
+	std::vector *mark_stack = &parent->mark_stack;
 	while(!mark_stack->empty())
 	{
-		object *obj = mark_stack->back();
+		cell ptr = mark_stack->back();
 		mark_stack->pop_back();
-		this->trace_object(obj);
+		this->trace_object((object *)ptr);
 	}
 }
 
@@ -25,7 +25,7 @@ void factor_vm::collect_to_tenured()
 	/* Copy live objects from aging space to tenured space. */
 	to_tenured_collector collector(this);
 
-	data->tenured->clear_mark_stack();
+	mark_stack.clear();
 
 	collector.trace_roots();
 	collector.trace_contexts();
@@ -42,10 +42,6 @@ void factor_vm::collect_to_tenured()
 
 	collector.tenure_reachable_objects();
 
-	current_gc->event->started_code_sweep();
-	update_code_heap_for_minor_gc(&code->points_to_aging);
-	current_gc->event->ended_code_sweep();
-
 	data->reset_generation(&nursery);
 	data->reset_generation(data->aging);
 	code->clear_remembered_set();
diff --git a/vm/to_tenured_collector.hpp b/vm/to_tenured_collector.hpp
index 2f2717efd1..8709b9a221 100644
--- a/vm/to_tenured_collector.hpp
+++ b/vm/to_tenured_collector.hpp
@@ -2,10 +2,10 @@ namespace factor
 {
 
 struct to_tenured_policy {
-	factor_vm *myvm;
+	factor_vm *parent;
 	tenured_space *tenured;
 
-	explicit to_tenured_policy(factor_vm *myvm_) : myvm(myvm_), tenured(myvm->data->tenured) {}
+	explicit to_tenured_policy(factor_vm *parent_) : parent(parent_), tenured(parent->data->tenured) {}
 
 	bool should_copy_p(object *untagged)
 	{
@@ -14,14 +14,14 @@ struct to_tenured_policy {
 
 	void promoted_object(object *obj)
 	{
-		tenured->mark_stack.push_back(obj);
+		parent->mark_stack.push_back((cell)obj);
 	}
 
 	void visited_object(object *obj) {}
 };
 
 struct to_tenured_collector : collector {
-	explicit to_tenured_collector(factor_vm *myvm_);
+	explicit to_tenured_collector(factor_vm *parent_);
 	void tenure_reachable_objects();
 };
 
diff --git a/vm/tuples.cpp b/vm/tuples.cpp
index eaac437753..e09bf17e11 100755
--- a/vm/tuples.cpp
+++ b/vm/tuples.cpp
@@ -6,27 +6,27 @@ namespace factor
 /* push a new tuple on the stack, filling its slots with f */
 void factor_vm::primitive_tuple()
 {
-	data_root layout(dpop(),this);
+	data_root layout(ctx->pop(),this);
 	tagged t(allot(tuple_size(layout.untagged())));
 	t->layout = layout.value();
 
 	memset_cell(t->data(),false_object,tuple_size(layout.untagged()) - sizeof(cell));
 
-	dpush(t.value());
+	ctx->push(t.value());
 }
 
 /* push a new tuple on the stack, filling its slots from the stack */
 void factor_vm::primitive_tuple_boa()
 {
-	data_root layout(dpop(),this);
+	data_root layout(ctx->pop(),this);
 	tagged t(allot(tuple_size(layout.untagged())));
 	t->layout = layout.value();
 
 	cell size = untag_fixnum(layout.untagged()->size) * sizeof(cell);
-	memcpy(t->data(),(cell *)(ds - size + sizeof(cell)),size);
-	ds -= size;
+	memcpy(t->data(),(cell *)(ctx->datastack - size + sizeof(cell)),size);
+	ctx->datastack -= size;
 
-	dpush(t.value());
+	ctx->push(t.value());
 }
 
 }
diff --git a/vm/utilities.cpp b/vm/utilities.cpp
index 8f063a9ad4..3e976d0619 100755
--- a/vm/utilities.cpp
+++ b/vm/utilities.cpp
@@ -18,4 +18,11 @@ cell read_cell_hex()
 	return cell;
 }
 
+/* On Windows, memcpy() is in a different DLL and the non-optimizing
+compiler can't find it */
+VM_C_API void *factor_memcpy(void *dst, void *src, size_t len)
+{
+	return memcpy(dst,src,len);
+}
+
 }
diff --git a/vm/utilities.hpp b/vm/utilities.hpp
index 94b9de6f48..cea70c0c37 100755
--- a/vm/utilities.hpp
+++ b/vm/utilities.hpp
@@ -27,5 +27,6 @@ inline static void memset_cell(void *dst, cell pattern, size_t size)
 
 vm_char *safe_strdup(const vm_char *str);
 cell read_cell_hex();
+VM_C_API void *factor_memcpy(void *dst, void *src, size_t len);
 
 }
diff --git a/vm/vm.cpp b/vm/vm.cpp
index 72c63292fd..623556416a 100755
--- a/vm/vm.cpp
+++ b/vm/vm.cpp
@@ -5,12 +5,14 @@ namespace factor
 
 factor_vm::factor_vm() :
 	nursery(0,0),
+	c_to_factor_func(NULL),
 	profiling_p(false),
 	gc_off(false),
 	current_gc(NULL),
 	gc_events(NULL),
 	fep_disabled(false),
-	full_output(false)
+	full_output(false),
+	last_nano_count(0)
 {
 	primitive_reset_dispatch_stats();
 }
diff --git a/vm/vm.hpp b/vm/vm.hpp
index aa5a3051e6..6f826ed9e0 100755
--- a/vm/vm.hpp
+++ b/vm/vm.hpp
@@ -30,6 +30,9 @@ struct factor_vm
 	/* Canonical truth value. In Factor, 't' */
 	cell true_object;
 
+	/* External entry points */
+	c_to_factor_func_type c_to_factor_func;
+
 	/* Is call counting enabled? */
 	bool profiling_p;
 
@@ -40,10 +43,6 @@ struct factor_vm
 	unsigned int signal_fpu_status;
 	stack_frame *signal_callstack_top;
 
-	/* A heap walk allows useful things to be done, like finding all
-	   references to an object for debugging purposes. */
-	cell heap_scan_ptr;
-
 	/* GC is off during heap walking */
 	bool gc_off;
 
@@ -59,6 +58,9 @@ struct factor_vm
 	/* Only set if we're performing a GC */
 	gc_state *current_gc;
 
+	/* Mark stack */
+	std::vector mark_stack;
+
 	/* If not NULL, we push GC events here */
 	std::vector *gc_events;
 
@@ -66,7 +68,7 @@ struct factor_vm
 	   allocates memory, it must wrap any references to the data and code
 	   heaps with data_root and code_root smart pointers, which register
 	   themselves here. See data_roots.hpp and code_roots.hpp */
-	std::vector data_roots;
+	std::vector data_roots;
 	std::vector bignum_roots;
 	std::vector code_roots;
 
@@ -85,14 +87,17 @@ struct factor_vm
 	/* Number of entries in a polymorphic inline cache */
 	cell max_pic_size;
 
+	/* Incrementing object counter for identity hashing */
+	cell object_counter;
+
+	/* Sanity check to ensure that monotonic counter doesn't
+	decrease */
+	u64 last_nano_count;
+
 	// contexts
-	void reset_datastack();
-	void reset_retainstack();
-	void fix_stacks();
-	void save_stacks();
 	context *alloc_context();
 	void dealloc_context(context *old_context);
-	void nest_stacks(stack_frame *magic_frame);
+	void nest_stacks();
 	void unnest_stacks();
 	void init_stacks(cell ds_size_, cell rs_size_);
 	bool stack_to_array(cell bottom, cell top);
@@ -102,6 +107,7 @@ struct factor_vm
 	void primitive_set_datastack();
 	void primitive_set_retainstack();
 	void primitive_check_datastack();
+	void primitive_load_locals();
 
 	template void iterate_active_frames(Iterator &iter)
 	{
@@ -110,21 +116,27 @@ struct factor_vm
 		while(ctx)
 		{
 			iterate_callstack(ctx,iter);
-			if(ctx->magic_frame) iter(ctx->magic_frame);
 			ctx = ctx->next;
 		}
 	}
 
 	// run
-	void primitive_getenv();
-	void primitive_setenv();
 	void primitive_exit();
-	void primitive_micros();
+	void primitive_system_micros();
+	void primitive_nano_count();
 	void primitive_sleep();
 	void primitive_set_slot();
-	void primitive_load_locals();
+
+	// objects
+	void primitive_special_object();
+	void primitive_set_special_object();
+	void primitive_identity_hashcode();
+	void compute_identity_hashcode(object *obj);
+	void primitive_compute_identity_hashcode();
+	cell object_size(cell tagged);
 	cell clone_object(cell obj_);
 	void primitive_clone();
+	void primitive_become();
 
 	// profiler
 	void init_profiler();
@@ -220,20 +232,29 @@ struct factor_vm
 	void primitive_data_room();
 	void begin_scan();
 	void end_scan();
-	void primitive_begin_scan();
-	cell next_object();
-	void primitive_next_object();
-	void primitive_end_scan();
-	cell find_all_words();
-	cell object_size(cell tagged);
+	cell instances(cell type);
+	void primitive_all_instances();
+
+	template
+	inline void each_object(Generation *gen, Iterator &iterator)
+	{
+		cell obj = gen->first_object();
+		while(obj)
+		{
+			iterator((object *)obj);
+			obj = gen->next_object_after(obj);
+		}
+	}
 
 	template inline void each_object(Iterator &iterator)
 	{
-		begin_scan();
-		cell obj;
-		while(to_boolean(obj = next_object()))
-			iterator(obj);
-		end_scan();
+		gc_off = true;
+
+		each_object(data->tenured,iterator);
+		each_object(data->aging,iterator);
+		each_object(data->nursery,iterator);
+
+		gc_off = false;
 	}
 
 	/* the write barrier must be called any time we are potentially storing a
@@ -244,6 +265,18 @@ struct factor_vm
 		*(char *)(decks_offset + ((cell)slot_ptr >> deck_bits)) = card_mark_mask;
 	}
 
+	inline void write_barrier(object *obj, cell size)
+	{
+		cell start = (cell)obj & (~card_size + 1);
+		cell end = ((cell)obj + size + card_size - 1) & (~card_size + 1);
+
+		for(cell offset = start; offset < end; offset += card_size)
+			write_barrier((cell *)offset);
+	}
+
+	// data heap checker
+	void check_data_heap();
+
 	// gc
 	void end_gc();
 	void start_gc_again();
@@ -264,16 +297,15 @@ struct factor_vm
 	void primitive_minor_gc();
 	void primitive_full_gc();
 	void primitive_compact_gc();
-	void primitive_become();
 	void inline_gc(cell *data_roots_base, cell data_roots_size);
 	void primitive_enable_gc_events();
 	void primitive_disable_gc_events();
-	object *allot_object(header header, cell size);
-	object *allot_large_object(header header, cell size);
+	object *allot_object(cell type, cell size);
+	object *allot_large_object(cell type, cell size);
 
 	template Type *allot(cell size)
 	{
-		return (Type *)allot_object(header(Type::type_number),size);
+		return (Type *)allot_object(Type::type_number,size);
 	}
 
 	inline void check_data_pointer(object *pointer)
@@ -341,9 +373,10 @@ struct factor_vm
 	void primitive_set_string_nth_slow();
 
 	//booleans
-	void box_boolean(bool value);
-	bool to_boolean(cell value);
-	inline cell tag_boolean(cell untagged);
+	cell tag_boolean(cell untagged)
+	{
+		return (untagged ? true_object : false_object);
+	}
 
 	//byte arrays
 	byte_array *allot_byte_array(cell size);
@@ -352,7 +385,6 @@ struct factor_vm
 	void primitive_resize_byte_array();
 
 	template byte_array *byte_array_from_value(Type *value);
-	template byte_array *byte_array_from_values(Type *values, cell len);
 
 	//tuples
 	void primitive_tuple();
@@ -361,10 +393,13 @@ struct factor_vm
 	//words
 	word *allot_word(cell name_, cell vocab_, cell hashcode_);
 	void primitive_word();
-	void primitive_word_xt();
-	void update_word_xt(word *w_);
+	void primitive_word_code();
+	void update_word_entry_point(word *w_);
 	void primitive_optimized_p();
 	void primitive_wrapper();
+	void jit_compile_word(cell word_, cell def_, bool relocating);
+	cell find_all_words();
+	void compile_all_words();
 
 	//math
 	void primitive_bignum_to_fixnum();
@@ -423,21 +458,19 @@ struct factor_vm
 	void primitive_bits_double();
 	fixnum to_fixnum(cell tagged);
 	cell to_cell(cell tagged);
-	void box_signed_1(s8 n);
-	void box_unsigned_1(u8 n);
-	void box_signed_2(s16 n);
-	void box_unsigned_2(u16 n);
-	void box_signed_4(s32 n);
-	void box_unsigned_4(u32 n);
-	void box_signed_cell(fixnum integer);
-	void box_unsigned_cell(cell cell);
-	void box_signed_8(s64 n);
+	cell from_signed_1(s8 n);
+	cell from_unsigned_1(u8 n);
+	cell from_signed_2(s16 n);
+	cell from_unsigned_2(u16 n);
+	cell from_signed_4(s32 n);
+	cell from_unsigned_4(u32 n);
+	cell from_signed_cell(fixnum integer);
+	cell from_unsigned_cell(cell integer);
+	cell from_signed_8(s64 n);
 	s64 to_signed_8(cell obj);
-	void box_unsigned_8(u64 n);
+	cell from_unsigned_8(u64 n);
 	u64 to_unsigned_8(cell obj);
-	void box_float(float flo);
 	float to_float(cell value);
-	void box_double(double flo);
 	double to_double(cell value);
 	inline void overflow_fixnum_add(fixnum x, fixnum y);
 	inline void overflow_fixnum_subtract(fixnum x, fixnum y);
@@ -459,6 +492,7 @@ struct factor_vm
 	void init_c_io();
 	void io_error();
 	void primitive_fopen();
+	FILE *pop_file_handle();
 	void primitive_fgetc();
 	void primitive_fread();
 	void primitive_fputc();
@@ -469,31 +503,22 @@ struct factor_vm
 	void primitive_fclose();
 
 	//code_block
-	relocation_type relocation_type_of(relocation_entry r);
-	relocation_class relocation_class_of(relocation_entry r);
-	cell relocation_offset_of(relocation_entry r);
-	void flush_icache_for(code_block *block);
-	int number_of_parameters(relocation_type type);
-	void *object_xt(cell obj);
-	void *xt_pic(word *w, cell tagged_quot);
-	void *word_xt_pic(word *w);
-	void *word_xt_pic_tail(word *w);
-	void undefined_symbol();
-	void *get_rel_symbol(array *literals, cell index);
-	cell compute_relocation(relocation_entry rel, cell index, code_block *compiled);
-	template void iterate_relocations(code_block *compiled, Iterator &iter);
-	void store_address_2_2(cell *ptr, cell value);
-	void store_address_masked(cell *ptr, fixnum value, cell mask, fixnum shift);
-	void store_address_in_code_block(cell klass, cell offset, fixnum absolute_value);
-	void update_literal_references(code_block *compiled);
-	void relocate_code_block_step(relocation_entry rel, cell index, code_block *compiled);
+	cell compute_entry_point_address(cell obj);
+	cell compute_entry_point_pic_address(word *w, cell tagged_quot);
+	cell compute_entry_point_pic_address(cell w_);
+	cell compute_entry_point_pic_tail_address(cell w_);
+	cell code_block_owner(code_block *compiled);
 	void update_word_references(code_block *compiled);
-	void update_code_block_words_and_literals(code_block *compiled);
 	void check_code_address(cell address);
-	void relocate_code_block(code_block *compiled);
+	void undefined_symbol();
+	cell compute_dlsym_address(array *literals, cell index);
+	cell compute_vm_address(cell arg);
+	void store_external_address(instruction_operand op);
+	cell compute_here_address(cell arg, cell offset, code_block *compiled);
+	void initialize_code_block(code_block *compiled);
 	void fixup_labels(array *labels, code_block *compiled);
 	code_block *allot_code_block(cell size, code_block_type type);
-	code_block *add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_);
+	code_block *add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell parameters_, cell literals_);
 
 	//code heap
 	inline void check_code_pointer(cell ptr)
@@ -505,17 +530,13 @@ struct factor_vm
 
 	void init_code_heap(cell size);
 	bool in_code_heap_p(cell ptr);
-	void jit_compile_word(cell word_, cell def_, bool relocate);
 	void update_code_heap_words();
-	void update_code_heap_words_and_literals();
-	void relocate_code_heap();
 	void primitive_modify_code_heap();
 	code_heap_room code_room();
 	void primitive_code_room();
 	void primitive_strip_stack_traces();
 
-	/* Apply a function to every code block */
-	template void iterate_code_heap(Iterator &iter)
+	template void each_code_block(Iterator &iter)
 	{
 		code->allocator->iterate(iter);
 	}
@@ -531,16 +552,8 @@ struct factor_vm
 	bool save_image(const vm_char *filename);
 	void primitive_save_image();
 	void primitive_save_image_and_exit();
-	void data_fixup(cell *handle, cell data_relocation_base);
-	template void code_fixup(Type **handle, cell code_relocation_base);
-	void fixup_word(word *word, cell code_relocation_base);
-	void fixup_quotation(quotation *quot, cell code_relocation_base);
-	void fixup_alien(alien *d);
-	void fixup_callstack_object(callstack *stack, cell code_relocation_base);
-	void relocate_object(object *object, cell data_relocation_base, cell code_relocation_base);
-	void relocate_data(cell data_relocation_base, cell code_relocation_base);
-	void fixup_code_block(code_block *compiled, cell data_relocation_base);
-	void relocate_code(cell data_relocation_base);
+	void fixup_data(cell data_offset, cell code_offset);
+	void fixup_code(cell data_offset, cell code_offset);
 	void load_image(vm_parameters *p);
 
 	//callstack
@@ -548,44 +561,25 @@ struct factor_vm
 	void check_frame(stack_frame *frame);
 	callstack *allot_callstack(cell size);
 	stack_frame *fix_callstack_top(stack_frame *top, stack_frame *bottom);
-	stack_frame *capture_start();
+	stack_frame *second_from_top_stack_frame();
 	void primitive_callstack();
-	void primitive_set_callstack();
 	code_block *frame_code(stack_frame *frame);
 	code_block_type frame_type(stack_frame *frame);
 	cell frame_executing(stack_frame *frame);
+	cell frame_executing_quot(stack_frame *frame);
 	stack_frame *frame_successor(stack_frame *frame);
 	cell frame_scan(stack_frame *frame);
 	void primitive_callstack_to_array();
 	stack_frame *innermost_stack_frame(callstack *stack);
-	stack_frame *innermost_stack_frame_quot(callstack *callstack);
 	void primitive_innermost_stack_frame_executing();
 	void primitive_innermost_stack_frame_scan();
 	void primitive_set_innermost_stack_frame_quot();
-	void save_callstack_bottom(stack_frame *callstack_bottom);
 	template void iterate_callstack(context *ctx, Iterator &iterator);
 
-	/* Every object has a regular representation in the runtime, which makes GC
-	much simpler. Every slot of the object until binary_payload_start is a pointer
-	to some other object. */
-	template void do_slots(cell obj, Iterator &iter)
-	{
-		cell scan = obj;
-		cell payload_start = ((object *)obj)->binary_payload_start();
-		cell end = obj + payload_start;
-
-		scan += sizeof(cell);
-
-		while(scan < end)
-		{
-			iter((cell *)scan);
-			scan += sizeof(cell);
-		}
-	}
-
 	//alien
 	char *pinned_alien_offset(cell obj);
 	cell allot_alien(cell delegate_, cell displacement);
+	cell allot_alien(void *address);
 	void primitive_displaced_alien();
 	void primitive_alien_address();
 	void *alien_pointer();
@@ -593,25 +587,26 @@ struct factor_vm
 	void primitive_dlsym();
 	void primitive_dlclose();
 	void primitive_dll_validp();
-	void primitive_vm_ptr();
 	char *alien_offset(cell obj);
-	char *unbox_alien();
-	void box_alien(void *ptr);
 	void to_value_struct(cell src, void *dest, cell size);
-	void box_value_struct(void *src, cell size);
-	void box_small_struct(cell x, cell y, cell size);
-	void box_medium_struct(cell x1, cell x2, cell x3, cell x4, cell size);
+	cell from_value_struct(void *src, cell size);
+	cell from_small_struct(cell x, cell y, cell size);
+	cell from_medium_struct(cell x1, cell x2, cell x3, cell x4, cell size);
 
 	//quotations
 	void primitive_jit_compile();
+	code_block *lazy_jit_compile_block();
 	void primitive_array_to_quotation();
-	void primitive_quotation_xt();
-	void set_quot_xt(quotation *quot, code_block *code);
-	void jit_compile(cell quot_, bool relocating);
-	void compile_all_words();
+	void primitive_quotation_code();
+	void set_quot_entry_point(quotation *quot, code_block *code);
+	code_block *jit_compile_quot(cell owner_, cell quot_, bool relocating);
+	void jit_compile_quot(cell quot_, bool relocating);
 	fixnum quot_code_offset_to_scan(cell quot_, cell offset);
-	cell lazy_jit_compile_impl(cell quot_, stack_frame *stack);
+	cell lazy_jit_compile(cell quot);
+	bool quot_compiled_p(quotation *quot);
 	void primitive_quot_compiled_p();
+	cell find_all_quotations();
+	void initialize_all_quotations();
 
 	//dispatch
 	cell search_lookup_alist(cell table, cell klass);
@@ -640,14 +635,19 @@ struct factor_vm
 	void update_pic_transitions(cell pic_size);
 	void *inline_cache_miss(cell return_address);
 
+	//entry points
+	void c_to_factor(cell quot);
+	void unwind_native_frames(cell quot, stack_frame *to);
+
 	//factor
 	void default_parameters(vm_parameters *p);
-	bool factor_arg(const vm_char* str, const vm_char* arg, cell* value);
+	bool factor_arg(const vm_char *str, const vm_char *arg, cell *value);
 	void init_parameters_from_args(vm_parameters *p, int argc, vm_char **argv);
-	void do_stage1_init();
+	void prepare_boot_image();
 	void init_factor(vm_parameters *p);
 	void pass_args_to_factor(int argc, vm_char **argv);
 	void start_factor(vm_parameters *p);
+	void stop_factor();
 	void start_embedded_factor(vm_parameters *p);
 	void start_standalone_factor(int argc, vm_char **argv);
 	char *factor_eval_string(char *string);
@@ -665,11 +665,10 @@ struct factor_vm
 
 	// os-windows
   #if defined(WINDOWS)
-	void sleep_micros(u64 usec);
 	const vm_char *vm_executable_path();
 	const vm_char *default_image_path();
 	void windows_image_path(vm_char *full_path, vm_char *temp_path, unsigned int length);
-	bool windows_stat(vm_char *path);
+	BOOL windows_stat(vm_char *path);
 
   #if defined(WINNT)
 	void open_console();
diff --git a/vm/words.cpp b/vm/words.cpp
index dfaeed2496..31041a6a19 100644
--- a/vm/words.cpp
+++ b/vm/words.cpp
@@ -3,6 +3,45 @@
 namespace factor
 {
 
+/* Compile a word definition with the non-optimizing compiler. Allocates memory */
+void factor_vm::jit_compile_word(cell word_, cell def_, bool relocating)
+{
+	data_root word(word_,this);
+	data_root def(def_,this);
+
+	/* Refuse to compile this word more than once, because quot_compiled_p()
+	depends on the identity of its code block */
+	if(word->code && word.value() == special_objects[LAZY_JIT_COMPILE_WORD])
+		return;
+
+	code_block *compiled = jit_compile_quot(word.value(),def.value(),relocating);
+	word->code = compiled;
+
+	if(to_boolean(word->pic_def)) jit_compile_quot(word->pic_def,relocating);
+	if(to_boolean(word->pic_tail_def)) jit_compile_quot(word->pic_tail_def,relocating);
+}
+
+cell factor_vm::find_all_words()
+{
+	return instances(WORD_TYPE);
+}
+
+void factor_vm::compile_all_words()
+{
+	data_root words(find_all_words(),this);
+
+	cell length = array_capacity(words.untagged());
+	for(cell i = 0; i < length; i++)
+	{
+		data_root word(array_nth(words.untagged(),i),this);
+
+		if(!word->code || !word->code->optimized_p())
+			jit_compile_word(word.value(),word->def,false);
+
+		update_word_entry_point(word.untagged());
+	}
+}
+
 word *factor_vm::allot_word(cell name_, cell vocab_, cell hashcode_)
 {
 	data_root vocab(vocab_,this);
@@ -23,10 +62,14 @@ word *factor_vm::allot_word(cell name_, cell vocab_, cell hashcode_)
 	new_word->code = NULL;
 
 	jit_compile_word(new_word.value(),new_word->def,true);
-	update_word_xt(new_word.untagged());
-
 	if(profiling_p)
-		relocate_code_block(new_word->profiling);
+	{
+		code_block *profiling_block = compile_profiling_stub(new_word.value());
+		new_word->profiling = profiling_block;
+		initialize_code_block(new_word->profiling);
+	}
+
+	update_word_entry_point(new_word.untagged());
 
 	return new_word.untagged();
 }
@@ -34,63 +77,49 @@ word *factor_vm::allot_word(cell name_, cell vocab_, cell hashcode_)
 /* (word) ( name vocabulary hashcode -- word ) */
 void factor_vm::primitive_word()
 {
-	cell hashcode = dpop();
-	cell vocab = dpop();
-	cell name = dpop();
-	dpush(tag(allot_word(name,vocab,hashcode)));
+	cell hashcode = ctx->pop();
+	cell vocab = ctx->pop();
+	cell name = ctx->pop();
+	ctx->push(tag(allot_word(name,vocab,hashcode)));
 }
 
-/* word-xt ( word -- start end ) */
-void factor_vm::primitive_word_xt()
+/* word-code ( word -- start end ) */
+void factor_vm::primitive_word_code()
 {
-	data_root w(dpop(),this);
+	data_root w(ctx->pop(),this);
 	w.untag_check(this);
 
 	if(profiling_p)
 	{
-		dpush(allot_cell((cell)w->profiling->xt()));
-		dpush(allot_cell((cell)w->profiling + w->profiling->size()));
+		ctx->push(allot_cell((cell)w->profiling->entry_point()));
+		ctx->push(allot_cell((cell)w->profiling + w->profiling->size()));
 	}
 	else
 	{
-		dpush(allot_cell((cell)w->code->xt()));
-		dpush(allot_cell((cell)w->code + w->code->size()));
+		ctx->push(allot_cell((cell)w->code->entry_point()));
+		ctx->push(allot_cell((cell)w->code + w->code->size()));
 	}
 }
 
-/* Allocates memory */
-void factor_vm::update_word_xt(word *w_)
+void factor_vm::update_word_entry_point(word *w)
 {
-	data_root w(w_,this);
-
-	if(profiling_p)
-	{
-		if(!w->profiling)
-		{
-			/* Note: can't do w->profiling = ... since LHS evaluates
-			before RHS, and if RHS does a GC, we will have an
-			invalid pointer on the LHS */
-			code_block *profiling = compile_profiling_stub(w.value());
-			w->profiling = profiling;
-		}
-
-		w->xt = w->profiling->xt();
-	}
+	if(profiling_p && w->profiling)
+		w->entry_point = w->profiling->entry_point();
 	else
-		w->xt = w->code->xt();
+		w->entry_point = w->code->entry_point();
 }
 
 void factor_vm::primitive_optimized_p()
 {
-	word *w = untag_check(dpeek());
-	drepl(tag_boolean(w->code->optimized_p()));
+	word *w = untag_check(ctx->peek());
+	ctx->replace(tag_boolean(w->code->optimized_p()));
 }
 
 void factor_vm::primitive_wrapper()
 {
 	wrapper *new_wrapper = allot(sizeof(wrapper));
-	new_wrapper->object = dpeek();
-	drepl(tag(new_wrapper));
+	new_wrapper->object = ctx->peek();
+	ctx->replace(tag(new_wrapper));
 }
 
 }