merge project-euler.factor

db4
Guillaume Nargeot 2009-10-12 17:08:50 +09:00
commit f97ede3d91
1377 changed files with 24146 additions and 15335 deletions

View File

@ -31,6 +31,7 @@ ifdef CONFIG
endif
DLL_OBJS = $(PLAF_DLL_OBJS) \
vm/aging_collector.o \
vm/alien.o \
vm/arrays.o \
vm/bignum.o \
@ -38,30 +39,33 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \
vm/byte_arrays.o \
vm/callstack.o \
vm/code_block.o \
vm/code_gc.o \
vm/code_heap.o \
vm/contexts.o \
vm/data_gc.o \
vm/data_heap.o \
vm/debug.o \
vm/dispatch.o \
vm/errors.o \
vm/factor.o \
vm/full_collector.o \
vm/gc.o \
vm/heap.o \
vm/image.o \
vm/inline_cache.o \
vm/io.o \
vm/jit.o \
vm/local_roots.o \
vm/math.o \
vm/nursery_collector.o \
vm/old_space.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/words.o \
vm/write_barrier.o
vm/vm.o \
vm/words.o
EXE_OBJS = $(PLAF_EXE_OBJS)

View File

@ -1,154 +0,0 @@
The Factor programming language
-------------------------------
This file covers installation and basic usage of the Factor
implementation. It is not an introduction to the language itself.
* Contents
- Compiling the Factor VM
- Libraries needed for compilation
- Bootstrapping the Factor image
- Running Factor on Unix with X11
- Running Factor on Mac OS X - Cocoa UI
- Running Factor on Mac OS X - X11 UI
- Running Factor on Windows
- Command line usage
- The Factor FAQ
- Source organization
- Community
* Compiling the Factor VM
Factor supports various platforms. For an up-to-date list, see
<http://factorcode.org>.
The Factor VM is written in C++ and uses GNU extensions. When compiling
with GCC 3.x, boost::unordered_map must be installed. On GCC 4.x, Factor
uses std::tr1::unordered_map which is shipped as part of GCC.
Run 'make' ('gmake' on *BSD) with no parameters to build the Factor VM.
* Bootstrapping the Factor image
Once you have compiled the Factor VM, you must bootstrap the Factor
system using the image that corresponds to your CPU architecture.
Boot images can be obtained from <http://factorcode.org/images/latest/>.
Once you download the right image, bootstrap Factor with the
following command line:
./factor -i=boot.<cpu>.image
Bootstrap can take a while, depending on your system. When the process
completes, a 'factor.image' file will be generated. Note that this image
is both CPU and OS-specific, so in general cannot be shared between
machines.
* Running Factor on Unix with X11
On Unix, Factor can either run a graphical user interface using X11, or
a terminal listener.
For X11 support, you need recent development libraries for libc,
Pango, X11, and OpenGL. On a Debian-derived Linux distribution
(like Ubuntu), you can use the following line to grab everything:
sudo apt-get install libc6-dev libpango1.0-dev libx11-dev libgl1-mesa-dev
Note that if you are using a proprietary OpenGL driver, you should
probably leave out the last package in the list.
If your DISPLAY environment variable is set, the UI will start
automatically when you run Factor:
./factor
To run an interactive terminal listener:
./factor -run=listener
* Running Factor on Mac OS X - Cocoa UI
On Mac OS X, a Cocoa UI is available in addition to the terminal
listener.
The 'factor' executable runs the terminal listener:
./factor
The 'Factor.app' bundle runs the Cocoa UI. Note that this is not a
self-contained bundle, it must be run from the same directory which
contains factor.image and the library sources.
* Running Factor on Mac OS X - X11 UI
The X11 UI is also available on Mac OS X, however its use is not
recommended since it does not integrate with the host OS.
When compiling Factor, pass the X11=1 parameter:
make X11=1
Then bootstrap with the following switches:
./factor -i=boot.<cpu>.image -ui-backend=x11
Now if $DISPLAY is set, running ./factor will start the UI.
* Running Factor on Windows XP/Vista
The Factor runtime is compiled into two binaries:
factor.com - a Windows console application
factor.exe - a Windows native application, without a console
If you did not download the binary package, you can bootstrap Factor in
the command prompt using the console application:
factor.com -i=boot.<cpu>.image
Once bootstrapped, double-clicking factor.exe or factor.com starts
the Factor UI.
To run the listener in the command prompt:
factor.com -run=listener
* The Factor FAQ
The Factor FAQ is available at the following location:
<http://concatenative.org/wiki/view/Factor/FAQ>
* Command line usage
Factor supports a number of command line switches. To read command line
usage documentation, enter the following in the UI listener:
"command-line" about
* Source organization
The Factor source tree is organized as follows:
build-support/ - scripts used for compiling Factor
vm/ - Factor VM
core/ - Factor core library
basis/ - Factor basis library, compiler, tools
extra/ - more libraries and applications
misc/ - editor modes, icons, etc
unmaintained/ - unmaintained contributions, please help!
* Community
The Factor homepage is located at <http://factorcode.org/>.
Factor developers meet in the #concatenative channel on the
irc.freenode.net server. Drop by if you want to discuss anything related
to Factor or language design in general.
Have fun!
:tabSize=2:indentSize=2:noTabs=true:

View File

@ -24,10 +24,12 @@ HELP: every
ARTICLE: "alarms" "Alarms"
"The " { $vocab-link "alarms" } " vocabulary provides a lightweight way to schedule one-time and recurring tasks without spawning a new thread."
{ $subsection alarm }
{ $subsection add-alarm }
{ $subsection later }
{ $subsection cancel-alarm }
{ $subsections
alarm
add-alarm
later
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"

View File

@ -1,12 +0,0 @@
USING: help.syntax help.markup byte-arrays alien.c-types alien.data ;
IN: alien.arrays
ARTICLE: "c-arrays" "C arrays"
"C arrays are allocated in the same manner as other C data; see " { $link "c-byte-arrays" } " and " { $link "malloc" } "."
$nl
"C type specifiers for array types are documented in " { $link "c-types-specs" } "."
$nl
"Specialized sequences are provided for accessing memory as an array of primitive type values. These sequences are implemented in the " { $vocab-link "specialized-arrays" } " vocabulary set. They can also be loaded and constructed through their primitive C types:"
{ $subsection require-c-array }
{ $subsection <c-array> }
{ $subsection <c-direct-array> } ;

View File

@ -3,6 +3,7 @@ byte-arrays strings hashtables alien.syntax alien.strings sequences
io.encodings.string debugger destructors vocabs.loader
classes.struct ;
QUALIFIED: math
QUALIFIED: sequences
IN: alien.c-types
HELP: byte-length
@ -10,25 +11,24 @@ HELP: byte-length
{ $contract "Outputs the size of the byte array, struct, or specialized array data in bytes." } ;
HELP: heap-size
{ $values { "type" string } { "size" math:integer } }
{ $values { "name" "a C type name" } { "size" math:integer } }
{ $description "Outputs the number of bytes needed for a heap-allocated value of this C type." }
{ $examples
"On a 32-bit system, you will get the following output:"
{ $unchecked-example "USE: alien\n\"void*\" heap-size ." "4" }
{ $example "USING: alien alien.c-types prettyprint ;\nint heap-size ." "4" }
}
{ $errors "Throws a " { $link no-c-type } " error if the type does not exist." } ;
HELP: stack-size
{ $values { "type" string } { "size" math:integer } }
{ $values { "name" "a C type name" } { "size" math:integer } }
{ $description "Outputs the number of bytes to reserve on the C stack by a value of this C type. In most cases this is equal to " { $link heap-size } ", except on some platforms where C structs are passed by invisible reference, in which case a C struct type only uses as much space as a pointer on the C stack." }
{ $errors "Throws a " { $link no-c-type } " error if the type does not exist." } ;
HELP: <c-type>
{ $values { "type" hashtable } }
{ $values { "c-type" c-type } }
{ $description "Creates a prototypical C type. User code should use higher-level facilities to define C types; see " { $link "c-data" } "." } ;
HELP: no-c-type
{ $values { "type" string } }
{ $values { "name" "a C type name" } }
{ $description "Throws a " { $link no-c-type } " error." }
{ $error-description "Thrown by " { $link c-type } " if a given string does not name a C type. When thrown during compile time, indicates a typo in an " { $link alien-invoke } " or " { $link alien-callback } " form." } ;
@ -36,32 +36,32 @@ HELP: c-types
{ $var-description "Global variable holding a hashtable mapping C type names to C types. Use the " { $link c-type } " word to look up C types." } ;
HELP: c-type
{ $values { "name" string } { "type" hashtable } }
{ $values { "name" "a C type" } { "c-type" c-type } }
{ $description "Looks up a C type by name." }
{ $errors "Throws a " { $link no-c-type } " error if the type does not exist." } ;
HELP: c-getter
{ $values { "name" string } { "quot" { $quotation "( c-ptr n -- obj )" } } }
{ $values { "name" "a C type" } { "quot" { $quotation "( c-ptr n -- obj )" } } }
{ $description "Outputs a quotation which reads values of this C type from a C structure." }
{ $errors "Throws a " { $link no-c-type } " error if the type does not exist." } ;
HELP: c-setter
{ $values { "name" string } { "quot" { $quotation "( obj c-ptr n -- )" } } }
{ $values { "name" "a C type" } { "quot" { $quotation "( obj c-ptr n -- )" } } }
{ $description "Outputs a quotation which writes values of this C type to a C structure." }
{ $errors "Throws an error if the type does not exist." } ;
HELP: box-parameter
{ $values { "n" math:integer } { "ctype" string } }
{ $values { "n" math:integer } { "c-type" "a C type" } }
{ $description "Generates code for converting a C value stored at offset " { $snippet "n" } " from the top of the stack into a Factor object to be pushed on the data stack." }
{ $notes "This is an internal word used by the compiler when compiling callbacks." } ;
HELP: box-return
{ $values { "ctype" string } }
{ $values { "c-type" "a C type" } }
{ $description "Generates code for converting a C value stored in return registers into a Factor object to be pushed on the data stack." }
{ $notes "This is an internal word used by the compiler when compiling alien calls." } ;
HELP: unbox-return
{ $values { "ctype" string } }
{ $values { "c-type" "a C type" } }
{ $description "Generates code for converting a Factor value on the data stack into a C value to be stored in the return registers." }
{ $notes "This is an internal word used by the compiler when compiling callbacks." } ;
@ -89,16 +89,24 @@ HELP: uint
{ $description "This C type represents a four-byte unsigned integer type. Input values will be converted to " { $link math:integer } "s and truncated to 32 bits; output values will be returned as " { $link math:integer } "s." } ;
HELP: long
{ $description "This C type represents a four- or eight-byte signed integer type. On Windows and on 32-bit Unix platforms, it will be four bytes. On 64-bit Unix platforms, it will be eight bytes. Input values will be converted to " { $link math:integer } "s and truncated to 32 or 64 bits; output values will be returned as " { $link math:integer } "s." } ;
HELP: intptr_t
{ $description "This C type represents a signed integer type large enough to hold any pointer value; that is, on 32-bit platforms, it will be four bytes, and on 64-bit platforms, it will be eight bytes. Input values will be converted to " { $link math:integer } "s and truncated to 32 or 64 bits; output values will be returned as " { $link math:integer } "s." } ;
HELP: ulong
{ $description "This C type represents a four- or eight-byte unsigned integer type. On Windows and on 32-bit Unix platforms, it will be four bytes. On 64-bit Unix platforms, it will be eight bytes. Input values will be converted to " { $link math:integer } "s and truncated to 32 or 64 bits; output values will be returned as " { $link math:integer } "s." } ;
HELP: uintptr_t
{ $description "This C type represents an unsigned integer type large enough to hold any pointer value; that is, on 32-bit platforms, it will be four bytes, and on 64-bit platforms, it will be eight bytes. Input values will be converted to " { $link math:integer } "s and truncated to 32 or 64 bits; output values will be returned as " { $link math:integer } "s." } ;
HELP: ptrdiff_t
{ $description "This C type represents a signed integer type large enough to hold the distance between two pointer values; that is, on 32-bit platforms, it will be four bytes, and on 64-bit platforms, it will be eight bytes. Input values will be converted to " { $link math:integer } "s and truncated to 32 or 64 bits; output values will be returned as " { $link math:integer } "s." } ;
HELP: size_t
{ $description "This C type represents unsigned size values of the size expected by the platform's standard C library (usually four bytes on a 32-bit platform, and eight on a 64-bit platform). Input values will be converted to " { $link math:integer } "s and truncated to the appropriate size; output values will be returned as " { $link math:integer } "s." } ;
HELP: longlong
{ $description "This C type represents an eight-byte signed integer type. Input values will be converted to " { $link math:integer } "s and truncated to 64 bits; output values will be returned as " { $link math:integer } "s." } ;
HELP: ulonglong
{ $description "This C type represents an eight-byte unsigned integer type. Input values will be converted to " { $link math:integer } "s and truncated to 64 bits; output values will be returned as " { $link math:integer } "s." } ;
HELP: void
{ $description "This symbol is not a valid C type, but it can be used as the return type for a " { $link POSTPONE: FUNCTION: } " or " { $link POSTPONE: CALLBACK: } " definition, or an " { $link alien-invoke } " or " { $link alien-callback } " call." } ;
{ $description "This symbol is not a valid C type, but it can be used as the return type for a " { $link POSTPONE: FUNCTION: } " or " { $link POSTPONE: CALLBACK: } " definition or for an " { $link alien-invoke } " or " { $link alien-callback } " call." } ;
HELP: void*
{ $description "This C type represents a pointer to C memory. " { $link byte-array } " and " { $link alien } " values can be passed as inputs, but see " { $link "byte-arrays-gc" } " for notes about passing byte arrays into C functions. Output values are returned as " { $link alien } "s." } ;
{ $description "This C type represents a pointer to C memory. " { $link byte-array } " and " { $link alien } " values can be passed as " { $snippet "void*" } " function inputs, but see " { $link "byte-arrays-gc" } " for notes about passing byte arrays into C functions. " { $snippet "void*" } " output values are returned as " { $link alien } "s." } ;
HELP: char*
{ $description "This C type represents a pointer to a C string. See " { $link "c-strings" } " for details about using strings with the FFI." } ;
HELP: float
@ -128,39 +136,41 @@ ARTICLE: "c-out-params" "Output parameters in C"
"A frequently-occurring idiom in C code is the \"out parameter\". If a C function returns more than one value, the caller passes pointers of the correct type, and the C function writes its return values to those locations."
$nl
"Each numerical C type, together with " { $snippet "void*" } ", has an associated " { $emphasis "out parameter constructor" } " word which takes a Factor object as input, constructs a byte array of the correct size, and converts the Factor object to a C value stored into the byte array:"
{ $subsection <char> }
{ $subsection <uchar> }
{ $subsection <short> }
{ $subsection <ushort> }
{ $subsection <int> }
{ $subsection <uint> }
{ $subsection <long> }
{ $subsection <ulong> }
{ $subsection <longlong> }
{ $subsection <ulonglong> }
{ $subsection <float> }
{ $subsection <double> }
{ $subsection <void*> }
{ $subsections
<char>
<uchar>
<short>
<ushort>
<int>
<uint>
<long>
<ulong>
<longlong>
<ulonglong>
<float>
<double>
<void*>
}
"You call the out parameter constructor with the required initial value, then pass the byte array to the C function, which receives a pointer to the start of the byte array's data area. The C function then returns, leaving the result in the byte array; you read it back using the next set of words:"
{ $subsection *char }
{ $subsection *uchar }
{ $subsection *short }
{ $subsection *ushort }
{ $subsection *int }
{ $subsection *uint }
{ $subsection *long }
{ $subsection *ulong }
{ $subsection *longlong }
{ $subsection *ulonglong }
{ $subsection *float }
{ $subsection *double }
{ $subsection *void* }
{ $subsections
*char
*uchar
*short
*ushort
*int
*uint
*long
*ulong
*longlong
*ulonglong
*float
*double
*void*
}
"Note that while structure and union types do not get these words defined for them, there is no loss of generality since " { $link <void*> } " and " { $link *void* } " may be used." ;
ARTICLE: "c-types-specs" "C type specifiers"
"C types are identified by special words, and type names occur as parameters to the " { $link alien-invoke } ", " { $link alien-indirect } " and " { $link alien-callback } " words. New C types can be defined by the words " { $link POSTPONE: STRUCT: } ", " { $link POSTPONE: UNION-STRUCT: } ", " { $link POSTPONE: CALLBACK: } ", and " { $link POSTPONE: TYPEDEF: } "."
$nl
"The following numerical types are available; a " { $snippet "u" } " prefix denotes an unsigned type:"
ARTICLE: "c-types.primitives" "Primitive C types"
"The following numerical types are defined in the " { $vocab-link "alien.c-types" } " vocabulary; a " { $snippet "u" } " prefix denotes an unsigned type:"
{ $table
{ "C type" "Notes" }
{ { $link char } "always 1 byte" }
@ -175,15 +185,68 @@ $nl
{ { $link ulonglong } { } }
{ { $link float } { "single-precision float (not the same as Factor's " { $link math:float } " class!)" } }
{ { $link double } { "double-precision float (the same format as Factor's " { $link math:float } " objects)" } }
}
"The following C99 complex number types are defined in the " { $vocab-link "alien.complex" } " vocabulary:"
{ $table
{ { $link complex-float } { "C99 or Fortran " { $snippet "complex float" } " type, converted to and from Factor " { $link math:complex } " values" } }
{ { $link complex-double } { "C99 or Fortran " { $snippet "complex double" } " type, converted to and from Factor " { $link math:complex } " values" } }
}
"When making alien calls, Factor numbers are converted to and from the above types in a canonical way. Converting a Factor number to a C value may result in a loss of precision."
$nl
"When making alien calls, Factor numbers are converted to and from the above types in a canonical way. Converting a Factor number to a C value may result in a loss of precision." ;
ARTICLE: "c-types.pointers" "Pointer and array types"
"Pointer types are specified by suffixing a C type with " { $snippet "*" } ", for example " { $snippet "float*" } ". One special case is " { $link void* } ", which denotes a generic pointer; " { $link void } " by itself is not a valid C type specifier. With the exception of strings (see " { $link "c-strings" } "), all pointer types are identical to " { $snippet "void*" } " as far as the C library interface is concerned."
$nl
"Fixed-size array types are supported; the syntax consists of a C type name followed by dimension sizes in brackets; the following denotes a 3 by 4 array of integers:"
{ $code "int[3][4]" }
"Fixed-size arrays differ from pointers in that they are allocated inside structures and unions; however when used as function parameters they behave exactly like pointers and thus the dimensions only serve as documentation."
"Fixed-size arrays differ from pointers in that they are allocated inside structures and unions; however when used as function parameters they behave exactly like pointers and thus the dimensions only serve as documentation." ;
ARTICLE: "c-types.ambiguity" "Word name clashes with C types"
"Note that some of the C type word names clash with commonly-used Factor words:"
{ $list
{ { $link short } " clashes with the " { $link sequences:short } " word in the " { $vocab-link "sequences" } " vocabulary" }
{ { $link float } " clashes with the " { $link math:float } " word in the " { $vocab-link "math" } " vocabulary" }
}
"If you use the wrong vocabulary, you will see a " { $link no-c-type } " error. For example, the following is " { $strong "not" } " valid, and will raise an error because the " { $link math:float } " word from the " { $vocab-link "math" } " vocabulary is not a C type:"
{ $code
"USING: alien.syntax math prettyprint ;"
"FUNCTION: float magic_number ( ) ;"
"magic_number 3.0 + ."
}
"The following won't work either; now the problem is that there are two vocabularies in the search path that define a word named " { $snippet "float" } ":"
{ $code
"USING: alien.c-types alien.syntax math prettyprint ;"
"FUNCTION: float magic_number ( ) ;"
"magic_number 3.0 + ."
}
"The correct solution is to use one of " { $link POSTPONE: FROM: } ", " { $link POSTPONE: QUALIFIED: } " or " { $link POSTPONE: QUALIFIED-WITH: } " to disambiguate word lookup:"
{ $code
"USING: alien.syntax math prettyprint ;"
"QUALIFIED-WITH: alien.c-types c"
"FUNCTION: c:float magic_number ( ) ;"
"magic_number 3.0 + ."
}
"See " { $link "word-search-semantics" } " for details." ;
ARTICLE: "c-types.structs" "Struct and union types"
"Struct and union types are identified by their class word. See " { $link "classes.struct" } "." ;
ARTICLE: "c-types-specs" "C type specifiers"
"C types are identified by special words, and type names occur as parameters to the " { $link alien-invoke } ", " { $link alien-indirect } " and " { $link alien-callback } " words."
$nl
"Structure and union types are specified by the name of the structure or union." ;
"Defining new C types:"
{ $subsections
POSTPONE: STRUCT:
POSTPONE: UNION-STRUCT:
POSTPONE: CALLBACK:
POSTPONE: TYPEDEF:
}
{ $heading "Related articles" }
{ $subsections
"c-types.primitives"
"c-types.pointers"
"c-types.ambiguity"
"c-types.structs"
}
;
ABOUT: "c-types-specs"

86
basis/alien/c-types/c-types-tests.factor Normal file → Executable file
View File

@ -1,49 +1,50 @@
USING: alien alien.syntax alien.c-types kernel tools.test
sequences system libc alien.strings io.encodings.utf8 ;
USING: alien alien.syntax alien.c-types alien.parser
eval kernel tools.test sequences system libc alien.strings
io.encodings.utf8 math.constants classes.struct classes ;
IN: alien.c-types.tests
CONSTANT: xyz 123
[ 492 ] [ { "int" xyz } heap-size ] unit-test
[ 492 ] [ { int xyz } heap-size ] unit-test
[ -1 ] [ -1 <char> *char ] unit-test
[ -1 ] [ -1 <short> *short ] unit-test
[ -1 ] [ -1 <int> *int ] unit-test
C-UNION: foo
"int"
"int" ;
UNION-STRUCT: foo
{ a int }
{ b int } ;
[ f ] [ "char*" c-type "void*" c-type eq? ] unit-test
[ t ] [ "char**" c-type "void*" c-type eq? ] unit-test
[ f ] [ char resolve-pointer-type c-type void* c-type eq? ] unit-test
[ t ] [ char* resolve-pointer-type c-type void* c-type eq? ] unit-test
[ t ] [ "foo" heap-size "int" heap-size = ] unit-test
[ t ] [ foo heap-size int heap-size = ] unit-test
TYPEDEF: int MyInt
[ t ] [ "int" c-type "MyInt" c-type eq? ] unit-test
[ t ] [ "void*" c-type "MyInt*" c-type eq? ] unit-test
[ t ] [ int c-type MyInt c-type eq? ] unit-test
[ t ] [ void* c-type MyInt resolve-pointer-type c-type eq? ] unit-test
TYPEDEF: char MyChar
[ t ] [ "char" c-type "MyChar" c-type eq? ] unit-test
[ f ] [ "void*" c-type "MyChar*" c-type eq? ] unit-test
[ t ] [ "char*" c-type "MyChar*" c-type eq? ] unit-test
[ t ] [ char c-type MyChar c-type eq? ] unit-test
[ f ] [ void* c-type MyChar resolve-pointer-type c-type eq? ] unit-test
[ t ] [ char* c-type MyChar resolve-pointer-type c-type eq? ] unit-test
[ 32 ] [ { "int" 8 } heap-size ] unit-test
[ 32 ] [ { int 8 } heap-size ] unit-test
TYPEDEF: char* MyString
[ t ] [ "char*" c-type "MyString" c-type eq? ] unit-test
[ t ] [ "void*" c-type "MyString*" c-type eq? ] unit-test
[ t ] [ char* c-type MyString c-type eq? ] unit-test
[ t ] [ void* c-type MyString resolve-pointer-type c-type eq? ] unit-test
TYPEDEF: int* MyIntArray
[ t ] [ "void*" c-type "MyIntArray" c-type eq? ] unit-test
[ t ] [ void* c-type MyIntArray c-type eq? ] unit-test
TYPEDEF: uchar* MyLPBYTE
[ t ] [ { char* utf8 } c-type "MyLPBYTE" c-type = ] unit-test
[ t ] [ { char* utf8 } c-type MyLPBYTE c-type = ] unit-test
[
0 B{ 1 2 3 4 } <displaced-alien> <void*>
@ -52,3 +53,50 @@ TYPEDEF: uchar* MyLPBYTE
os windows? cpu x86.64? and [
[ -2147467259 ] [ 2147500037 <long> *long ] unit-test
] when
[ 0 ] [ -10 uchar c-type-clamp ] unit-test
[ 12 ] [ 12 uchar c-type-clamp ] unit-test
[ -10 ] [ -10 char c-type-clamp ] unit-test
[ 127 ] [ 230 char c-type-clamp ] unit-test
[ t ] [ pi dup float c-type-clamp = ] unit-test
C-TYPE: opaque
[ t ] [ void* c-type opaque resolve-pointer-type c-type eq? ] unit-test
[ opaque c-type ] [ no-c-type? ] must-fail-with
[ """
USING: alien.syntax ;
IN: alien.c-types.tests
FUNCTION: opaque return_opaque ( ) ;
""" eval( -- ) ] [ no-c-type? ] must-fail-with
C-TYPE: forward
STRUCT: backward { x forward* } ;
STRUCT: forward { x backward* } ;
[ t ] [ forward c-type struct-c-type? ] unit-test
[ t ] [ backward c-type struct-c-type? ] unit-test
DEFER: struct-redefined
[ f ]
[
"""
USING: alien.c-types classes.struct ;
IN: alien.c-types.tests
STRUCT: struct-redefined { x int } ;
""" eval( -- )
"""
USING: alien.syntax ;
IN: alien.c-types.tests
C-TYPE: struct-redefined
""" eval( -- )
\ struct-redefined class?
] unit-test

View File

@ -1,11 +1,12 @@
! Copyright (C) 2004, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: byte-arrays arrays assocs kernel kernel.private math
namespaces make parser sequences strings words splitting math.parser
cpu.architecture alien alien.accessors alien.strings quotations
layouts system compiler.units io io.files io.encodings.binary
io.streams.memory accessors combinators effects continuations fry
classes vocabs vocabs.loader words.symbol ;
math.order math.parser namespaces make parser sequences strings
words splitting cpu.architecture alien alien.accessors
alien.strings quotations layouts system compiler.units io
io.files io.encodings.binary io.streams.memory accessors
combinators effects continuations fry classes vocabs
vocabs.loader words.symbol ;
QUALIFIED: math
IN: alien.c-types
@ -38,8 +39,8 @@ unboxer
{ rep initial: int-rep }
stack-align? ;
: <c-type> ( -- type )
\ c-type new ;
: <c-type> ( -- c-type )
\ c-type new ; inline
SYMBOL: c-types
@ -55,13 +56,19 @@ PREDICATE: c-type-word < word
UNION: c-type-name string c-type-word ;
! C type protocol
GENERIC: c-type ( name -- type ) foldable
GENERIC: c-type ( name -- c-type ) foldable
GENERIC: resolve-pointer-type ( name -- c-type )
<< \ void \ void* "pointer-c-type" set-word-prop >>
: void? ( c-type -- ? )
{ void "void" } member? ;
M: word resolve-pointer-type
dup "pointer-c-type" word-prop
[ ] [ drop void* ] ?if ;
M: string resolve-pointer-type
dup "*" append dup c-types get at
[ nip ] [
@ -70,14 +77,15 @@ M: string resolve-pointer-type
[ resolve-pointer-type ] [ drop void* ] if
] if ;
: resolve-typedef ( name -- type )
: resolve-typedef ( name -- c-type )
dup void? [ no-c-type ] when
dup c-type-name? [ c-type ] when ;
: parse-array-type ( name -- dims type )
: parse-array-type ( name -- dims c-type )
"[" split unclip
[ [ "]" ?tail drop string>number ] map ] dip ;
M: string c-type ( name -- type )
M: string c-type ( name -- c-type )
CHAR: ] over member? [
parse-array-type prefix
] [
@ -87,12 +95,10 @@ M: string c-type ( name -- type )
] if ;
M: word c-type
"c-type" word-prop resolve-typedef ;
dup "c-type" word-prop resolve-typedef
[ ] [ no-c-type ] ?if ;
: void? ( c-type -- ? )
{ void "void" } member? ;
GENERIC: c-struct? ( type -- ? )
GENERIC: c-struct? ( c-type -- ? )
M: object c-struct?
drop f ;
@ -168,33 +174,33 @@ M: c-type c-type-stack-align? stack-align?>> ;
M: c-type-name c-type-stack-align? c-type c-type-stack-align? ;
: c-type-box ( n type -- )
: c-type-box ( n c-type -- )
[ c-type-rep ] [ c-type-boxer [ "No boxer" throw ] unless* ] bi
%box ;
: c-type-unbox ( n ctype -- )
: c-type-unbox ( n c-type -- )
[ c-type-rep ] [ c-type-unboxer [ "No unboxer" throw ] unless* ] bi
%unbox ;
GENERIC: box-parameter ( n ctype -- )
GENERIC: box-parameter ( n c-type -- )
M: c-type box-parameter c-type-box ;
M: c-type-name box-parameter c-type box-parameter ;
GENERIC: box-return ( ctype -- )
GENERIC: box-return ( c-type -- )
M: c-type box-return f swap c-type-box ;
M: c-type-name box-return c-type box-return ;
GENERIC: unbox-parameter ( n ctype -- )
GENERIC: unbox-parameter ( n c-type -- )
M: c-type unbox-parameter c-type-unbox ;
M: c-type-name unbox-parameter c-type unbox-parameter ;
GENERIC: unbox-return ( ctype -- )
GENERIC: unbox-return ( c-type -- )
M: c-type unbox-return f swap c-type-unbox ;
@ -202,13 +208,13 @@ M: c-type-name unbox-return c-type unbox-return ;
: little-endian? ( -- ? ) 1 <int> *char 1 = ; foldable
GENERIC: heap-size ( type -- size ) foldable
GENERIC: heap-size ( name -- size ) foldable
M: c-type-name heap-size c-type heap-size ;
M: abstract-c-type heap-size size>> ;
GENERIC: stack-size ( type -- size ) foldable
GENERIC: stack-size ( name -- size ) foldable
M: c-type-name stack-size c-type stack-size ;
@ -235,7 +241,7 @@ MIXIN: value-type
[ "Cannot write struct fields with this type" throw ]
] unless* ;
: array-accessor ( type quot -- def )
: array-accessor ( c-type quot -- def )
[
\ swap , [ heap-size , [ * >fixnum ] % ] [ % ] bi*
] [ ] make ;
@ -261,19 +267,19 @@ M: word typedef ( old new -- )
TUPLE: long-long-type < c-type ;
: <long-long-type> ( -- type )
: <long-long-type> ( -- c-type )
long-long-type new ;
M: long-long-type unbox-parameter ( n type -- )
M: long-long-type unbox-parameter ( n c-type -- )
c-type-unboxer %unbox-long-long ;
M: long-long-type unbox-return ( type -- )
M: long-long-type unbox-return ( c-type -- )
f swap unbox-parameter ;
M: long-long-type box-parameter ( n type -- )
M: long-long-type box-parameter ( n c-type -- )
c-type-boxer %box-long-long ;
M: long-long-type box-return ( type -- )
M: long-long-type box-return ( c-type -- )
f swap box-parameter ;
: define-deref ( name -- )
@ -285,13 +291,13 @@ M: long-long-type box-return ( type -- )
[ dup c-setter '[ _ heap-size <byte-array> [ 0 @ ] keep ] ] bi
(( value -- c-ptr )) define-inline ;
: define-primitive-type ( type name -- )
: define-primitive-type ( c-type name -- )
[ typedef ]
[ name>> define-deref ]
[ name>> define-out ]
tri ;
: if-void ( type true false -- )
: if-void ( c-type true false -- )
pick void? [ drop nip call ] [ nip call ] if ; inline
CONSTANT: primitive-types
@ -306,7 +312,7 @@ CONSTANT: primitive-types
}
SYMBOLS:
ptrdiff_t intptr_t size_t
ptrdiff_t intptr_t uintptr_t size_t
char* uchar* ;
[
@ -467,8 +473,33 @@ SYMBOLS:
[ >float ] >>unboxer-quot
\ double define-primitive-type
\ long \ ptrdiff_t typedef
\ long \ intptr_t typedef
\ ulong \ size_t typedef
\ long c-type \ ptrdiff_t typedef
\ long c-type \ intptr_t typedef
\ ulong c-type \ uintptr_t typedef
\ ulong c-type \ size_t typedef
] with-compilation-unit
M: char-16-rep rep-component-type drop char ;
M: uchar-16-rep rep-component-type drop uchar ;
M: short-8-rep rep-component-type drop short ;
M: ushort-8-rep rep-component-type drop ushort ;
M: int-4-rep rep-component-type drop int ;
M: uint-4-rep rep-component-type drop uint ;
M: longlong-2-rep rep-component-type drop longlong ;
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 ;
: (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
: signed-interval ( c-type -- from to ) heap-size (signed-interval) ; foldable
: c-type-interval ( c-type -- from to )
{
{ [ dup { float double } memq? ] [ drop -1/0. 1/0. ] }
{ [ dup { char short int long longlong } memq? ] [ signed-interval ] }
{ [ dup { uchar ushort uint ulong ulonglong } memq? ] [ unsigned-interval ] }
} cond ; foldable
: c-type-clamp ( value c-type -- value' ) c-type-interval clamp ; inline

View File

@ -16,6 +16,6 @@ STRUCT: complex-holder
[ C{ 1.0 2.0 } ] [ "h" get z>> ] unit-test
[ number ] [ "complex-float" c-type-boxed-class ] unit-test
[ complex ] [ "complex-float" c-type-boxed-class ] unit-test
[ number ] [ "complex-double" c-type-boxed-class ] unit-test
[ complex ] [ "complex-double" c-type-boxed-class ] unit-test

View File

@ -25,7 +25,7 @@ STRUCT: T-class { real N } { imaginary N } ;
T-class c-type
<T> 1quotation >>unboxer-quot
*T 1quotation >>boxer-quot
number >>boxed-class
complex >>boxed-class
drop
;FUNCTOR

View File

@ -1,6 +1,7 @@
USING: alien alien.c-types help.syntax help.markup libc kernel.private
byte-arrays math strings hashtables alien.syntax alien.strings sequences
io.encodings.string debugger destructors vocabs.loader ;
USING: alien alien.c-types help.syntax help.markup libc
kernel.private byte-arrays math strings hashtables alien.syntax
alien.strings sequences io.encodings.string debugger destructors
vocabs.loader classes.struct ;
IN: alien.data
HELP: <c-array>
@ -26,7 +27,7 @@ HELP: byte-array>memory
{ $warning "This word is unsafe. Improper use can corrupt memory." } ;
HELP: malloc-array
{ $values { "n" "a non-negative integer" } { "type" "a C type" } { "alien" alien } }
{ $values { "n" "a non-negative integer" } { "type" "a C type" } { "array" "a specialized array" } }
{ $description "Allocates an unmanaged memory block large enough to hold " { $snippet "n" } " values of a C type, then wraps the memory in a sequence object using " { $link <c-direct-array> } "." }
{ $notes "The appropriate specialized array vocabulary must be loaded; otherwise, an error will be thrown. The vocabulary can be loaded with the " { $link require-c-array } " word. See the " { $vocab-link "specialized-arrays" } " vocabulary for details on the underlying sequence type constructed." }
{ $warning "Don't forget to deallocate the memory with a call to " { $link free } "." }
@ -52,60 +53,70 @@ ARTICLE: "malloc" "Manual memory management"
"Sometimes data passed to C functions must be allocated at a fixed address. See " { $link "byte-arrays-gc" } " for an explanation of when this is the case."
$nl
"Allocating a C datum with a fixed address:"
{ $subsection malloc-object }
{ $subsection malloc-array }
{ $subsection malloc-byte-array }
"There is a set of words in the " { $vocab-link "libc" } " vocabulary which directly call C standard library memory management functions:"
{ $subsection malloc }
{ $subsection calloc }
{ $subsection realloc }
{ $subsections
malloc-object
malloc-byte-array
}
"The " { $vocab-link "libc" } " vocabulary defines several words which directly call C standard library memory management functions:"
{ $subsections
malloc
calloc
realloc
}
"You must always free pointers returned by any of the above words when the block of memory is no longer in use:"
{ $subsection free }
{ $subsections free }
"Utilities for automatically freeing memory in conjunction with " { $link with-destructors } ":"
{ $subsection &free }
{ $subsection |free }
{ $subsections
&free
|free
}
"The " { $link &free } " and " { $link |free } " words are generated using " { $link "alien.destructors" } "."
$nl
"You can unsafely copy a range of bytes from one memory location to another:"
{ $subsection memcpy }
{ $subsections memcpy }
"You can copy a range of bytes from memory into a byte array:"
{ $subsection memory>byte-array }
{ $subsections memory>byte-array }
"You can copy a byte array to memory unsafely:"
{ $subsection byte-array>memory } ;
{ $subsections byte-array>memory } ;
ARTICLE: "c-byte-arrays" "Passing data in byte arrays"
"Instances of the " { $link byte-array } " class can be passed to C functions; the C function receives a pointer to the first element of the array."
$nl
"Byte arrays can be allocated directly with a byte count using the " { $link <byte-array> } " word. However in most cases, instead of computing a size in bytes directly, it is easier to use a higher-level word which expects C type and outputs a byte array large enough to hold that type:"
{ $subsection <c-object> }
{ $subsection <c-array> }
ARTICLE: "c-pointers" "Passing pointers to C functions"
"The following Factor objects may be passed to C function parameters with pointer types:"
{ $list
{ "Instances of " { $link alien } "." }
{ "Instances of " { $link f } "; this is interpreted as a null pointer." }
{ "Instances of " { $link byte-array } "; the C function receives a pointer to the first element of the array." }
{ "Any data type which defines a method on " { $link >c-ptr } " that returns an instance of one of the above. This includes " { $link "classes.struct" } " and " { $link "specialized-arrays" } "." }
}
"The class of primitive C pointer types:"
{ $subsections c-ptr }
"A generic word for converting any object to a C pointer; user-defined types may add methods to this generic word:"
{ $subsections >c-ptr }
"More about the " { $link alien } " type:"
{ $subsections "aliens" }
{ $warning
"The Factor garbage collector can move byte arrays around, and code passing byte arrays to C must obey important guidelines. See " { $link "byte-arrays-gc" } "." }
{ $see-also "c-arrays" } ;
"The Factor garbage collector can move byte arrays around, and code passing byte arrays, or objects backed by byte arrays, must obey important guidelines. See " { $link "byte-arrays-gc" } "." } ;
ARTICLE: "c-data" "Passing data between Factor and C"
"Two defining characteristics of Factor are dynamic typing and automatic memory management, which are somewhat incompatible with the machine-level data model exposed by C. Factor's C library interface defines its own set of C data types, distinct from Factor language types, together with automatic conversion between Factor values and C types. For example, C integer types must be declared and are fixed-width, whereas Factor supports arbitrary-precision integers."
$nl
"Furthermore, Factor's garbage collector can move objects in memory; for a discussion of the consequences, see " { $link "byte-arrays-gc" } "."
{ $subsection "c-types-specs" }
{ $subsection "c-byte-arrays" }
{ $subsection "malloc" }
{ $subsection "c-strings" }
{ $subsection "c-arrays" }
{ $subsection "c-out-params" }
{ $subsections
"c-types-specs"
"c-pointers"
"malloc"
"c-strings"
"c-out-params"
}
"Important guidelines for passing data in byte arrays:"
{ $subsection "byte-arrays-gc" }
{ $subsections "byte-arrays-gc" }
"C-style enumerated types are supported:"
{ $subsection POSTPONE: C-ENUM: }
{ $subsections POSTPONE: C-ENUM: }
"C types can be aliased for convenience and consitency with native library documentation:"
{ $subsection POSTPONE: TYPEDEF: }
"New C types can be defined:"
{ $subsection "c-structs" }
{ $subsection "c-unions" }
{ $subsections POSTPONE: TYPEDEF: }
"A utility for defining " { $link "destructors" } " for deallocating memory:"
{ $subsection "alien.destructors" }
{ $see-also "aliens" } ;
{ $subsections "alien.destructors" }
"C struct and union types can be defined with " { $link POSTPONE: STRUCT: } " and " { $link POSTPONE: UNION: } ". See " { $link "classes.struct" } " for details. For passing arrays to and from C, use the " { $link "specialized-arrays" } " vocabulary." ;
HELP: malloc-string
{ $values { "string" string } { "encoding" "an encoding descriptor" } { "alien" c-ptr } }
{ $description "Encodes a string together with a trailing null code point using the given encoding, and stores the resulting bytes in a freshly-allocated unmanaged memory block." }
@ -138,11 +149,13 @@ $nl
"Care must be taken if the C function expects a " { $link char* } " with a length in bytes, rather than a null-terminated " { $link char* } "; passing the result of calling " { $link length } " on the string object will not suffice. This is because a Factor string of " { $emphasis "n" } " characters will not necessarily encode to " { $emphasis "n" } " bytes. The correct idiom for C functions which take a string with a length is to first encode the string using " { $link encode } ", and then pass the resulting byte array together with the length of this byte array."
$nl
"Sometimes a C function has a parameter type of " { $link void* } ", and various data types, among them strings, can be passed in. In this case, strings are not automatically converted to aliens, and instead you must call one of these words:"
{ $subsection string>alien }
{ $subsection malloc-string }
{ $subsections
string>alien
malloc-string
}
"The first allocates " { $link byte-array } "s, and the latter allocates manually-managed memory which is not moved by the garbage collector and has to be explicitly freed by calling " { $link free } ". See " { $link "byte-arrays-gc" } " for a discussion of the two approaches."
$nl
"A word to read strings from arbitrary addresses:"
{ $subsection alien>string }
{ $subsections alien>string }
"For example, if a C function returns a " { $link char* } " but stipulates that the caller must deallocate the memory afterward, you must define the function as returning " { $link void* } ", and call one of the above words before passing the pointer to " { $link free } "." ;

View File

@ -1,35 +1,35 @@
! (c)2009 Slava Pestov, Joe Groff bsd license
USING: accessors alien alien.c-types alien.strings arrays
byte-arrays cpu.architecture fry io io.encodings.binary
io.files io.streams.memory kernel libc math sequences ;
io.files io.streams.memory kernel libc math sequences words ;
IN: alien.data
GENERIC: require-c-array ( c-type -- )
M: array require-c-array first require-c-array ;
GENERIC: c-array-constructor ( c-type -- word )
GENERIC: c-array-constructor ( c-type -- word ) foldable
GENERIC: c-(array)-constructor ( c-type -- word )
GENERIC: c-(array)-constructor ( c-type -- word ) foldable
GENERIC: c-direct-array-constructor ( c-type -- word )
GENERIC: c-direct-array-constructor ( c-type -- word ) foldable
GENERIC: <c-array> ( len c-type -- array )
M: c-type-name <c-array>
M: word <c-array>
c-array-constructor execute( len -- array ) ; inline
GENERIC: (c-array) ( len c-type -- array )
M: c-type-name (c-array)
M: word (c-array)
c-(array)-constructor execute( len -- array ) ; inline
GENERIC: <c-direct-array> ( alien len c-type -- array )
M: c-type-name <c-direct-array>
M: word <c-direct-array>
c-direct-array-constructor execute( alien len -- array ) ; inline
: malloc-array ( n type -- alien )
: malloc-array ( n type -- array )
[ heap-size calloc ] [ <c-direct-array> ] 2bi ; inline
: (malloc-array) ( n type -- alien )
@ -56,9 +56,6 @@ M: c-type-name <c-direct-array>
: malloc-string ( string encoding -- alien )
string>alien malloc-byte-array ;
: malloc-file-contents ( path -- alien len )
binary file-contents [ malloc-byte-array ] [ length ] bi ;
M: memory-stream stream-read
[
[ index>> ] [ alien>> ] bi <displaced-alien>
@ -81,3 +78,4 @@ M: value-type c-type-setter ( type -- quot )
[ c-type-getter ] [ c-type-unboxer-quot ] [ heap-size ] tri
'[ @ swap @ _ memcpy ] ;

View File

@ -25,6 +25,6 @@ HELP: DESTRUCTOR:
ARTICLE: "alien.destructors" "Alien destructors"
"The " { $vocab-link "alien.destructors" } " vocabulary defines a utility parsing word for defining new disposable classes."
{ $subsection POSTPONE: DESTRUCTOR: } ;
{ $subsections POSTPONE: DESTRUCTOR: } ;
ABOUT: "alien.destructors"

View File

@ -56,13 +56,14 @@ HELP: fortran-invoke
ARTICLE: "alien.fortran" "Fortran FFI"
"The " { $vocab-link "alien.fortran" } " vocabulary provides an interface to code in shared libraries written in Fortran."
{ $subsection "alien.fortran-types" }
{ $subsection "alien.fortran-abis" }
{ $subsection add-fortran-library }
{ $subsection POSTPONE: LIBRARY: }
{ $subsection POSTPONE: FUNCTION: }
{ $subsection POSTPONE: SUBROUTINE: }
{ $subsection fortran-invoke }
;
{ $subsections
"alien.fortran-types"
"alien.fortran-abis"
add-fortran-library
POSTPONE: LIBRARY:
POSTPONE: FUNCTION:
POSTPONE: SUBROUTINE:
fortran-invoke
} ;
ABOUT: "alien.fortran"

View File

@ -45,10 +45,12 @@ HELP: load-library
HELP: add-library
{ $values { "name" string } { "path" string } { "abi" "one of " { $snippet "\"cdecl\"" } " or " { $snippet "\"stdcall\"" } } }
{ $description "Defines a new logical library named " { $snippet "name" } " located in the file system at " { $snippet "path" } "and the specified ABI." }
{ $notes "Because the entire source file is parsed before top-level forms are executed, " { $link add-library } " cannot be used in the same file as " { $link POSTPONE: FUNCTION: } " definitions from that library. The " { $link add-library } " call will happen too late, after compilation, and the alien calls will not work."
{ $description "Defines a new logical library named " { $snippet "name" } " located in the file system at " { $snippet "path" } " and the specified ABI. The logical library name can then be used by a " { $link POSTPONE: LIBRARY: } " form to specify the logical library for subsequent " { $link POSTPONE: FUNCTION: } " definitions." }
{ $notes "Because the entire source file is parsed before top-level forms are executed, " { $link add-library } " must be placed within a " { $snippet "<< ... >>" } " parse-time evaluation block."
$nl
"Instead, " { $link add-library } " calls must either be placed in different source files from those that use that library, or alternatively, " { $link "syntax-immediate" } " can be used to load the library before compilation." }
"This ensures that if the logical library is later used in the same file, for example by a " { $link POSTPONE: FUNCTION: } " definition. Otherwise, the " { $link add-library } " call will happen too late, after compilation, and the C function calls will not refer to the correct library."
$nl
"For details about parse-time evaluation, see " { $link "syntax-immediate" } "." }
{ $examples "Here is a typical usage of " { $link add-library } ":"
{ $code
"<< \"freetype\" {"
@ -65,8 +67,10 @@ HELP: remove-library
ARTICLE: "loading-libs" "Loading native libraries"
"Before calling a C library, you must associate its path name on disk with a logical name which Factor uses to identify the library:"
{ $subsection add-library }
{ $subsection remove-library }
{ $subsections
add-library
remove-library
}
"Once a library has been defined, you can try loading it to see if the path name is correct:"
{ $subsection load-library }
{ $subsections load-library }
"If the compiler cannot load a library, or cannot resolve a symbol in a library, a linkage error is reported using the compiler error mechanism (see " { $link "compiler-errors" } "). Once you install the right library, reload the source file containing the " { $link add-library } " form to force the compiler to try loading the library again." ;

View File

@ -0,0 +1,43 @@
! (c)2009 Joe Groff bsd license
USING: accessors alien.c-types alien.parser alien.syntax
tools.test vocabs.parser parser eval vocabs.parser debugger
continuations ;
IN: alien.parser.tests
TYPEDEF: char char2
SYMBOL: not-c-type
[
"alien.parser.tests" use-vocab
"alien.c-types" use-vocab
[ int ] [ "int" parse-c-type ] unit-test
[ { int 5 } ] [ "int[5]" parse-c-type ] unit-test
[ { int 5 10 11 } ] [ "int[5][10][11]" parse-c-type ] unit-test
[ void* ] [ "int*" parse-c-type ] unit-test
[ void* ] [ "int**" parse-c-type ] unit-test
[ void* ] [ "int***" parse-c-type ] unit-test
[ void* ] [ "int****" parse-c-type ] unit-test
[ char* ] [ "char*" parse-c-type ] unit-test
[ void* ] [ "char**" parse-c-type ] unit-test
[ void* ] [ "char***" parse-c-type ] unit-test
[ void* ] [ "char****" parse-c-type ] unit-test
[ char2 ] [ "char2" parse-c-type ] unit-test
[ char* ] [ "char2*" parse-c-type ] unit-test
[ "not-c-type" parse-c-type ] [ no-c-type? ] must-fail-with
[ "not-word" parse-c-type ] [ error>> no-word-error? ] must-fail-with
] with-file-vocabs
! Reported by mnestic
TYPEDEF: int alien-parser-test-int ! reasonably unique name...
[ "OK!" ] [
[
"USE: specialized-arrays SPECIALIZED-ARRAY: alien-parser-test-int" eval( -- )
! after restart, we end up here
"OK!"
] [ :1 ] recover
] unit-test

View File

@ -1,22 +1,23 @@
! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien alien.c-types arrays assocs
combinators combinators.short-circuit effects grouping
USING: accessors alien alien.c-types alien.parser
alien.libraries arrays assocs classes combinators
combinators.short-circuit compiler.units effects grouping
kernel parser sequences splitting words fry locals lexer
namespaces summary math vocabs.parser ;
IN: alien.parser
: parse-c-type-name ( name -- word/string )
[ search ] keep or ;
: parse-c-type-name ( name -- word )
dup search [ ] [ no-word ] ?if ;
: parse-c-type ( string -- array )
: parse-c-type ( string -- type )
{
{ [ dup "void" = ] [ drop void ] }
{ [ CHAR: ] over member? ] [ parse-array-type parse-c-type-name prefix ] }
{ [ dup search c-type-word? ] [ parse-c-type-name ] }
{ [ dup c-types get at ] [ ] }
{ [ "**" ?tail ] [ drop void* ] }
{ [ "*" ?tail ] [ parse-c-type-name resolve-pointer-type ] }
[ no-c-type ]
[ dup search [ no-c-type ] [ no-word ] ?if ]
} cond ;
: scan-c-type ( -- c-type )
@ -25,10 +26,22 @@ IN: alien.parser
[ parse-c-type ] if ;
: reset-c-type ( word -- )
{ "c-type" "pointer-c-type" "callback-effect" "callback-abi" } reset-props ;
dup "struct-size" word-prop
[ dup [ forget-class ] [ { "struct-size" } reset-props ] bi ] when
{
"c-type"
"pointer-c-type"
"callback-effect"
"callback-library"
} reset-props ;
: CREATE-C-TYPE ( -- word )
scan current-vocab create dup reset-c-type ;
scan current-vocab create {
[ fake-definition ]
[ set-word ]
[ reset-c-type ]
[ ]
} cleave ;
: normalize-c-arg ( type name -- type' name' )
[ length ]
@ -67,17 +80,21 @@ IN: alien.parser
: callback-quot ( return types abi -- quot )
[ [ ] 3curry dip alien-callback ] 3curry ;
:: make-callback-type ( abi return! type-name! parameters -- word quot effect )
: library-abi ( lib -- abi )
library [ abi>> ] [ "cdecl" ] if* ;
:: make-callback-type ( lib return! type-name! parameters -- word quot effect )
return type-name normalize-c-arg type-name! return!
type-name current-vocab create :> type-word
type-word [ reset-generic ] [ reset-c-type ] bi
void* type-word typedef
parameters return parse-arglist :> callback-effect :> types
type-word callback-effect "callback-effect" set-word-prop
type-word abi "callback-abi" set-word-prop
type-word return types abi callback-quot (( quot -- alien )) ;
type-word lib "callback-library" set-word-prop
type-word return types lib library-abi callback-quot (( quot -- alien )) ;
: (CALLBACK:) ( abi -- word quot effect )
: (CALLBACK:) ( -- word quot effect )
"c-library" get
scan scan parse-arg-tokens make-callback-type ;
PREDICATE: alien-function-word < word

View File

@ -45,13 +45,16 @@ M: typedef-word synopsis*
first2 pprint-function-arg
] if-empty ;
: pprint-library ( library -- )
[ \ LIBRARY: [ text ] pprint-prefix ] when* ;
M: alien-function-word definer
drop \ FUNCTION: \ ; ;
M: alien-function-word definition drop f ;
M: alien-function-word synopsis*
{
[ seeing-word ]
[ def>> second [ \ LIBRARY: [ text ] pprint-prefix ] when* ]
[ def>> second pprint-library ]
[ definer. ]
[ def>> first pprint-c-type ]
[ pprint-word ]
@ -64,13 +67,12 @@ M: alien-function-word synopsis*
} cleave ;
M: alien-callback-type-word definer
"callback-abi" word-prop "stdcall" =
\ STDCALL-CALLBACK: \ CALLBACK: ?
f ;
drop \ CALLBACK: \ ; ;
M: alien-callback-type-word definition drop f ;
M: alien-callback-type-word synopsis*
{
[ seeing-word ]
[ "callback-library" word-prop pprint-library ]
[ definer. ]
[ def>> first pprint-c-type ]
[ pprint-word ]

View File

@ -1,45 +0,0 @@
! Copyright (C) 2005, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays kernel kernel.private math namespaces
make sequences strings words effects combinators alien.c-types ;
IN: alien.structs.fields
TUPLE: field-spec name offset type reader writer ;
: reader-word ( class name vocab -- word )
[ "-" glue ] dip create dup make-deprecated ;
: writer-word ( class name vocab -- word )
[ [ swap "set-" % % "-" % % ] "" make ] dip create dup make-deprecated ;
: <field-spec> ( struct-name vocab type field-name -- spec )
field-spec new
0 >>offset
swap >>name
swap >>type
3dup name>> swap reader-word >>reader
3dup name>> swap writer-word >>writer
2nip ;
: align-offset ( offset type -- offset )
c-type-align align ;
: struct-offsets ( specs -- size )
0 [
[ type>> align-offset ] keep
[ (>>offset) ] [ type>> heap-size + ] 2bi
] reduce ;
: define-struct-slot-word ( word quot spec effect -- )
[ offset>> prefix ] dip define-inline ;
: define-getter ( spec -- )
[ reader>> ] [ type>> c-type-getter-boxer ] [ ] tri
(( c-ptr -- value )) define-struct-slot-word ;
: define-setter ( spec -- )
[ writer>> ] [ type>> c-setter ] [ ] tri
(( value c-ptr -- )) define-struct-slot-word ;
: define-field ( spec -- )
[ define-getter ] [ define-setter ] bi ;

View File

@ -1 +0,0 @@
Struct field implementation and reflection support

View File

@ -1,33 +0,0 @@
USING: alien.c-types alien.data strings help.markup help.syntax alien.syntax
sequences io arrays kernel words assocs namespaces ;
IN: alien.structs
ARTICLE: "c-structs" "C structure types"
"A " { $snippet "struct" } " in C is essentially a block of memory with the value of each structure field stored at a fixed offset from the start of the block. The C library interface provides some utilities to define words which read and write structure fields given a base address."
{ $subsection POSTPONE: C-STRUCT: }
"Great care must be taken when working with C structures since no type or bounds checking is possible."
$nl
"An example:"
{ $code
"C-STRUCT: XVisualInfo"
" { \"Visual*\" \"visual\" }"
" { \"VisualID\" \"visualid\" }"
" { \"int\" \"screen\" }"
" { \"uint\" \"depth\" }"
" { \"int\" \"class\" }"
" { \"ulong\" \"red_mask\" }"
" { \"ulong\" \"green_mask\" }"
" { \"ulong\" \"blue_mask\" }"
" { \"int\" \"colormap_size\" }"
" { \"int\" \"bits_per_rgb\" } ;"
}
"C structure objects can be allocated by calling " { $link <c-object> } " or " { $link malloc-object } "."
$nl
"Arrays of C structures can be created with the " { $vocab-link "specialized-arrays" } " vocabulary." ;
ARTICLE: "c-unions" "C unions"
"A " { $snippet "union" } " in C defines a type large enough to hold its largest member. This is usually used to allocate a block of memory which can hold one of several types of values."
{ $subsection POSTPONE: C-UNION: }
"C union objects can be allocated by calling " { $link <c-object> } " or " { $link malloc-object } "."
$nl
"Arrays of C unions can be created with the " { $vocab-link "specialized-arrays" } " vocabulary." ;

View File

@ -1,59 +0,0 @@
USING: alien alien.syntax alien.c-types alien.data kernel tools.test
sequences system libc words vocabs namespaces layouts ;
IN: alien.structs.tests
C-STRUCT: bar
{ "int" "x" }
{ { "int" 8 } "y" } ;
[ 36 ] [ "bar" heap-size ] unit-test
[ t ] [ \ <displaced-alien> "bar" c-type-getter memq? ] unit-test
C-STRUCT: align-test
{ "int" "x" }
{ "double" "y" } ;
os winnt? cpu x86? and [
[ 16 ] [ "align-test" heap-size ] unit-test
cell 4 = [
C-STRUCT: one
{ "long" "a" } { "double" "b" } { "int" "c" } ;
[ 24 ] [ "one" heap-size ] unit-test
] when
] when
CONSTANT: MAX_FOOS 30
C-STRUCT: foox
{ { "int" MAX_FOOS } "x" } ;
[ 120 ] [ "foox" heap-size ] unit-test
C-UNION: barx
{ "int" MAX_FOOS }
"float" ;
[ 120 ] [ "barx" heap-size ] unit-test
"help" vocab [
"print-topic" "help" lookup "help" set
[ ] [ \ foox-x "help" get execute ] unit-test
[ ] [ \ set-foox-x "help" get execute ] unit-test
] when
C-STRUCT: nested
{ "int" "x" } ;
C-STRUCT: nested-2
{ "nested" "y" } ;
[ 4 ] [
"nested-2" <c-object>
"nested" <c-object>
4 over set-nested-x
over set-nested-2-y
nested-2-y
nested-x
] unit-test

View File

@ -1,71 +0,0 @@
! Copyright (C) 2004, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs generic hashtables kernel kernel.private
math namespaces parser sequences strings words libc fry
alien.c-types alien.structs.fields cpu.architecture math.order
quotations byte-arrays ;
IN: alien.structs
TUPLE: struct-type < abstract-c-type fields return-in-registers? ;
INSTANCE: struct-type value-type
M: struct-type c-type ;
M: struct-type c-type-stack-align? drop f ;
: if-value-struct ( ctype true false -- )
[ dup value-struct? ] 2dip '[ drop void* @ ] if ; inline
M: struct-type unbox-parameter
[ %unbox-large-struct ] [ unbox-parameter ] if-value-struct ;
M: struct-type box-parameter
[ %box-large-struct ] [ box-parameter ] if-value-struct ;
: if-small-struct ( c-type true false -- ? )
[ dup return-struct-in-registers? ] 2dip '[ f swap @ ] if ; inline
M: struct-type unbox-return
[ %unbox-small-struct ] [ %unbox-large-struct ] if-small-struct ;
M: struct-type box-return
[ %box-small-struct ] [ %box-large-struct ] if-small-struct ;
M: struct-type stack-size
[ heap-size ] [ stack-size ] if-value-struct ;
M: struct-type c-struct? drop t ;
: (define-struct) ( name size align fields class -- )
[ [ align ] keep ] 2dip new
byte-array >>class
byte-array >>boxed-class
swap >>fields
swap >>align
swap >>size
swap typedef ;
: make-fields ( name vocab fields -- fields )
[ first2 <field-spec> ] with with map ;
: compute-struct-align ( types -- n )
[ c-type-align ] [ max ] map-reduce ;
: define-struct ( name vocab fields -- )
[ 2drop ] [ make-fields ] 3bi
[ struct-offsets ] keep
[ [ type>> ] map compute-struct-align ] keep
[ struct-type (define-struct) ] keep
[ define-field ] each ; deprecated
: define-union ( name members -- )
[ [ heap-size ] [ max ] map-reduce ] keep
compute-struct-align f struct-type (define-struct) ; deprecated
: offset-of ( field struct -- offset )
c-types get at fields>>
[ name>> = ] with find nip offset>> ;
USE: vocabs.loader
"specialized-arrays" require

View File

@ -1 +0,0 @@
C structure support

View File

@ -1,6 +1,6 @@
IN: alien.syntax
USING: alien alien.c-types alien.parser alien.structs
classes.struct help.markup help.syntax ;
USING: alien alien.c-types alien.parser alien.libraries
classes.struct help.markup help.syntax see ;
HELP: DLL"
{ $syntax "DLL\" path\"" }
@ -14,13 +14,16 @@ HELP: ALIEN:
{ $notes "Alien objects are invalidated between image saves and loads, and hence source files should not contain alien literals; this word is for interactive use only. See " { $link "alien-expiry" } " for details." } ;
ARTICLE: "syntax-aliens" "Alien object literal syntax"
{ $subsection POSTPONE: ALIEN: }
{ $subsection POSTPONE: DLL" } ;
{ $subsections
POSTPONE: ALIEN:
POSTPONE: DLL"
} ;
HELP: LIBRARY:
{ $syntax "LIBRARY: name" }
{ $values { "name" "a logical library name" } }
{ $description "Sets the logical library for consequent " { $link POSTPONE: FUNCTION: } " definitions that follow." } ;
{ $description "Sets the logical library for consequent " { $link POSTPONE: FUNCTION: } ", " { $link POSTPONE: C-GLOBAL: } " and " { $link POSTPONE: CALLBACK: } " definitions, as well as " { $link POSTPONE: &: } " forms." }
{ $notes "Logical library names are defined with the " { $link add-library } " word." } ;
HELP: FUNCTION:
{ $syntax "FUNCTION: return name ( parameters )" }
@ -54,21 +57,6 @@ HELP: TYPEDEF:
{ $description "Aliases the C type " { $snippet "old" } " under the name " { $snippet "new" } " if ." }
{ $notes "This word differs from " { $link typedef } " in that it runs at parse time, to ensure correct ordering of operations when loading source files. Words defined in source files are compiled before top-level forms are run, so if a source file defines C binding words and uses " { $link typedef } ", the type alias won't be available at compile time." } ;
HELP: C-STRUCT:
{ $deprecated "New code should use " { $link "classes.struct" } ". See the " { $link POSTPONE: STRUCT: } " word." }
{ $syntax "C-STRUCT: name pairs... ;" }
{ $values { "name" "a new C type name" } { "pairs" "C type / field name string pairs" } }
{ $description "Defines a C struct layout and accessor words." }
{ $notes "C type names are documented in " { $link "c-types-specs" } "." } ;
HELP: C-UNION:
{ $deprecated "New code should use " { $link "classes.struct" } ". See the " { $link POSTPONE: UNION-STRUCT: } " word." }
{ $syntax "C-UNION: name members... ;" }
{ $values { "name" "a new C type name" } { "members" "a sequence of C types" } }
{ $description "Defines a new C type sized to fit its largest member." }
{ $notes "C type names are documented in " { $link "c-types-specs" } "." }
{ $examples { $code "C-UNION: event \"active-event\" \"keyboard-event\" \"mouse-event\" ;" } } ;
HELP: C-ENUM:
{ $syntax "C-ENUM: words... ;" }
{ $values { "words" "a sequence of word names" } }
@ -81,10 +69,20 @@ HELP: C-ENUM:
{ $code "CONSTANT: red 0" "CONSTANT: green 1" "CONSTANT: blue 2" }
} ;
HELP: C-TYPE:
{ $syntax "C-TYPE: type" }
{ $values { "type" "a new C type" } }
{ $description "Defines a new, opaque C type. Since it is opaque, " { $snippet "type" } " will not be directly usable as a parameter or return type of a " { $link POSTPONE: FUNCTION: } " or as a slot of a " { $link POSTPONE: STRUCT: } ". However, it can be used as the type of a pointer (that is, as " { $snippet "type*" } ")." $nl
{ $snippet "C-TYPE:" } " can also be used to forward-declare C types to enable circular dependencies. For example:"
{ $code """C-TYPE: forward
STRUCT: backward { x forward* } ;
STRUCT: forward { x backward* } ; """ } }
{ $notes "Primitive C types are also displayed using " { $snippet "C-TYPE:" } " syntax when they are displayed by " { $link see } "." } ;
HELP: CALLBACK:
{ $syntax "CALLBACK: return type ( parameters ) ;" }
{ $values { "return" "a C return type" } { "type" "a type name" } { "parameters" "a comma-separated sequence of type/name pairs; " { $snippet "type1 arg1, type2 arg2, ..." } } }
{ $description "Defines a new function pointer C type word " { $snippet "type" } ". The newly defined word works both as a C type and as a wrapper for " { $link alien-callback } " for callbacks that accept the given return type and parameters with the " { $snippet "\"cdecl\"" } " ABI." }
{ $description "Defines a new function pointer C type word " { $snippet "type" } ". The newly defined word works both as a C type and as a wrapper for " { $link alien-callback } " for callbacks that accept the given return type and parameters. The ABI of the callback is decided from the ABI of the active " { $link POSTPONE: LIBRARY: } " declaration." }
{ $examples
{ $code
"CALLBACK: bool FakeCallback ( int message, void* payload ) ;"
@ -98,42 +96,28 @@ HELP: CALLBACK:
}
} ;
HELP: STDCALL-CALLBACK:
{ $syntax "STDCALL-CALLBACK: return type ( parameters ) ;" }
{ $values { "return" "a C return type" } { "type" "a type name" } { "parameters" "a comma-separated sequence of type/name pairs; " { $snippet "type1 arg1, type2 arg2, ..." } } }
{ $description "Defines a new function pointer C type word " { $snippet "type" } ". The newly defined word works both as a C type and as a wrapper for " { $link alien-callback } " for callbacks that accept the given return type and parameters with the " { $snippet "\"stdcall\"" } " ABI." }
{ $examples
{ $code
"STDCALL-CALLBACK: bool FakeCallback ( int message, void* payload ) ;"
": MyFakeCallback ( -- alien )"
" [| message payload |"
" \"message #\" write"
" message number>string write"
" \" received\" write nl"
" t"
" ] FakeCallback ;"
}
} ;
{ POSTPONE: CALLBACK: POSTPONE: STDCALL-CALLBACK: } related-words
HELP: &:
{ $syntax "&: symbol" }
{ $values { "symbol" "A C library symbol name" } }
{ $values { "symbol" "A C global variable name" } }
{ $description "Pushes the address of a symbol named " { $snippet "symbol" } " from the current library, set with " { $link POSTPONE: LIBRARY: } "." } ;
HELP: typedef
{ $values { "old" "a string" } { "new" "a string" } }
{ $values { "old" "a C type" } { "new" "a C type" } }
{ $description "Aliases the C type " { $snippet "old" } " under the name " { $snippet "new" } "." }
{ $notes "Using this word in the same source file which defines C bindings can cause problems, because words are compiled before top-level forms are run. Use the " { $link POSTPONE: TYPEDEF: } " word instead." } ;
{ POSTPONE: TYPEDEF: typedef } related-words
HELP: c-struct?
{ $values { "type" "a string" } { "?" "a boolean" } }
{ $description "Tests if a C type is a structure defined by " { $link POSTPONE: C-STRUCT: } "." } ;
{ $values { "c-type" "a C type" } { "?" "a boolean" } }
{ $description "Tests if a C type is a structure defined by " { $link POSTPONE: STRUCT: } "." } ;
HELP: define-function
{ $values { "return" "a C return type" } { "library" "a logical library name" } { "function" "a C function name" } { "parameters" "a sequence of C parameter types" } }
{ $description "Defines a word named " { $snippet "function" } " in the current vocabulary (see " { $link "vocabularies" } "). The word calls " { $link alien-invoke } " with the specified parameters." }
{ $notes "This word is used to implement the " { $link POSTPONE: FUNCTION: } " parsing word." } ;
HELP: C-GLOBAL:
{ $syntax "C-GLOBAL: type name" }
{ $values { "type" "a C type" } { "name" "a C global variable name" } }
{ $description "Defines a new word named " { $snippet "name" } " which accesses a global variable in the current library, set with " { $link POSTPONE: LIBRARY: } "." } ;

View File

@ -1,6 +1,6 @@
! Copyright (C) 2005, 2009 Slava Pestov, Alex Chapman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays alien alien.c-types alien.structs
USING: accessors arrays alien alien.c-types
alien.arrays alien.strings kernel math namespaces parser
sequences words quotations math.parser splitting grouping
effects assocs combinators lexer strings.parser alien.parser
@ -19,26 +19,17 @@ SYNTAX: FUNCTION:
(FUNCTION:) define-declared ;
SYNTAX: CALLBACK:
"cdecl" (CALLBACK:) define-inline ;
SYNTAX: STDCALL-CALLBACK:
"stdcall" (CALLBACK:) define-inline ;
(CALLBACK:) define-inline ;
SYNTAX: TYPEDEF:
scan-c-type CREATE-C-TYPE typedef ;
SYNTAX: C-STRUCT:
scan current-vocab parse-definition define-struct ; deprecated
SYNTAX: C-UNION:
scan parse-definition define-union ; deprecated
SYNTAX: C-ENUM:
";" parse-tokens
[ [ create-in ] dip define-constant ] each-index ;
SYNTAX: C-TYPE:
"Primitive C type definition not supported" throw ;
void CREATE-C-TYPE typedef ;
ERROR: no-such-symbol name library ;
@ -47,3 +38,12 @@ ERROR: no-such-symbol name library ;
SYNTAX: &:
scan "c-library" get '[ _ _ address-of ] over push-all ;
: global-quot ( type word -- quot )
name>> "c-library" get '[ _ _ address-of 0 ]
swap c-type-getter-boxer append ;
: define-global ( type word -- )
[ nip ] [ global-quot ] 2bi (( -- value )) define-declared ;
SYNTAX: C-GLOBAL: scan-c-type CREATE-WORD define-global ;

View File

@ -61,18 +61,22 @@ ARTICLE: "ascii" "ASCII"
"The " { $vocab-link "ascii" } " vocabulary implements support for the legacy ASCII character set. Most applications should use " { $link "unicode" } " instead."
$nl
"ASCII character classes:"
{ $subsection blank? }
{ $subsection letter? }
{ $subsection LETTER? }
{ $subsection digit? }
{ $subsection printable? }
{ $subsection control? }
{ $subsection quotable? }
{ $subsection ascii? }
{ $subsections
blank?
letter?
LETTER?
digit?
printable?
control?
quotable?
ascii?
}
"ASCII case conversion:"
{ $subsection ch>lower }
{ $subsection ch>upper }
{ $subsection >lower }
{ $subsection >upper } ;
{ $subsections
ch>lower
ch>upper
>lower
>upper
} ;
ABOUT: "ascii"

View File

@ -36,12 +36,16 @@ HELP: encode-base64-lines
ARTICLE: "base64" "Base 64 conversions"
"The " { $vocab-link "base64" } " vocabulary implements conversions of sequences to printable characters in base 64. These plain-text representations of binary data may be passed around and converted back to binary data later." $nl
"Converting to and from base64 as strings:"
{ $subsection >base64 }
{ $subsection >base64-lines }
{ $subsection base64> }
{ $subsections
>base64
>base64-lines
base64>
}
"Using base64 from streams:"
{ $subsection encode-base64 }
{ $subsection encode-base64-lines }
{ $subsection decode-base64 } ;
{ $subsections
encode-base64
encode-base64-lines
decode-base64
} ;
ABOUT: "base64"

View File

@ -26,12 +26,16 @@ $nl
"Bidirectional assocs implement the entire " { $link "assocs-protocol" } " with the exception of " { $link delete-at } ". Duplicate values are allowed, however value lookups with " { $link value-at } " only return the first key that a given value was stored with."
$nl
"The class of biassocs:"
{ $subsection biassoc }
{ $subsection biassoc? }
{ $subsections
biassoc
biassoc?
}
"Creating new biassocs:"
{ $subsection <biassoc> }
{ $subsection <bihash> }
{ $subsections
<biassoc>
<bihash>
}
"Converting existing assocs to biassocs:"
{ $subsection >biassoc } ;
{ $subsections >biassoc } ;
ABOUT: "biassocs"

View File

@ -33,11 +33,13 @@ HELP: sorted-memq?
ARTICLE: "binary-search" "Binary search"
"The " { $emphasis "binary search" } " algorithm allows elements to be located in sorted sequence in " { $snippet "O(log n)" } " time."
{ $subsection search }
{ $subsections search }
"Variants of sequence words optimized for sorted sequences:"
{ $subsection sorted-index }
{ $subsection sorted-member? }
{ $subsection sorted-memq? }
{ $subsections
sorted-index
sorted-member?
sorted-memq?
}
{ $see-also "order-specifiers" "sequences-sorting" } ;
ABOUT: "binary-search"

View File

@ -7,22 +7,30 @@ ARTICLE: "bit-arrays" "Bit arrays"
$nl
"Bit array words are in the " { $vocab-link "bit-arrays" } " vocabulary."
$nl
"Bit arrays play a special role in the C library interface; they can be used to pass binary data back and forth between Factor and C. See " { $link "c-byte-arrays" } "."
"Bit arrays play a special role in the C library interface; they can be used to pass binary data back and forth between Factor and C. See " { $link "c-pointers" } "."
$nl
"Bit arrays form a class of objects:"
{ $subsection bit-array }
{ $subsection bit-array? }
{ $subsections
bit-array
bit-array?
}
"Creating new bit arrays:"
{ $subsection >bit-array }
{ $subsection <bit-array> }
{ $subsections
>bit-array
<bit-array>
}
"Efficiently setting and clearing all bits in a bit array:"
{ $subsection set-bits }
{ $subsection clear-bits }
{ $subsections
set-bits
clear-bits
}
"Converting between unsigned integers and their binary representation:"
{ $subsection integer>bit-array }
{ $subsection bit-array>integer }
{ $subsections
integer>bit-array
bit-array>integer
}
"Bit array literal syntax:"
{ $subsection POSTPONE: ?{ } ;
{ $subsections POSTPONE: ?{ } ;
ABOUT: "bit-arrays"

View File

@ -6,13 +6,17 @@ ARTICLE: "bit-vectors" "Bit vectors"
"A bit vector is a resizable mutable sequence of bits. Bit vector words are found in the " { $vocab-link "bit-vectors" } " vocabulary."
$nl
"Bit vectors form a class:"
{ $subsection bit-vector }
{ $subsection bit-vector? }
{ $subsections
bit-vector
bit-vector?
}
"Creating bit vectors:"
{ $subsection >bit-vector }
{ $subsection <bit-vector> }
{ $subsections
>bit-vector
<bit-vector>
}
"Literal syntax:"
{ $subsection POSTPONE: ?V{ }
{ $subsections POSTPONE: ?V{ }
"If you don't care about initial capacity, a more elegant way to create a new bit vector is to write:"
{ $code "?V{ } clone" } ;

View File

@ -3,7 +3,7 @@ IN: bootstrap.image
ARTICLE: "bootstrap.image" "Bootstrapping new images"
"A new image can be built from source; this is known as " { $emphasis "bootstrap" } ". Bootstrap is a two-step process. The first stage is the creation of a bootstrap image from a running Factor instance:"
{ $subsection make-image }
{ $subsections make-image }
"The second bootstrapping stage is initiated by running the resulting bootstrap image:"
{ $code "./factor -i=boot.x86.32.image" }
"This stage loads additional code, compiles all words, and dumps a final " { $snippet "factor.image" } "."

View File

@ -163,6 +163,7 @@ USERENV: jit-3dip 40
USERENV: jit-execute-word 41
USERENV: jit-execute-jump 42
USERENV: jit-execute-call 43
USERENV: jit-declare-word 44
! PIC stubs
USERENV: pic-load 47
@ -493,6 +494,7 @@ M: quotation '
\ 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
[ undefined ] undefined-quot set ;
: emit-userenvs ( -- )

View File

@ -24,14 +24,16 @@ HELP: ?box
ARTICLE: "boxes" "Boxes"
"A " { $emphasis "box" } " is a container which can either be empty or hold a single value."
{ $subsection box }
{ $subsections box }
"Creating an empty box:"
{ $subsection <box> }
{ $subsections <box> }
"Storing a value and removing a value from a box:"
{ $subsection >box }
{ $subsection box> }
{ $subsections
>box
box>
}
"Safely removing a value:"
{ $subsection ?box }
{ $subsections ?box }
"Testing if a box is full can be done by reading the " { $snippet "occupied" } " slot." ;
ABOUT: "boxes"

View File

@ -520,125 +520,142 @@ HELP: since-1970
ARTICLE: "calendar" "Calendar"
"The two data types used throughout the calendar library:"
{ $subsection timestamp }
{ $subsection duration }
{ $subsections
timestamp
duration
}
"Durations represent spans of time:"
{ $subsection "using-durations" }
{ $subsections "using-durations" }
"Arithmetic on timestamps and durations:"
{ $subsection "timestamp-arithmetic" }
{ $subsections "timestamp-arithmetic" }
"Getting the current timestamp:"
{ $subsection now }
{ $subsection gmt }
{ $subsections
now
gmt
}
"Converting between timestamps:"
{ $subsection >local-time }
{ $subsection >gmt }
{ $subsections
>local-time
>gmt
}
"Converting between timezones:"
{ $subsection convert-timezone }
{ $subsections convert-timezone }
"Timestamps relative to each other:"
{ $subsection "relative-timestamps" }
{ $subsections "relative-timestamps" }
"Operations on units of time:"
{ $subsection "years" }
{ $subsection "months" }
{ $subsection "days" }
{ $subsections
"years"
"months"
"days"
}
"Meta-data about the calendar:"
{ $subsection "calendar-facts" }
{ $subsections "calendar-facts" }
;
ARTICLE: "timestamp-arithmetic" "Timestamp arithmetic"
"Adding timestamps and durations, or durations and durations:"
{ $subsection time+ }
{ $subsections time+ }
"Subtracting:"
{ $subsection time- }
{ $subsections time- }
"Element-wise multiplication:"
{ $subsection time* } ;
{ $subsections time* } ;
ARTICLE: "using-durations" "Using durations"
"Creating a duration object:"
{ $subsection years }
{ $subsection months }
{ $subsection weeks }
{ $subsection days }
{ $subsection hours }
{ $subsection minutes }
{ $subsection seconds }
{ $subsection milliseconds }
{ $subsection microseconds }
{ $subsection nanoseconds }
{ $subsection instant }
{ $subsections
years
months
weeks
days
hours
minutes
seconds
milliseconds
microseconds
nanoseconds
instant
}
"Converting a duration to a number:"
{ $subsection duration>years }
{ $subsection duration>months }
{ $subsection duration>days }
{ $subsection duration>hours }
{ $subsection duration>minutes }
{ $subsection duration>seconds }
{ $subsection duration>milliseconds }
{ $subsection duration>microseconds }
{ $subsection duration>nanoseconds } ;
{ $subsections
duration>years
duration>months
duration>days
duration>hours
duration>minutes
duration>seconds
duration>milliseconds
duration>microseconds
duration>nanoseconds
} ;
ARTICLE: "relative-timestamps" "Relative timestamps"
"In the future:"
{ $subsection hence }
{ $subsections hence }
"In the past:"
{ $subsection ago }
{ $subsections ago }
"Invert a duration:"
{ $subsection before }
{ $subsections before }
"Days of the week relative to " { $link now } ":"
{ $subsection sunday }
{ $subsection monday }
{ $subsection tuesday }
{ $subsection wednesday }
{ $subsection thursday }
{ $subsection friday }
{ $subsection saturday }
{ $subsections
sunday
monday
tuesday
wednesday
thursday
friday
saturday
}
"New timestamps relative to calendar events:"
{ $subsection beginning-of-year }
{ $subsection beginning-of-month }
{ $subsection beginning-of-week }
{ $subsection midnight }
{ $subsection noon }
;
{ $subsections
beginning-of-year
beginning-of-month
beginning-of-week
midnight
noon
} ;
ARTICLE: "days" "Day operations"
"Naming days:"
{ $subsection day-abbreviation2 }
{ $subsection day-abbreviations2 }
{ $subsection day-abbreviation3 }
{ $subsection day-abbreviations3 }
{ $subsection day-name }
{ $subsection day-names }
{ $subsections
day-abbreviation2
day-abbreviations2
day-abbreviation3
day-abbreviations3
day-name
day-names
}
"Calculating a Julian day number:"
{ $subsection julian-day-number }
{ $subsections julian-day-number }
"Calculate a timestamp:"
{ $subsection julian-day-number>date }
;
{ $subsections julian-day-number>date } ;
ARTICLE: "calendar-facts" "Calendar facts"
"Calendar facts:"
{ $subsection average-month }
{ $subsection months-per-year }
{ $subsection days-per-year }
{ $subsection hours-per-year }
{ $subsection minutes-per-year }
{ $subsection seconds-per-year }
{ $subsection days-in-month }
{ $subsection day-of-year }
{ $subsection day-of-week }
;
{ $subsections
average-month
months-per-year
days-per-year
hours-per-year
minutes-per-year
seconds-per-year
days-in-month
day-of-year
day-of-week
} ;
ARTICLE: "years" "Year operations"
"Leap year predicate:"
{ $subsection leap-year? }
{ $subsections leap-year? }
"Find the number of days in a year:"
{ $subsection days-in-year }
;
{ $subsections days-in-year } ;
ARTICLE: "months" "Month operations"
"Naming months:"
{ $subsection month-name }
{ $subsection month-names }
{ $subsection month-abbreviation }
{ $subsection month-abbreviations }
;
{ $subsections
month-name
month-names
month-abbreviation
month-abbreviations
} ;
ABOUT: "calendar"

View File

@ -37,10 +37,10 @@ HELP: from
ARTICLE: "channels" "Channels"
"The " { $vocab-link "channels" } " vocabulary provides a simple abstraction to send and receive objects." $nl
"Opening a channel:"
{ $subsection <channel> }
{ $subsections <channel> }
"Sending a message:"
{ $subsection to }
{ $subsections to }
"Receiving a message:"
{ $subsection from } ;
{ $subsections from } ;
ABOUT: "channels"

View File

@ -6,6 +6,6 @@ HELP: adler-32
ARTICLE: "checksums.adler-32" "Adler-32 checksum"
"The Adler-32 checksum algorithm implements simple and fast checksum. It is used in zlib and rsync."
{ $subsection adler-32 } ;
{ $subsections adler-32 } ;
ABOUT: "checksums.adler-32"

View File

@ -44,24 +44,29 @@ HELP: fnv1a-1024
ARTICLE: "checksums.fnv1" "Fowler-Noll-Vo checksum"
"The Fowler-Noll-Vo checksum algorithm is another simple and fast checksum. It comes in 32, 64, 128, 256, 512 and 1024-bit versions, each in 1 and 1a variants. The 1a variants tend to produce a slightly better result. See http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash for more details."
{ $subsection fnv1-32 }
{ $subsection fnv1a-32 }
{ $subsection fnv1-64 }
{ $subsection fnv1a-64 }
{ $subsection fnv1-128 }
{ $subsection fnv1a-128 }
{ $subsection fnv1-256 }
{ $subsection fnv1a-256 }
{ $subsection fnv1-512 }
{ $subsection fnv1a-512 }
{ $subsection fnv1-1024 }
{ $subsection fnv1a-1024 }
;
{ $subsections
fnv1-32
fnv1a-32
}
{ $subsections
fnv1-64
fnv1a-64
}
{ $subsections
fnv1-128
fnv1a-128
}
{ $subsections
fnv1-256
fnv1a-256
}
{ $subsections
fnv1-512
fnv1a-512
}
{ $subsections
fnv1-1024
fnv1a-1024
} ;
ABOUT: "checksums.fnv1"

View File

@ -6,6 +6,6 @@ HELP: md5
ARTICLE: "checksums.md5" "MD5 checksum"
"The MD5 checksum algorithm implements a one-way hash function. While it is widely used, many weaknesses are known and it should not be used in new applications (" { $url "http://www.schneier.com/blog/archives/2005/03/more_hash_funct.html" } ")."
{ $subsection md5 } ;
{ $subsections md5 } ;
ABOUT: "checksums.md5"

View File

@ -1,7 +1,8 @@
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: byte-arrays checksums checksums.md5 io.encodings.binary
io.streams.byte-array kernel math namespaces tools.test ;
io.streams.byte-array kernel math namespaces tools.test
sequences ;
IN: checksums.md5.tests
[ "d41d8cd98f00b204e9800998ecf8427e" ] [ "" >byte-array md5 checksum-bytes hex-string ] unit-test
@ -33,3 +34,9 @@ IN: checksums.md5.tests
<md5-state> "asdf" binary <byte-reader> add-checksum-stream
[ get-checksum ] [ get-checksum ] bi =
] unit-test
[
t
] [
{ "abcd" "efg" } md5 checksum-lines length 16 =
] unit-test

View File

@ -21,14 +21,16 @@ HELP: unknown-digest
ARTICLE: "checksums.openssl" "OpenSSL checksums"
"The OpenSSL library provides a large number of efficient checksum (message digest) algorithms which may be used independently of its SSL functionality."
{ $subsection openssl-checksum }
{ $subsections openssl-checksum }
"Constructing a checksum from a known name:"
{ $subsection <openssl-checksum> }
{ $subsections <openssl-checksum> }
"Two utility words:"
{ $subsection openssl-md5 }
{ $subsection openssl-sha1 }
{ $subsections
openssl-md5
openssl-sha1
}
"An error thrown if the digest name is unrecognized:"
{ $subsection unknown-digest }
{ $subsections unknown-digest }
"An example where we compute the SHA1 checksum of a string using the OpenSSL implementation of SHA1:"
{ $example "USING: byte-arrays checksums checksums.openssl ;" "\"hello world\" >byte-array openssl-sha1 checksum-bytes hex-string ." "\"2aae6c35c94fcfb415dbe95f408b9ce91ee846ed\"" }
"If we use the Factor implementation, we get the same result, just slightly slower:"

View File

@ -1,4 +1,4 @@
! Copyright (C) 2008 Slava Pestov
! copyright (C) 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: accessors byte-arrays alien.c-types alien.data kernel
continuations destructors sequences io openssl openssl.libcrypto
@ -23,10 +23,10 @@ TUPLE: evp-md-context < disposable handle ;
: <evp-md-context> ( -- ctx )
evp-md-context new-disposable
EVP_MD_CTX <struct> dup EVP_MD_CTX_init >>handle ;
EVP_MD_CTX_create >>handle ;
M: evp-md-context dispose*
handle>> EVP_MD_CTX_cleanup drop ;
handle>> EVP_MD_CTX_destroy ;
: with-evp-md-context ( quot -- )
maybe-init-ssl [ <evp-md-context> ] dip with-disposal ; inline

View File

@ -10,9 +10,11 @@ HELP: sha-256
ARTICLE: "checksums.sha" "SHA-2 checksum"
"The SHA family of checksum algorithms are one-way hashes useful for checksumming data. SHA-1 is considered insecure, while SHA-2 It is generally considered to be pretty strong." $nl
"SHA-2 checksums:"
{ $subsection sha-224 }
{ $subsection sha-256 }
{ $subsections
sha-224
sha-256
}
"SHA-1 checksum:"
{ $subsection sha1 } ;
{ $subsections sha1 } ;
ABOUT: "checksums.sha"

View File

@ -51,14 +51,20 @@ HELP: rotate-circular
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:"
{ $subsection <circular> }
{ $subsection <circular-string> }
{ $subsection <growing-circular> }
{ $subsections
<circular>
<circular-string>
<growing-circular>
}
"Changing the start index:"
{ $subsection change-circular-start }
{ $subsection rotate-circular }
{ $subsections
change-circular-start
rotate-circular
}
"Pushing new elements:"
{ $subsection push-circular }
{ $subsection push-growing-circular } ;
{ $subsections
push-circular
push-growing-circular
} ;
ABOUT: "circular"

View File

@ -0,0 +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 ;
IN: classes.struct.bit-accessors.test
[ t ] [ 20 random 20 random bit-reader infer (( alien -- n )) effect= ] unit-test
[ t ] [ 20 random 20 random bit-writer infer (( n alien -- )) effect= ] unit-test

View File

@ -0,0 +1,46 @@
! Copyright (C) 2009 Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences math fry locals math.order alien.accessors ;
IN: classes.struct.bit-accessors
! Bitfield accessors are little-endian on all platforms
! Why not? It's unspecified in C
: ones-between ( start end -- n )
[ 2^ 1 - ] bi@ swap bitnot bitand ;
:: manipulate-bits ( offset bits step-quot -- quot shift-amount offset' bits' )
offset 8 /mod :> start-bit :> i
start-bit bits + 8 min :> end-bit
start-bit end-bit ones-between :> mask
end-bit start-bit - :> used-bits
i mask start-bit step-quot call( i mask start-bit -- quot )
used-bits
i 1 + 8 *
bits used-bits - ; inline
:: bit-manipulator ( offset bits
step-quot: ( i mask start-bit -- quot )
combine-quot: ( prev-quot shift-amount next-quot -- quot )
-- quot )
offset bits step-quot manipulate-bits
dup zero? [ 3drop ] [
step-quot combine-quot bit-manipulator
combine-quot call( prev shift next -- quot )
] if ; inline recursive
: bit-reader ( offset bits -- quot: ( alien -- n ) )
[ neg '[ _ alien-unsigned-1 _ bitand _ shift ] ]
[ swap '[ _ _ bi _ shift bitor ] ]
bit-manipulator ;
:: write-bits ( n alien i mask start-bit -- )
n start-bit shift mask bitand
alien i alien-unsigned-1 mask bitnot bitand
bitor alien i set-alien-unsigned-1 ; inline
: bit-writer ( offset bits -- quot: ( n alien -- ) )
[ '[ _ _ _ write-bits ] ]
[ '[ _ [ [ _ neg shift ] dip @ ] 2bi ] ]
bit-manipulator ;

View File

@ -23,6 +23,11 @@ IN: classes.struct.prettyprint
[ type>> pprint-c-type ]
[ read-only>> [ \ read-only pprint-word ] when ]
[ initial>> [ \ initial: pprint-word pprint* ] when* ]
[
dup struct-bit-slot-spec?
[ \ bits: pprint-word bits>> pprint* ]
[ drop ] if
]
} cleave block>
\ } pprint-word block> ;

View File

@ -95,21 +95,84 @@ HELP: struct
HELP: struct-class
{ $class-description "The metaclass of all " { $link struct } " classes." } ;
ARTICLE: "classes.struct" "Struct classes"
{ $link struct } " classes are similar to " { $link tuple } "s, but their slots exhibit value semantics, and they are backed by a contiguous structured block of memory. Structs can be used for structured access to C memory or Factor byte arrays and for passing struct values in and out of the FFI. Struct types are defined using a syntax similar to tuple syntax:"
{ $subsection POSTPONE: STRUCT: }
ARTICLE: "classes.struct.examples" "Struct class examples"
"A struct with a variety of fields:"
{ $code
"USING: alien.c-types classes.struct ;"
""
"STRUCT: test-struct"
" { i int }"
" { chicken char[16] }"
" { data void* } ;"
}
"Creating a new instance of this struct, and printing out:"
{ $code "test-struct <struct> ." }
"Creating a new instance with slots initialized from the stack:"
{ $code
"USING: libc specialized-arrays ;"
"SPECIALIZED-ARRAY: char"
""
"42"
"\"Hello, chicken.\" >char-array"
"1024 malloc"
"test-struct <struct-boa> ."
} ;
ARTICLE: "classes.struct.define" "Defining struct classes"
"Struct classes are defined using a syntax similar to the " { $link POSTPONE: TUPLE: } " syntax for defining tuple classes:"
{ $subsections POSTPONE: STRUCT: }
"Union structs are also supported, which behave like structs but share the same memory for all the slots."
{ $subsections POSTPONE: UNION-STRUCT: } ;
ARTICLE: "classes.struct.create" "Creating instances of structs"
"Structs can be allocated with " { $link new } "- and " { $link boa } "-like constructor words. Additional words are provided for building structs from C memory and from existing buffers:"
{ $subsection <struct> }
{ $subsection <struct-boa> }
{ $subsection malloc-struct }
{ $subsection memory>struct }
{ $subsections
<struct>
<struct-boa>
malloc-struct
memory>struct
}
"When the contents of a struct will be immediately reset, faster primitive words are available that will create a struct without initializing its contents:"
{ $subsection (struct) }
{ $subsection (malloc-struct) }
"Structs have literal syntax like tuples:"
{ $subsection POSTPONE: S{ }
"Union structs are also supported, which behave like structs but share the same memory for all the type's slots."
{ $subsection POSTPONE: UNION-STRUCT: }
;
{ $subsections
(struct)
(malloc-struct)
}
"Structs have literal syntax, similar to " { $link POSTPONE: T{ } " for tuples:"
{ $subsections POSTPONE: S{ } ;
ARTICLE: "classes.struct.c" "Passing structs to C functions"
"Structs can be passed and returned by value, or by reference."
$nl
"If a parameter is declared with a struct type, the parameter is passed by value. To pass a struct by reference, declare a parameter with a pointer to struct type."
$nl
"If a C function is declared as returning a struct type, the struct is returned by value, and wrapped in an instance of the correct struct class automatically. If a C function is declared as returning a pointer to a struct, it will return an " { $link alien } " instance. This is because there is no way to distinguish between a pointer to a single struct and a pointer to an array of zero or more structs. It is up to the caller to wrap it in a struct, or a specialized array of structs, respectively."
$nl
"An example of a struct declaration:"
{ $code
"USING: alien.c-types classes.struct ;"
""
"STRUCT: Point"
" { x int }"
" { y int }"
" { z int } ;"
}
"A C function which returns a struct by value:"
{ $code
"USING: alien.syntax ;"
"FUNCTION: Point give_me_a_point ( char* description ) ;"
}
"A C function which takes a struct parameter by reference:"
{ $code
"FUNCTION: void print_point ( Point* p ) ;"
} ;
ARTICLE: "classes.struct" "Struct classes"
"The " { $vocab-link "classes.struct" } " vocabulary implements " { $link struct } " classes. They are similar to " { $link tuple } " classes, but their slots exhibit value semantics, and they are backed by a contiguous structured block of memory. Structs can be used for space-efficient storage of data in the Factor heap, as well as for passing data to and from C libraries using the " { $link "alien" } "."
{ $subsections
"classes.struct.examples"
"classes.struct.define"
"classes.struct.create"
"classes.struct.c"
} ;
ABOUT: "classes.struct"

View File

@ -3,7 +3,7 @@ USING: accessors alien alien.c-types alien.data ascii
assocs byte-arrays classes.struct classes.tuple.private
combinators compiler.tree.debugger compiler.units destructors
io.encodings.utf8 io.pathnames io.streams.string kernel libc
literals math mirrors multiline namespaces prettyprint
literals math mirrors namespaces prettyprint
prettyprint.config see sequences specialized-arrays system
tools.test parser lexer eval layouts ;
FROM: math => float ;
@ -183,18 +183,18 @@ STRUCT: struct-test-string-ptr
] with-scope
] unit-test
[ <" USING: alien.c-types classes.struct ;
[ "USING: alien.c-types classes.struct ;
IN: classes.struct.tests
STRUCT: struct-test-foo
{ x char initial: 0 } { y int initial: 123 } { z bool } ;
"> ]
" ]
[ [ struct-test-foo see ] with-string-writer ] unit-test
[ <" USING: alien.c-types classes.struct ;
[ "USING: alien.c-types classes.struct ;
IN: classes.struct.tests
UNION-STRUCT: struct-test-float-and-bits
{ f float initial: 0.0 } { bits uint initial: 0 } ;
"> ]
" ]
[ [ struct-test-float-and-bits see ] with-string-writer ] unit-test
[ {
@ -352,3 +352,16 @@ STRUCT: struct-that's-a-word { x int } ;
] unit-test
[ f ] [ "a-struct" c-types get key? ] unit-test
STRUCT: bit-field-test
{ a uint bits: 12 }
{ b int bits: 2 }
{ c char } ;
[ S{ bit-field-test f 0 0 0 } ] [ bit-field-test <struct> ] unit-test
[ S{ bit-field-test f 1 -2 3 } ] [ bit-field-test <struct> 1 >>a 2 >>b 3 >>c ] unit-test
[ 4095 ] [ bit-field-test <struct> 8191 >>a a>> ] unit-test
[ 1 ] [ bit-field-test <struct> 1 >>b b>> ] unit-test
[ -2 ] [ bit-field-test <struct> 2 >>b b>> ] unit-test
[ 1 ] [ bit-field-test <struct> 257 >>c c>> ] unit-test
[ 3 ] [ bit-field-test heap-size ] unit-test

View File

@ -1,4 +1,4 @@
! (c)Joe Groff bsd license
! (c)Joe Groff, Daniel Ehrenberg bsd license
USING: accessors alien alien.c-types alien.data alien.parser arrays
byte-arrays classes classes.parser classes.tuple classes.tuple.parser
classes.tuple.private combinators combinators.short-circuit
@ -6,7 +6,9 @@ combinators.smart cpu.architecture definitions functors.backend
fry generalizations generic.parser kernel kernel.private lexer
libc locals macros make math math.order parser quotations
sequences slots slots.private specialized-arrays vectors words
summary namespaces assocs vocabs.parser ;
summary namespaces assocs vocabs.parser math.functions
classes.struct.bit-accessors bit-arrays ;
QUALIFIED: math
IN: classes.struct
SPECIALIZED-ARRAY: uchar
@ -22,14 +24,19 @@ TUPLE: struct
TUPLE: struct-slot-spec < slot-spec
type ;
! For a struct-bit-slot-spec, offset is in bits, not bytes
TUPLE: struct-bit-slot-spec < struct-slot-spec
bits signed? ;
PREDICATE: struct-class < tuple-class
superclass \ struct eq? ;
M: struct-class valid-superclass? drop f ;
GENERIC: struct-slots ( struct-class -- slots )
SLOT: fields
M: struct-class struct-slots "struct-slots" word-prop ;
: struct-slots ( struct-class -- slots )
"c-type" word-prop fields>> ;
! struct allocation
@ -83,14 +90,36 @@ MACRO: <struct-boa> ( class -- quot: ( ... -- struct ) )
: pad-struct-slots ( values class -- values' class )
[ struct-slots [ initial>> ] map over length tail append ] keep ;
: (reader-quot) ( slot -- quot )
: sign-extend ( n bits -- n' )
! formula from:
! http://guru.multimedia.cx/fast-sign-extension/
1 - -1 swap shift [ + ] keep bitxor ; inline
: sign-extender ( signed? bits -- quot )
'[ _ [ _ sign-extend ] when ] ;
GENERIC: (reader-quot) ( slot -- quot )
M: struct-slot-spec (reader-quot)
[ type>> c-type-getter-boxer ]
[ offset>> [ >c-ptr ] swap suffix ] bi prepend ;
: (writer-quot) ( slot -- quot )
M: struct-bit-slot-spec (reader-quot)
[ [ offset>> ] [ bits>> ] bi bit-reader ]
[ [ signed?>> ] [ bits>> ] bi sign-extender ]
bi compose
[ >c-ptr ] prepose ;
GENERIC: (writer-quot) ( slot -- quot )
M: struct-slot-spec (writer-quot)
[ type>> c-setter ]
[ offset>> [ >c-ptr ] swap suffix ] bi prepend ;
M: struct-bit-slot-spec (writer-quot)
[ offset>> ] [ bits>> ] bi bit-writer
[ >c-ptr ] prepose ;
: (boxer-quot) ( class -- quot )
'[ _ memory>struct ] ;
@ -103,6 +132,8 @@ M: struct-class boa>object
[ <struct> ] [ struct-slots ] bi
[ [ (writer-quot) call( value struct -- ) ] with 2each ] curry keep ;
M: struct-class initial-value* <struct> ; inline
! Struct slot accessors
GENERIC: struct-slot-values ( struct -- sequence )
@ -113,6 +144,9 @@ M: struct-class reader-quot
M: struct-class writer-quot
nip (writer-quot) ;
: offset-of ( field struct -- offset )
struct-slots slot-named offset>> ; inline
! c-types
TUPLE: struct-c-type < abstract-c-type
@ -170,31 +204,34 @@ M: struct-c-type c-struct? drop t ;
[ \ clone-underlying swap literalize \ memory>struct [ ] 3sequence ] bi
define-inline-method ;
: c-type-for-class ( class -- c-type )
struct-c-type new swap {
[ drop byte-array >>class ]
[ >>boxed-class ]
[ struct-slots >>fields ]
[ "struct-size" word-prop >>size ]
[ "struct-align" word-prop >>align ]
[ (unboxer-quot) >>unboxer-quot ]
[ (boxer-quot) >>boxer-quot ]
} cleave ;
:: c-type-for-class ( class slots size align -- c-type )
struct-c-type new
byte-array >>class
class >>boxed-class
slots >>fields
size >>size
align >>align
class (unboxer-quot) >>unboxer-quot
class (boxer-quot) >>boxer-quot ;
: align-offset ( offset class -- offset' )
c-type-align align ;
GENERIC: align-offset ( offset class -- offset' )
M: struct-slot-spec align-offset
[ type>> c-type-align 8 * align ] keep
[ [ 8 /i ] dip (>>offset) ] [ type>> heap-size 8 * + ] 2bi ;
M: struct-bit-slot-spec align-offset
[ (>>offset) ] [ bits>> + ] 2bi ;
: struct-offsets ( slots -- size )
0 [
[ type>> align-offset ] keep
[ (>>offset) ] [ type>> heap-size + ] 2bi
] reduce ;
0 [ align-offset ] reduce 8 align 8 /i ;
: union-struct-offsets ( slots -- size )
[ 0 >>offset type>> heap-size ] [ max ] map-reduce ;
1 [ 0 >>offset type>> heap-size max ] reduce ;
: struct-align ( slots -- align )
[ type>> c-type-align ] [ max ] map-reduce ;
[ struct-bit-slot-spec? not ] filter
1 [ type>> c-type-align max ] reduce ;
PRIVATE>
M: struct byte-length class "struct-size" word-prop ; foldable
@ -202,50 +239,55 @@ M: struct byte-length class "struct-size" word-prop ; foldable
! class definition
<PRIVATE
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
[ <displaced-alien> *uchar zero? ] curry all? ;
: struct-needs-prototype? ( class -- ? )
struct-slots [ initial>> binary-zero? ] all? not ;
: make-struct-prototype ( class -- prototype )
[ "struct-size" word-prop <byte-array> ]
[ memory>struct ]
[ struct-slots ] tri
[
[ initial>> ]
[ (writer-quot) ] bi
over [ swapd [ call( value struct -- ) ] curry keep ] [ 2drop ] if
] each ;
dup struct-needs-prototype? [
[ "c-type" word-prop size>> <byte-array> ]
[ memory>struct ]
[ struct-slots ] tri
[
[ initial>> ]
[ (writer-quot) ] bi
over [ swapd [ call( value struct -- ) ] curry keep ] [ 2drop ] if
] each
] [ drop f ] if ;
: (struct-methods) ( class -- )
[ (define-struct-slot-values-method) ]
[ (define-clone-method) ]
bi ;
: (struct-word-props) ( class slots size align -- )
[
[ "struct-slots" set-word-prop ]
[ define-accessors ] 2bi
]
[ "struct-size" set-word-prop ]
[ "struct-align" set-word-prop ] tri-curry*
[ tri ] 3curry
[ dup make-struct-prototype "prototype" set-word-prop ]
[ (struct-methods) ] tri ;
: check-struct-slots ( slots -- )
[ type>> c-type drop ] each ;
: redefine-struct-tuple-class ( class -- )
[ dup class? [ forget-class ] [ drop ] if ] [ struct f define-tuple-class ] bi ;
: (define-struct-class) ( class slots offsets-quot -- )
[
empty?
[ struct-must-have-slots ]
[ redefine-struct-tuple-class ] if
]
swap '[
make-slots dup
[ check-struct-slots ] _ [ struct-align [ align ] keep ] tri
(struct-word-props)
]
[ drop [ c-type-for-class ] keep typedef ] 2tri ; inline
:: (define-struct-class) ( class slots offsets-quot -- )
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
class slot-specs size alignment c-type-for-class :> c-type
c-type class typedef
class slot-specs define-accessors
class size "struct-size" set-word-prop
class dup make-struct-prototype "prototype" set-word-prop
class (struct-methods) ; inline
PRIVATE>
: define-struct-class ( class slots -- )
@ -263,11 +305,43 @@ ERROR: invalid-struct-slot token ;
c-type c-type-boxed-class
dup \ byte-array = [ drop \ c-ptr ] when ;
SYMBOL: bits:
<PRIVATE
ERROR: bad-type-for-bits type ;
:: set-bits ( slot-spec n -- slot-spec )
struct-bit-slot-spec new
n >>bits
slot-spec type>> {
{ int [ t ] }
{ uint [ f ] }
[ bad-type-for-bits ]
} case >>signed?
slot-spec name>> >>name
slot-spec class>> >>class
slot-spec type>> >>type
slot-spec read-only>> >>read-only
slot-spec initial>> >>initial ;
: peel-off-struct-attributes ( slot-spec array -- slot-spec array )
dup empty? [
unclip {
{ initial: [ [ first >>initial ] [ rest ] bi ] }
{ read-only [ [ t >>read-only ] dip ] }
{ bits: [ [ first set-bits ] [ rest ] bi ] }
[ bad-slot-attribute ]
} case
] unless ;
PRIVATE>
: <struct-slot-spec> ( name c-type attributes -- slot-spec )
[ struct-slot-spec new ] 3dip
[ >>name ]
[ [ >>type ] [ struct-slot-class >>class ] bi ]
[ [ dup empty? ] [ peel-off-attributes ] until drop ] tri* ;
[ [ dup empty? ] [ peel-off-struct-attributes ] until drop ] tri* ;
<PRIVATE
: parse-struct-slot ( -- slot )

View File

@ -41,14 +41,18 @@ HELP: objc-error
ARTICLE: "cocoa-application-utils" "Cocoa application utilities"
"Utilities:"
{ $subsection NSApp }
{ $subsection add-observer }
{ $subsection remove-observer }
{ $subsection install-delegate }
{ $subsections
NSApp
add-observer
remove-observer
install-delegate
}
"Combinators:"
{ $subsection cocoa-app }
{ $subsection with-autorelease-pool }
{ $subsection with-cocoa } ;
{ $subsections
cocoa-app
with-autorelease-pool
with-cocoa
} ;
IN: cocoa.application
ABOUT: "cocoa-application-utils"

View File

@ -25,15 +25,19 @@ HELP: IMPORT:
ARTICLE: "objc-calling" "Calling Objective C code"
"Before an Objective C class can be used, it must be imported; by default, a small set of common classes are imported automatically, but additional classes can be imported as needed."
{ $subsection POSTPONE: IMPORT: }
{ $subsections POSTPONE: IMPORT: }
"Every imported Objective C class has as corresponding class word in the " { $vocab-link "cocoa.classes" } " vocabulary. Class words push the class object in the stack, allowing class methods to be invoked."
$nl
"Messages can be sent to classes and instances using a pair of parsing words:"
{ $subsection POSTPONE: -> }
{ $subsection POSTPONE: SUPER-> }
{ $subsections
POSTPONE: ->
POSTPONE: SUPER->
}
"These parsing words are actually syntax sugar for a pair of ordinary words; they can be used instead of the parsing words if the selector name is dynamically computed:"
{ $subsection send }
{ $subsection super-send } ;
{ $subsections
send
super-send
} ;
ARTICLE: "cocoa" "Cocoa bridge"
"The " { $vocab-link "cocoa" } " vocabulary implements a Factor-Cocoa bridge for Mac OS X (GNUstep is not supported)."
@ -41,14 +45,18 @@ $nl
"The lowest layer uses the " { $link "alien" } " to define bindings for the various functions in Apple's Objective-C runtime. This is defined in the " { $vocab-link "cocoa.runtime" } " vocabulary."
$nl
"On top of this, a dynamic message send facility is built:"
{ $subsection "objc-calling" }
{ $subsection "objc-subclassing" }
{ $subsections
"objc-calling"
"objc-subclassing"
}
"A utility library is built to faciliate the development of Cocoa applications in Factor:"
{ $subsection "cocoa-application-utils" }
{ $subsection "cocoa-dialogs" }
{ $subsection "cocoa-pasteboard-utils" }
{ $subsection "cocoa-view-utils" }
{ $subsection "cocoa-window-utils" } ;
{ $subsections
"cocoa-application-utils"
"cocoa-dialogs"
"cocoa-pasteboard-utils"
"cocoa-view-utils"
"cocoa-window-utils"
} ;
IN: cocoa
ABOUT: "cocoa"

View File

@ -19,11 +19,15 @@ HELP: save-panel
ARTICLE: "cocoa-dialogs" "Cocoa file dialogs"
"Open dialogs:"
{ $subsection <NSOpenPanel> }
{ $subsection open-panel }
{ $subsections
<NSOpenPanel>
open-panel
}
"Save dialogs:"
{ $subsection <NSSavePanel> }
{ $subsection save-panel } ;
{ $subsections
<NSSavePanel>
save-panel
} ;
IN: cocoa.dialogs
ABOUT: "cocoa-dialogs"

View File

@ -14,9 +14,11 @@ HELP: set-pasteboard-string
{ $description "Sets the contents of the pasteboard." } ;
ARTICLE: "cocoa-pasteboard-utils" "Cocoa pasteboard utilities"
{ $subsection pasteboard-string? }
{ $subsection pasteboard-string }
{ $subsection set-pasteboard-string } ;
{ $subsections
pasteboard-string?
pasteboard-string
set-pasteboard-string
} ;
IN: cocoa.pasteboard
ABOUT: "cocoa-pasteboard-utils"

View File

@ -1,6 +1,6 @@
! Copyright (C) 2006, 2007 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: alien.syntax classes.struct ;
USING: alien.c-types alien.syntax classes.struct ;
IN: cocoa.runtime
TYPEDEF: void* SEL

View File

@ -37,9 +37,9 @@ HELP: CLASS:
ARTICLE: "objc-subclassing" "Subclassing Objective C classes"
"Objective C classes can be subclassed, with new methods defined in Factor, using a parsing word:"
{ $subsection POSTPONE: CLASS: }
{ $subsections POSTPONE: CLASS: }
"This word is actually syntax sugar for an ordinary word:"
{ $subsection define-objc-class }
{ $subsections define-objc-class }
"Objective C class definitions are saved in the image. If the image is saved and Factor is restarted with the saved image, custom class definitions are made available to the Objective C runtime when they are first accessed from within Factor." ;
IN: cocoa.subclassing

View File

@ -1,7 +1,7 @@
! Copyright (C) 2006, 2009 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: alien.c-types alien.syntax combinators kernel layouts
classes.struct core-graphics.types ;
classes.struct cocoa.runtime core-graphics.types ;
IN: cocoa.types
TYPEDEF: long NSInteger

View File

@ -14,9 +14,11 @@ HELP: mouse-location
{ $description "Outputs the current mouse location." } ;
ARTICLE: "cocoa-view-utils" "Cocoa view utilities"
{ $subsection <GLView> }
{ $subsection view-dim }
{ $subsection mouse-location } ;
{ $subsections
<GLView>
view-dim
mouse-location
} ;
IN: cocoa.views
ABOUT: "cocoa-view-utils"

View File

@ -40,7 +40,9 @@ CONSTANT: NSOpenGLPFAScreenMask 84
CONSTANT: NSOpenGLPFAPixelBuffer 90
CONSTANT: NSOpenGLPFAAllowOfflineRenderers 96
CONSTANT: NSOpenGLPFAVirtualScreenCount 128
CONSTANT: NSOpenGLCPSwapInterval 222
CONSTANT: NSOpenGLCPSurfaceOpacity 236
: <GLView> ( class dim pixel-format -- view )
[ -> alloc ]

View File

@ -10,8 +10,10 @@ HELP: <ViewWindow>
{ $description "Creates a new " { $snippet "NSWindow" } " with the specified dimensions, containing the given view." } ;
ARTICLE: "cocoa-window-utils" "Cocoa window utilities"
{ $subsection <NSWindow> }
{ $subsection <ViewWindow> } ;
{ $subsections
<NSWindow>
<ViewWindow>
} ;
IN: cocoa.windows
ABOUT: "cocoa-window-utils"

View File

@ -5,11 +5,12 @@ sequences math.bitwise ;
IN: cocoa.windows
! Window styles
CONSTANT: NSBorderlessWindowMask 0
CONSTANT: NSTitledWindowMask 1
CONSTANT: NSClosableWindowMask 2
CONSTANT: NSMiniaturizableWindowMask 4
CONSTANT: NSResizableWindowMask 8
CONSTANT: NSBorderlessWindowMask 0
CONSTANT: NSTitledWindowMask 1
CONSTANT: NSClosableWindowMask 2
CONSTANT: NSMiniaturizableWindowMask 4
CONSTANT: NSResizableWindowMask 8
CONSTANT: NSTexturedBackgroundWindowMask 256
! Additional panel-only styles
CONSTANT: NSUtilityWindowMask 16
@ -26,7 +27,7 @@ CONSTANT: NSBackingStoreBuffered 2
-> initWithContentRect:styleMask:backing:defer: ;
: class-for-style ( style -- NSWindow/NSPanel )
HEX: 1ff0 bitand zero? NSWindow NSPanel ? ;
HEX: 1ef0 bitand zero? NSWindow NSPanel ? ;
: <ViewWindow> ( view rect style -- window )
dup class-for-style <NSWindow> [ swap -> setContentView: ] keep

View File

@ -13,7 +13,7 @@ HELP: >rgba
ARTICLE: "colors.protocol" "Color protocol"
"Abstract superclass for colors:"
{ $subsection color }
{ $subsections color }
"All color objects must are required to implement a method on the " { $link >rgba } " generic word."
$nl
"Optionally, they can provide methods on the accessors " { $link red>> } ", " { $link green>> } ", " { $link blue>> } " and " { $link alpha>> } ", either by defining slots with the appropriate names, or with methods which calculate the color component values. The accessors should return color components which are real numbers in the range between 0 and 1."
@ -24,15 +24,19 @@ ARTICLE: "colors" "Colors"
"The " { $vocab-link "colors" } " vocabulary defines a protocol for colors, with a concrete implementation for RGBA colors. This vocabulary is used by " { $vocab-link "io.styles" } ", " { $vocab-link "ui" } " and other vocabularies, but it is independent of them."
$nl
"RGBA colors with floating point components in the range " { $snippet "[0,1]" } ":"
{ $subsection rgba }
{ $subsection <rgba> }
{ $subsections
rgba
<rgba>
}
"Converting a color to RGBA:"
{ $subsection >rgba }
{ $subsections >rgba }
"Extracting RGBA components of colors:"
{ $subsection >rgba-components }
{ $subsections >rgba-components }
"Further topics:"
{ $subsection "colors.protocol" }
{ $subsection "colors.constants" }
{ $subsections
"colors.protocol"
"colors.constants"
}
{ $vocab-subsection "Grayscale colors" "colors.gray" }
{ $vocab-subsection "HSV colors" "colors.hsv" } ;

View File

@ -24,8 +24,10 @@ HELP: COLOR:
ARTICLE: "colors.constants" "Standard color database"
"The " { $vocab-link "colors.constants" } " vocabulary bundles the X11 " { $snippet "rgb.txt" } " database and Factor's " { $snippet "factor-colors.txt" } " theme database to provide words for looking up color values by name."
{ $subsection named-color }
{ $subsection named-colors }
{ $subsection POSTPONE: COLOR: } ;
{ $subsections
named-color
named-colors
POSTPONE: COLOR:
} ;
ABOUT: "colors.constants"

View File

@ -4,3 +4,4 @@
172 167 147 FactorDarkTan
81 91 105 FactorLightSlateBlue
55 62 72 FactorDarkSlateBlue
0 51 0 FactorDarkGreen

View File

@ -3,7 +3,9 @@ IN: colors.gray
ARTICLE: "colors.gray" "Grayscale colors"
"The " { $vocab-link "colors.gray" } " vocabulary implements grayscale colors. These colors hold a single value, and respond to " { $link red>> } ", " { $link green>> } ", " { $link blue>> } " with that value. They also have an independent alpha channel, " { $link alpha>> } "."
{ $subsection gray }
{ $subsection <gray> } ;
{ $subsections
gray
<gray>
} ;
ABOUT: "colors.gray"

View File

@ -6,8 +6,10 @@ HELP: hsva
ARTICLE: "colors.hsv" "HSV colors"
"The " { $vocab-link "colors.hsv" } " vocabulary implements colors specified by their hue, saturation, and value, together with an alpha channel."
{ $subsection hsva }
{ $subsection <hsva> }
{ $subsections
hsva
<hsva>
}
{ $see-also "colors" } ;
ABOUT: "colors.hsv"

View File

@ -25,9 +25,11 @@ HELP: <flipped>
ARTICLE: "columns" "Column sequences"
"A " { $emphasis "column" } " presents a column of a matrix represented as a sequence of rows:"
{ $subsection column }
{ $subsection <column> }
{ $subsections
column
<column>
}
"A utility word:"
{ $subsection <flipped> } ;
{ $subsections <flipped> } ;
ABOUT: "columns"

View File

@ -51,18 +51,24 @@ HELP: n||
ARTICLE: "combinators.short-circuit" "Short-circuit combinators"
"The " { $vocab-link "combinators.short-circuit" } " vocabulary stops a computation early once a condition is met." $nl
"AND combinators:"
{ $subsection 0&& }
{ $subsection 1&& }
{ $subsection 2&& }
{ $subsection 3&& }
{ $subsections
0&&
1&&
2&&
3&&
}
"OR combinators:"
{ $subsection 0|| }
{ $subsection 1|| }
{ $subsection 2|| }
{ $subsection 3|| }
{ $subsections
0||
1||
2||
3||
}
"Generalized combinators:"
{ $subsection n&& }
{ $subsection n|| }
{ $subsections
n&&
n||
}
;
ABOUT: "combinators.short-circuit"

View File

@ -31,8 +31,8 @@ ARTICLE: "combinators.short-circuit.smart" "Smart short-circuit combinators"
"The " { $vocab-link "combinators.short-circuit.smart" } " vocabulary is similar to " { $vocab-link "combinators.short-circuit" } " except the combinators here infer the number of inputs that the sequence of quotations takes."
$nl
"Generalized AND:"
{ $subsection && }
{ $subsections && }
"Generalized OR:"
{ $subsection || } ;
{ $subsections || } ;
ABOUT: "combinators.short-circuit.smart"

View File

@ -1,7 +1,7 @@
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: help.markup help.syntax kernel quotations math sequences
multiline stack-checker ;
stack-checker ;
IN: combinators.smart
HELP: input<sequence
@ -26,10 +26,10 @@ HELP: output>array
{ $description "Infers the number or outputs from the quotation and constructs an array from those outputs." }
{ $examples
{ $example
<" USING: combinators combinators.smart math prettyprint ;
"USING: combinators combinators.smart math prettyprint ;
9 [
{ [ 1 - ] [ 1 + ] [ sq ] } cleave
] output>array .">
] output>array ."
"{ 8 10 81 }"
}
} ;
@ -119,20 +119,26 @@ HELP: keep-inputs
ARTICLE: "combinators.smart" "Smart combinators"
"A " { $emphasis "smart combinator" } " is a macro which reflects on the stack effect of an input quotation. The " { $vocab-link "combinators.smart" } " vocabulary implements a few simple smart combinators which look at the static stack effects of input quotations and generate code which produces or consumes the relevant number of stack values." $nl
"Call a quotation and discard all output values or preserve all input values:"
{ $subsection drop-outputs }
{ $subsection keep-inputs }
{ $subsections
drop-outputs
keep-inputs
}
"Take all input values from a sequence:"
{ $subsection input<sequence }
{ $subsections input<sequence }
"Store all output values to a sequence:"
{ $subsection output>sequence }
{ $subsection output>array }
{ $subsections
output>sequence
output>array
}
"Reducing the set of output values:"
{ $subsection reduce-outputs }
{ $subsections reduce-outputs }
"Summing output values:"
{ $subsection sum-outputs }
{ $subsections sum-outputs }
"Concatenating output values:"
{ $subsection append-outputs }
{ $subsection append-outputs-as }
{ $subsections
append-outputs
append-outputs-as
}
"New smart combinators can be created by defining " { $link "macros" } " which call " { $link infer } "." ;
ABOUT: "combinators.smart"

View File

@ -25,7 +25,7 @@ HELP: (command-line)
{ $description "Outputs the command line parameters which were passed to the Factor VM on startup." } ;
HELP: command-line
{ $var-description "The command line parameters which follow the name of the script on the command line." } ;
{ $var-description "When Factor is run with a script, this variable contains command line parameters which follow the name of the script on the command line. In deployed applications, it contains the entire command line. In all other cases it is set to " { $link f } "." } ;
HELP: main-vocab-hook
{ $var-description "Global variable holding a quotation which outputs a vocabulary name. UI backends set this so that the UI can automatically start if the prerequisites are met (for example, " { $snippet "$DISPLAY" } " being set on X11)." } ;
@ -47,7 +47,6 @@ ARTICLE: "runtime-cli-args" "Command line switches for the VM"
{ { $snippet "-i=" { $emphasis "image" } } { "Specifies the image file to use; see " { $link "images" } } }
{ { $snippet "-datastack=" { $emphasis "n" } } "Data stack size, kilobytes" }
{ { $snippet "-retainstack=" { $emphasis "n" } } "Retain stack size, kilobytes" }
{ { $snippet "-generations=" { $emphasis "n" } } "Number of generations, must equal 1, 2 or 3" }
{ { $snippet "-young=" { $emphasis "n" } } { "Size of youngest generation (0), megabytes" } }
{ { $snippet "-aging=" { $emphasis "n" } } "Size of aging generation (1), megabytes" }
{ { $snippet "-tenured=" { $emphasis "n" } } "Size of oldest generation (2), megabytes" }
@ -99,26 +98,28 @@ ARTICLE: "factor-boot-rc" "Bootstrap initialization file"
"The botstrap initialization file is named " { $snippet "factor-boot-rc" } " on Windows and " { $snippet ".factor-boot-rc" } " on Unix. This file can contain " { $link require } " calls for vocabularies you use frequently, and other such long-running tasks that you do not want to perform every time Factor starts."
$nl
"A word to run this file from an existing Factor session:"
{ $subsection run-bootstrap-init }
{ $subsections run-bootstrap-init }
"For example, if you changed " { $snippet ".factor-boot-rc" } " and do not want to bootstrap again, you can just invoke " { $link run-bootstrap-init } " in the listener." ;
ARTICLE: "factor-rc" "Startup initialization file"
"The startup initialization file is named " { $snippet "factor-rc" } " on Windows and " { $snippet ".factor-rc" } " on Unix. If it exists, it is run every time Factor starts."
$nl
"A word to run this file from an existing Factor session:"
{ $subsection run-user-init } ;
{ $subsections run-user-init } ;
ARTICLE: "factor-roots" "Additional vocabulary roots file"
"The vocabulary roots file is named " { $snippet "factor-roots" } " on Windows and " { $snippet ".factor-roots" } " on Unix. If it exists, it is loaded every time Factor starts. It contains a newline-separated list of " { $link "vocabs.roots" } "."
$nl
"A word to run this file from an existing Factor session:"
{ $subsection load-vocab-roots } ;
{ $subsections load-vocab-roots } ;
ARTICLE: "rc-files" "Running code on startup"
"Factor looks for three optional files in your home directory."
{ $subsection "factor-boot-rc" }
{ $subsection "factor-rc" }
{ $subsection "factor-roots" }
{ $subsections
"factor-boot-rc"
"factor-rc"
"factor-roots"
}
"The " { $snippet "-no-user-init" } " command line switch will inhibit loading running of these files."
$nl
"If you are unsure where the files should be located, evaluate the following code:"
@ -127,19 +128,17 @@ $nl
"\"factor-rc\" rc-path print"
"\"factor-boot-rc\" rc-path print"
}
"Here is an example " { $snippet ".factor-boot-rc" } " which sets up GVIM editor integration, adds an additional vocabulary root (see " { $link "vocabs.roots" } "), and increases the font size in the UI by setting the DPI (dots-per-inch) variable:"
"Here is an example " { $snippet ".factor-boot-rc" } " which sets up GVIM editor integration:"
{ $code
"USING: editors.gvim vocabs.loader ui.freetype namespaces sequences ;"
"USING: editors.gvim namespaces ;"
"\"/opt/local/bin\" \\ gvim-path set-global"
"\"/home/jane/src/\" vocab-roots get push"
"100 dpi set-global"
} ;
ARTICLE: "cli" "Command line arguments"
"Factor command line usage:"
{ $code "factor [system switches...] [script args...]" }
"Zero or more system switches can be passed in, followed by an optional script file name. If the script file is specified, it will be run on startup, any arguments after the script file are stored in a variable, with no further processing by Factor itself:"
{ $subsection command-line }
{ $code "factor [VM args...] [script] [args...]" }
"Zero or more VM arguments can be passed in, followed by an optional script file name. If the script file is specified, it will be run on startup, any arguments after the script file are stored in the following variable, with no further processing by Factor itself:"
{ $subsections command-line }
"Instead of running a script, it is also possible to run a vocabulary; this invokes the vocabulary's " { $link POSTPONE: MAIN: } " word:"
{ $code "factor [system switches...] -run=<vocab name>" }
"If no script file or " { $snippet "-run=" } " switch is specified, Factor will start " { $link "listener" } " or " { $link "ui-tools" } ", depending on the operating system."
@ -152,12 +151,14 @@ $nl
{ { $snippet "-no-" { $emphasis "foo" } } " - sets the global variable " { $snippet "\"" { $emphasis "foo" } "\"" } " to " { $link f } }
{ { $snippet "-" { $emphasis "foo" } "=" { $emphasis "bar" } } " - sets the global variable " { $snippet "\"" { $emphasis "foo" } "\"" } " to " { $snippet "\"" { $emphasis "bar" } "\"" } }
}
{ $subsection "runtime-cli-args" }
{ $subsection "bootstrap-cli-args" }
{ $subsection "standard-cli-args" }
{ $subsections
"runtime-cli-args"
"bootstrap-cli-args"
"standard-cli-args"
}
"The raw list of command line arguments can also be obtained and inspected directly:"
{ $subsection (command-line) }
{ $subsections (command-line) }
"There is a way to override the default vocabulary to run on startup, if no script name or " { $snippet "-run" } " switch is specified:"
{ $subsection main-vocab-hook } ;
{ $subsections main-vocab-hook } ;
ABOUT: "cli"

View File

@ -1,10 +1,17 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math namespaces assocs hashtables sequences arrays
accessors vectors combinators sets classes cpu.architecture
compiler.cfg compiler.cfg.registers compiler.cfg.instructions
compiler.cfg.def-use compiler.cfg.copy-prop compiler.cfg.rpo
compiler.cfg.liveness ;
accessors words vectors combinators combinators.short-circuit
sets classes layouts cpu.architecture
compiler.cfg
compiler.cfg.rpo
compiler.cfg.def-use
compiler.cfg.liveness
compiler.cfg.copy-prop
compiler.cfg.registers
compiler.cfg.comparisons
compiler.cfg.instructions
compiler.cfg.representations.preferred ;
IN: compiler.cfg.alias-analysis
! We try to eliminate redundant slot operations using some simple heuristics.
@ -77,10 +84,15 @@ SYMBOL: acs>vregs
: ac>vregs ( ac -- vregs ) acs>vregs get at ;
: aliases ( vreg -- vregs )
GENERIC: aliases ( vreg -- vregs )
M: integer aliases
#! All vregs which may contain the same value as vreg.
vreg>ac ac>vregs ;
M: word aliases
1array ;
: each-alias ( vreg quot -- )
[ aliases ] dip each ; inline
@ -181,7 +193,6 @@ SYMBOL: constants
#! assigned by an ##load-immediate.
resolve constants get at ;
! We treat slot accessors and stack traffic alike
GENERIC: insn-slot# ( insn -- slot#/f )
GENERIC: insn-object ( insn -- vreg )
@ -190,7 +201,7 @@ M: ##slot-imm insn-slot# slot>> ;
M: ##set-slot insn-slot# slot>> constant ;
M: ##set-slot-imm insn-slot# slot>> ;
M: ##alien-global insn-slot# [ library>> ] [ symbol>> ] bi 2array ;
M: ##vm-field-ptr insn-slot# fieldname>> 1array ; ! is this right?
M: ##vm-field-ptr insn-slot# field-name>> ;
M: ##slot insn-object obj>> resolve ;
M: ##slot-imm insn-object obj>> resolve ;
@ -206,18 +217,33 @@ M: ##vm-field-ptr insn-object drop \ ##vm-field-ptr ;
H{ } clone live-slots set
H{ } clone constants set
H{ } clone copies set
0 ac-counter set
next-ac heap-ac set
\ ##vm-field-ptr set-new-ac
\ ##alien-global set-new-ac
dup local-live-in [ set-heap-ac ] each ;
GENERIC: analyze-aliases* ( insn -- insn' )
M: insn analyze-aliases*
dup defs-vreg [ set-heap-ac ] when* ;
! If an instruction defines a value with a non-integer
! representation it means that the value will be boxed
! anywhere its used as a tagged pointer. Boxing allocates
! a new value, except boxing instructions haven't been
! inserted yet.
dup defs-vreg [
over defs-vreg-rep int-rep eq?
[ set-heap-ac ] [ set-new-ac ] if
] when* ;
M: ##phi analyze-aliases*
dup defs-vreg set-heap-ac ;
M: ##load-immediate analyze-aliases*
call-next-method
dup [ val>> ] [ dst>> ] bi constants get set-at ;
M: ##allocation analyze-aliases*
@ -249,6 +275,19 @@ M: ##copy analyze-aliases*
#! vreg, since they both contain the same value.
dup record-copy ;
: useless-compare? ( insn -- ? )
{
[ cc>> cc= eq? ]
[ [ src1>> ] [ src2>> ] bi [ resolve vreg>ac ] bi@ = not ]
} 1&& ; inline
M: ##compare analyze-aliases*
call-next-method
dup useless-compare? [
dst>> \ f tag-number \ ##load-immediate new-insn
analyze-aliases*
] when ;
: analyze-aliases ( insns -- insns' )
[ insn# set analyze-aliases* ] map-index sift ;

View File

@ -25,7 +25,7 @@ M: stack-frame-insn compute-stack-frame*
M: ##call compute-stack-frame*
word>> sub-primitive>> [ frame-required? on ] unless ;
M: _gc compute-stack-frame*
M: ##gc compute-stack-frame*
frame-required? on
stack-frame new swap tagged-values>> length cells >>gc-root-size
request-stack-frame ;

View File

@ -4,6 +4,7 @@ compiler.tree.optimizer compiler.cfg.builder compiler.cfg.debugger
compiler.cfg.optimizer compiler.cfg.predecessors compiler.cfg.checker
compiler.cfg arrays locals byte-arrays kernel.private math
slots.private vectors sbufs strings math.partial-dispatch
hashtables assocs combinators.short-circuit
strings.private accessors compiler.cfg.instructions ;
IN: compiler.cfg.builder.tests
@ -158,9 +159,12 @@ IN: compiler.cfg.builder.tests
{ pinned-c-ptr class fixnum } \ set-alien-cell '[ _ declare _ execute ] unit-test-cfg
] each
: contains-insn? ( quot insn-check -- ? )
: count-insns ( quot insn-check -- ? )
[ test-mr [ instructions>> ] map ] dip
'[ _ any? ] any? ; inline
'[ _ count ] sigma ; inline
: contains-insn? ( quot insn-check -- ? )
count-insns 0 > ; inline
[ t ] [ [ swap ] [ ##replace? ] contains-insn? ] unit-test
@ -196,12 +200,17 @@ IN: compiler.cfg.builder.tests
[ f t ] [
[ { byte-array fixnum } declare alien-cell 4 alien-float ]
[ [ ##box-alien? ] contains-insn? ]
[ [ ##box-float? ] contains-insn? ] bi
[ [ ##allot? ] contains-insn? ] bi
] unit-test
[ f t ] [
[ { byte-array fixnum } declare alien-cell { simple-alien } declare 4 alien-float ]
[ [ ##box-alien? ] contains-insn? ]
[ [ ##box-float? ] contains-insn? ] bi
[ [ ##allot? ] contains-insn? ] bi
] unit-test
] when
[ 1 ] [ [ dup float+ ] [ ##alien-double? ] count-insns ] unit-test
] when
! Regression. Make sure everything is inlined correctly
[ f ] [ M\ hashtable set-at [ { [ ##call? ] [ word>> \ set-slot eq? ] } 1&& ] contains-insn? ] unit-test

View File

@ -9,6 +9,9 @@ SYMBOLS:
cc< cc<= cc= cc> cc>= cc<> cc<>=
cc/< cc/<= cc/= cc/> cc/>= cc/<> cc/<>= ;
SYMBOLS:
vcc-all vcc-notall vcc-any vcc-none ;
: negate-cc ( cc -- cc' )
H{
{ cc< cc/< }
@ -27,6 +30,14 @@ SYMBOLS:
{ cc/<>= cc<>= }
} at ;
: negate-vcc ( cc -- cc' )
H{
{ vcc-all vcc-notall }
{ vcc-any vcc-none }
{ vcc-none vcc-any }
{ vcc-notall vcc-all }
} at ;
: swap-cc ( cc -- cc' )
H{
{ cc< cc> }

View File

@ -7,10 +7,10 @@ prettyprint.sections parser compiler.tree.builder
compiler.tree.optimizer cpu.architecture compiler.cfg.builder
compiler.cfg.linearization compiler.cfg.registers
compiler.cfg.stack-frame compiler.cfg.linear-scan
compiler.cfg.two-operand compiler.cfg.optimizer
compiler.cfg.instructions compiler.cfg.utilities
compiler.cfg.def-use compiler.cfg.rpo compiler.cfg.mr
compiler.cfg.representations.preferred compiler.cfg ;
compiler.cfg.optimizer compiler.cfg.instructions
compiler.cfg.utilities compiler.cfg.def-use compiler.cfg.rpo
compiler.cfg.mr compiler.cfg.representations.preferred
compiler.cfg ;
IN: compiler.cfg.debugger
GENERIC: test-cfg ( quot -- cfgs )
@ -44,6 +44,9 @@ M: word test-cfg
nl
] each ;
: test-mr. ( quot -- )
test-mr mr. ; inline
! Prettyprinting
: pprint-loc ( loc word -- ) <block pprint-word n>> pprint* block> ;
@ -79,4 +82,4 @@ M: rs-loc pprint* \ R pprint-loc ;
[ [ defs-vreg ] [ defs-vreg-rep ] bi 2dup and [ 2array ] [ 2drop f ] if ]
bi [ suffix ] when*
] map concat
] map concat >hashtable representations set ;
] map concat >hashtable representations set ;

View File

@ -16,7 +16,7 @@ V{
} 0 test-bb
V{
T{ ##box-float f 0 1 }
T{ ##box-alien f 0 1 }
} 1 test-bb
0 1 edge

View File

@ -1,7 +1,7 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel sequences assocs fry
cpu.architecture
cpu.architecture layouts
compiler.cfg.rpo
compiler.cfg.registers
compiler.cfg.instructions
@ -17,11 +17,26 @@ IN: compiler.cfg.gc-checks
: blocks-with-gc ( cfg -- bbs )
post-order [ insert-gc-check? ] filter ;
GENERIC: allocation-size* ( insn -- n )
M: ##allot allocation-size* size>> ;
M: ##box-alien allocation-size* drop 4 cells ;
M: ##box-displaced-alien allocation-size* drop 4 cells ;
: allocation-size ( bb -- n )
instructions>> [ ##allocation? ] filter [ allocation-size* ] sigma ;
: insert-gc-check ( bb -- )
dup '[
dup dup '[
int-rep next-vreg-rep
int-rep next-vreg-rep
f f _ uninitialized-locs \ ##gc new-insn
_ allocation-size
f
f
_ uninitialized-locs
\ ##gc new-insn
prefix
] change-instructions drop ;

View File

@ -45,16 +45,15 @@ insn-classes get [
[ next-vreg dup ] dip {
{ [ dup not ] [ drop \ f tag-number ##load-immediate ] }
{ [ dup fixnum? ] [ tag-fixnum ##load-immediate ] }
{ [ dup float? ] [ ##load-constant ] }
[ ##load-reference ]
} cond ; inline
} cond ;
: ^^unbox-c-ptr ( src class -- dst )
[ next-vreg dup ] 2dip next-vreg ##unbox-c-ptr ; inline
: ^^offset>slot ( slot -- vreg' )
cell 4 = [ 1 ^^shr-imm ] [ any-rep ^^copy ] if ;
: ^^neg ( src -- dst ) [ 0 ^^load-literal ] dip ^^sub ; inline
: ^^allot-tuple ( n -- dst ) 2 + cells tuple ^^allot ; inline
: ^^allot-array ( n -- dst ) 2 + cells array ^^allot ; inline
: ^^allot-byte-array ( n -- dst ) 2 cells + byte-array ^^allot ; inline
: ^^offset>slot ( vreg -- vreg' ) cell 4 = [ 1 ^^shr-imm ] [ any-rep ^^copy ] if ; inline
: ^^tag-fixnum ( src -- dst ) tag-bits get ^^shl-imm ; inline
: ^^untag-fixnum ( src -- dst ) tag-bits get ^^sar-imm ; inline
: ^^tag-fixnum ( src -- dst )
tag-bits get ^^shl-imm ;
: ^^untag-fixnum ( src -- dst )
tag-bits get ^^sar-imm ;

View File

@ -29,6 +29,10 @@ INSN: ##load-reference
def: dst/int-rep
constant: obj ;
INSN: ##load-constant
def: dst/int-rep
constant: obj ;
INSN: ##peek
def: dst/int-rep
literal: loc ;
@ -63,9 +67,7 @@ temp: temp/int-rep ;
! Slot access
INSN: ##slot
def: dst/int-rep
use: obj/int-rep slot/int-rep
literal: tag
temp: temp/int-rep ;
use: obj/int-rep slot/int-rep ;
INSN: ##slot-imm
def: dst/int-rep
@ -73,9 +75,7 @@ use: obj/int-rep
literal: slot tag ;
INSN: ##set-slot
use: src/int-rep obj/int-rep slot/int-rep
literal: tag
temp: temp/int-rep ;
use: src/int-rep obj/int-rep slot/int-rep ;
INSN: ##set-slot-imm
use: src/int-rep obj/int-rep
@ -190,31 +190,15 @@ PURE-INSN: ##not
def: dst/int-rep
use: src/int-rep ;
PURE-INSN: ##neg
def: dst/int-rep
use: src/int-rep ;
PURE-INSN: ##log2
def: dst/int-rep
use: src/int-rep ;
! Bignum/integer conversion
PURE-INSN: ##integer>bignum
def: dst/int-rep
use: src/int-rep
temp: temp/int-rep ;
PURE-INSN: ##bignum>integer
def: dst/int-rep
use: src/int-rep
temp: temp/int-rep ;
! Float arithmetic
PURE-INSN: ##unbox-float
def: dst/double-rep
use: src/int-rep ;
PURE-INSN: ##box-float
def: dst/int-rep
use: src/double-rep
temp: temp/int-rep ;
PURE-INSN: ##add-float
def: dst/double-rep
use: src1/double-rep src2/double-rep ;
@ -273,21 +257,12 @@ def: dst/double-rep
use: src/int-rep ;
! SIMD operations
PURE-INSN: ##box-vector
def: dst/int-rep
use: src
literal: rep
temp: temp/int-rep ;
PURE-INSN: ##unbox-vector
PURE-INSN: ##zero-vector
def: dst
use: src/int-rep
literal: rep ;
PURE-INSN: ##broadcast-vector
PURE-INSN: ##fill-vector
def: dst
use: src/scalar-rep
literal: rep ;
PURE-INSN: ##gather-vector-2
@ -300,21 +275,118 @@ def: dst
use: src1/scalar-rep src2/scalar-rep src3/scalar-rep src4/scalar-rep
literal: rep ;
PURE-INSN: ##shuffle-vector
def: dst
use: src shuffle
literal: rep ;
PURE-INSN: ##shuffle-vector-imm
def: dst
use: src
literal: shuffle rep ;
PURE-INSN: ##tail>head-vector
def: dst
use: src
literal: rep ;
PURE-INSN: ##merge-vector-head
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##merge-vector-tail
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##signed-pack-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##unsigned-pack-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##unpack-vector-head
def: dst
use: src
literal: rep ;
PURE-INSN: ##unpack-vector-tail
def: dst
use: src
literal: rep ;
PURE-INSN: ##integer>float-vector
def: dst
use: src
literal: rep ;
PURE-INSN: ##float>integer-vector
def: dst
use: src
literal: rep ;
PURE-INSN: ##compare-vector
def: dst
use: src1 src2
literal: rep cc ;
PURE-INSN: ##test-vector
def: dst/int-rep
use: src1
temp: temp/int-rep
literal: rep vcc ;
INSN: ##test-vector-branch
use: src1
temp: temp/int-rep
literal: rep vcc ;
INSN: _test-vector-branch
literal: label
use: src1
temp: temp/int-rep
literal: rep vcc ;
PURE-INSN: ##add-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##saturated-add-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##add-sub-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##sub-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##saturated-sub-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##mul-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##saturated-mul-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##div-vector
def: dst
use: src1 src2
@ -330,9 +402,9 @@ def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##sqrt-vector
def: dst
use: src
PURE-INSN: ##dot-vector
def: dst/scalar-rep
use: src1 src2
literal: rep ;
PURE-INSN: ##horizontal-add-vector
@ -340,6 +412,87 @@ def: dst/scalar-rep
use: src
literal: rep ;
PURE-INSN: ##horizontal-sub-vector
def: dst/scalar-rep
use: src
literal: rep ;
PURE-INSN: ##horizontal-shl-vector
def: dst
use: src1
literal: src2 rep ;
PURE-INSN: ##horizontal-shr-vector
def: dst
use: src1
literal: src2 rep ;
PURE-INSN: ##abs-vector
def: dst
use: src
literal: rep ;
PURE-INSN: ##sqrt-vector
def: dst
use: src
literal: rep ;
PURE-INSN: ##and-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##andn-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##or-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##xor-vector
def: dst
use: src1 src2
literal: rep ;
PURE-INSN: ##not-vector
def: dst
use: src
literal: rep ;
PURE-INSN: ##shl-vector
def: dst
use: src1 src2/int-scalar-rep
literal: rep ;
PURE-INSN: ##shr-vector
def: dst
use: src1 src2/int-scalar-rep
literal: rep ;
! Scalar/vector conversion
PURE-INSN: ##scalar>integer
def: dst/int-rep
use: src
literal: rep ;
PURE-INSN: ##integer>scalar
def: dst
use: src/int-rep
literal: rep ;
PURE-INSN: ##vector>scalar
def: dst/scalar-rep
use: src
literal: rep ;
PURE-INSN: ##scalar>vector
def: dst
use: src/scalar-rep
literal: rep ;
! Boxing and unboxing aliens
PURE-INSN: ##box-alien
def: dst/int-rep
@ -375,65 +528,88 @@ use: src/int-rep ;
! Alien accessors
INSN: ##alien-unsigned-1
def: dst/int-rep
use: src/int-rep ;
use: src/int-rep
literal: offset ;
INSN: ##alien-unsigned-2
def: dst/int-rep
use: src/int-rep ;
use: src/int-rep
literal: offset ;
INSN: ##alien-unsigned-4
def: dst/int-rep
use: src/int-rep ;
use: src/int-rep
literal: offset ;
INSN: ##alien-signed-1
def: dst/int-rep
use: src/int-rep ;
use: src/int-rep
literal: offset ;
INSN: ##alien-signed-2
def: dst/int-rep
use: src/int-rep ;
use: src/int-rep
literal: offset ;
INSN: ##alien-signed-4
def: dst/int-rep
use: src/int-rep ;
use: src/int-rep
literal: offset ;
INSN: ##alien-cell
def: dst/int-rep
use: src/int-rep ;
use: src/int-rep
literal: offset ;
INSN: ##alien-float
def: dst/float-rep
use: src/int-rep ;
use: src/int-rep
literal: offset ;
INSN: ##alien-double
def: dst/double-rep
use: src/int-rep ;
use: src/int-rep
literal: offset ;
INSN: ##alien-vector
def: dst
use: src/int-rep
literal: rep ;
literal: offset rep ;
INSN: ##set-alien-integer-1
use: src/int-rep value/int-rep ;
use: src/int-rep
literal: offset
use: value/int-rep ;
INSN: ##set-alien-integer-2
use: src/int-rep value/int-rep ;
use: src/int-rep
literal: offset
use: value/int-rep ;
INSN: ##set-alien-integer-4
use: src/int-rep value/int-rep ;
use: src/int-rep
literal: offset
use: value/int-rep ;
INSN: ##set-alien-cell
use: src/int-rep value/int-rep ;
use: src/int-rep
literal: offset
use: value/int-rep ;
INSN: ##set-alien-float
use: src/int-rep value/float-rep ;
use: src/int-rep
literal: offset
use: value/float-rep ;
INSN: ##set-alien-double
use: src/int-rep value/double-rep ;
use: src/int-rep
literal: offset
use: value/double-rep ;
INSN: ##set-alien-vector
use: src/int-rep value
use: src/int-rep
literal: offset
use: value
literal: rep ;
! Memory allocation
@ -452,7 +628,7 @@ literal: symbol library ;
INSN: ##vm-field-ptr
def: dst/int-rep
literal: fieldname ;
literal: field-name ;
! FFI
INSN: ##alien-invoke
@ -535,7 +711,7 @@ use: src1/int-rep src2/int-rep ;
INSN: ##gc
temp: temp1/int-rep temp2/int-rep
literal: data-values tagged-values uninitialized-locs ;
literal: size data-values tagged-values uninitialized-locs ;
INSN: ##save-context
temp: temp1/int-rep temp2/int-rep
@ -600,35 +776,29 @@ literal: label
def: dst/int-rep
use: src1/int-rep src2/int-rep ;
TUPLE: spill-slot n ; C: <spill-slot> spill-slot
INSN: _gc
temp: temp1 temp2
literal: data-values tagged-values uninitialized-locs ;
TUPLE: spill-slot { n integer } ;
C: <spill-slot> spill-slot
! These instructions operate on machine registers and not
! virtual registers
INSN: _spill
use: src
literal: rep n ;
literal: rep dst ;
INSN: _reload
def: dst
literal: rep n ;
literal: rep src ;
INSN: _spill-area-size
literal: n ;
UNION: ##allocation
##allot
##box-float
##box-vector
##box-alien
##box-displaced-alien
##integer>bignum ;
##box-displaced-alien ;
! For alias analysis
UNION: ##read ##slot ##slot-imm ;
UNION: ##read ##slot ##slot-imm ##vm-field-ptr ##alien-global ;
UNION: ##write ##set-slot ##set-slot-imm ;
! Instructions that kill all live vregs but cannot trigger GC
@ -648,8 +818,9 @@ UNION: kill-vreg-insn
! Instructions that have complex expansions and require that the
! output registers are not equal to any of the input registers
UNION: def-is-use-insn
##integer>bignum
##bignum>integer
##box-alien
##box-displaced-alien
##string-nth
##unbox-any-c-ptr ;
SYMBOL: vreg-insn

View File

@ -3,8 +3,9 @@
USING: accessors kernel sequences alien math classes.algebra fry
locals combinators combinators.short-circuit cpu.architecture
compiler.tree.propagation.info compiler.cfg.hats
compiler.cfg.stacks compiler.cfg.instructions
compiler.cfg.utilities compiler.cfg.builder.blocks ;
compiler.cfg.registers compiler.cfg.stacks
compiler.cfg.instructions compiler.cfg.utilities
compiler.cfg.builder.blocks ;
IN: compiler.cfg.intrinsics.alien
: emit-<displaced-alien>? ( node -- ? )
@ -33,10 +34,13 @@ IN: compiler.cfg.intrinsics.alien
[ second class>> fixnum class<= ]
bi and ;
: prepare-alien-accessor ( info -- offset-vreg )
class>> [ 2inputs ^^untag-fixnum swap ] dip ^^unbox-c-ptr ^^add ;
: ^^unbox-c-ptr ( src class -- dst )
[ next-vreg dup ] 2dip next-vreg ##unbox-c-ptr ;
: prepare-alien-getter ( infos -- offset-vreg )
: prepare-alien-accessor ( info -- ptr-vreg offset )
class>> [ 2inputs ^^untag-fixnum swap ] dip ^^unbox-c-ptr ^^add 0 ;
: prepare-alien-getter ( infos -- ptr-vreg offset )
first prepare-alien-accessor ;
: inline-alien-getter ( node quot -- )
@ -49,7 +53,7 @@ IN: compiler.cfg.intrinsics.alien
[ third class>> fixnum class<= ]
tri and and ;
: prepare-alien-setter ( infos -- offset-vreg )
: prepare-alien-setter ( infos -- ptr-vreg offset )
second prepare-alien-accessor ;
: inline-alien-integer-setter ( node quot -- )

View File

@ -18,6 +18,9 @@ IN: compiler.cfg.intrinsics.allot
: tuple-slot-regs ( layout -- vregs )
[ second ds-load ] [ ^^load-literal ] bi prefix ;
: ^^allot-tuple ( n -- dst )
2 + cells tuple ^^allot ;
: emit-<tuple-boa> ( node -- )
dup node-input-infos last literal>>
dup array? [
@ -36,6 +39,9 @@ IN: compiler.cfg.intrinsics.allot
: expand-<array>? ( obj -- ? )
dup integer? [ 0 8 between? ] [ drop f ] if ;
: ^^allot-array ( n -- dst )
2 + cells array ^^allot ;
:: emit-<array> ( node -- )
[let | len [ node node-input-infos first literal>> ] |
len expand-<array>? [
@ -49,18 +55,24 @@ IN: compiler.cfg.intrinsics.allot
] [ node emit-primitive ] if
] ;
: expand-(byte-array)? ( obj -- ? )
dup integer? [ 0 1024 between? ] [ drop f ] if ;
: expand-<byte-array>? ( obj -- ? )
dup integer? [ 0 32 between? ] [ drop f ] if ;
: bytes>cells ( m -- n ) cell align cell /i ;
: ^^allot-byte-array ( n -- dst )
2 cells + byte-array ^^allot ;
: emit-allot-byte-array ( len -- dst )
ds-drop
dup ^^allot-byte-array
[ byte-array store-length ] [ ds-push ] [ ] tri ;
: emit-(byte-array) ( node -- )
dup node-input-infos first literal>> dup expand-<byte-array>?
dup node-input-infos first literal>> dup expand-(byte-array)?
[ nip emit-allot-byte-array drop ] [ drop emit-primitive ] if ;
:: emit-<byte-array> ( node -- )

View File

@ -57,12 +57,6 @@ IN: compiler.cfg.intrinsics.fixnum
: emit-fixnum-comparison ( cc -- )
'[ _ ^^compare ] emit-fixnum-op ;
: emit-bignum>fixnum ( -- )
ds-pop ^^bignum>integer ^^tag-fixnum ds-push ;
: emit-fixnum>bignum ( -- )
ds-pop ^^untag-fixnum ^^integer>bignum ds-push ;
: emit-no-overflow-case ( dst -- final-bb )
[ ds-drop ds-drop ds-push ] with-branch ;

View File

@ -151,27 +151,64 @@ IN: compiler.cfg.intrinsics
{ math.integers.private:fixnum-log2 [ drop emit-fixnum-log2 ] }
} enable-intrinsics ;
: enable-sse2-simd ( -- )
: 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) [ [ ^^min-vector ] emit-binary-vector-op ] }
{ math.vectors.simd.intrinsics:(simd-vmax) [ [ ^^max-vector ] emit-binary-vector-op ] }
{ math.vectors.simd.intrinsics:(simd-vsqrt) [ [ ^^sqrt-vector ] emit-binary-vector-op ] }
{ math.vectors.simd.intrinsics:(simd-broadcast) [ [ ^^broadcast-vector ] emit-unary-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 ] emit-binary-vector-op ] }
{ math.vectors.simd.intrinsics:(simd-vrshift) [ [ ^^shr-vector ] emit-binary-vector-op ] }
{ math.vectors.simd.intrinsics:(simd-hlshift) [ [ ^^horizontal-shl-vector ] emit-horizontal-shift ] }
{ math.vectors.simd.intrinsics:(simd-hrshift) [ [ ^^horizontal-shr-vector ] emit-horizontal-shift ] }
{ 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 ;
: enable-sse3-simd ( -- )
{
{ math.vectors.simd.intrinsics:(simd-sum) [ [ ^^horizontal-add-vector ] emit-unary-vector-op ] }
} enable-intrinsics ;
: emit-intrinsic ( node word -- )
"intrinsic" word-prop call( node -- ) ;

View File

@ -12,5 +12,5 @@ IN: compiler.cfg.intrinsics.misc
: emit-getenv ( node -- )
"userenv" ^^vm-field-ptr
swap node-input-infos first literal>>
[ ds-drop 0 ^^slot-imm ] [ ds-pop ^^offset>slot 0 ^^slot ] if*
[ ds-drop 0 ^^slot-imm ] [ ds-pop ^^offset>slot ^^slot ] if*
ds-push ;

View File

@ -1,22 +1,63 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors byte-arrays fry cpu.architecture kernel
sequences compiler.tree.propagation.info
compiler.cfg.builder.blocks compiler.cfg.stacks
compiler.cfg.stacks.local compiler.cfg.hats
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
compiler.cfg.comparisons
compiler.cfg.stacks compiler.cfg.stacks.local compiler.cfg.hats
compiler.cfg.instructions compiler.cfg.registers
compiler.cfg.intrinsics.alien ;
compiler.cfg.intrinsics.alien
specialized-arrays ;
FROM: alien.c-types => heap-size char uchar float double ;
SPECIALIZED-ARRAYS: float double ;
IN: compiler.cfg.intrinsics.simd
MACRO: check-elements ( quots -- )
[ length '[ _ firstn ] ]
[ '[ _ spread ] ]
[ length 1 - \ and <repetition> [ ] 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 -- ) -- )
[ dup node-input-infos last literal>> ] dip over representation?
[ [ drop ] 2dip call ] [ 2drop emit-primitive ] if ; inline
{ [ representation? ] } if-literals-match ; inline
: [binary] ( quot -- quot' )
'[ [ ds-drop 2inputs ] dip @ ds-push ] ; inline
: emit-binary-vector-op ( node quot -- )
'[ [ ds-drop 2inputs ] dip @ ds-push ] emit-vector-op ; inline
[binary] emit-vector-op ; inline
: [unary] ( quot -- quot' )
'[ [ ds-drop ds-pop ] dip @ ds-push ] ; inline
: emit-unary-vector-op ( node quot -- )
'[ [ ds-drop ds-pop ] dip @ ds-push ] emit-vector-op ; inline
[unary] emit-vector-op ; inline
: [unary/param] ( quot -- quot' )
'[ [ -2 inc-d ds-pop ] 2dip @ ds-push ] ; inline
: emit-horizontal-shift ( node quot -- )
[unary/param]
{ [ integer? ] [ representation? ] } if-literals-match ; inline
: emit-gather-vector-2 ( node -- )
[ ^^gather-vector-2 ] emit-binary-vector-op ;
@ -35,6 +76,61 @@ IN: compiler.cfg.intrinsics.simd
ds-push
] emit-vector-op ;
: shuffle? ( obj -- ? ) { [ array? ] [ [ integer? ] all? ] } 1&& ;
: >variable-shuffle ( shuffle rep -- shuffle' )
rep-component-type heap-size
[ dup <repetition> >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 <array> ] 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 [
'[
@ -42,7 +138,7 @@ IN: compiler.cfg.intrinsics.simd
_ ^^alien-vector ds-push
]
[ inline-alien-getter? ] inline-alien
] with emit-vector-op ;
] with emit-alien-vector-op ;
: emit-set-alien-vector ( node -- )
dup [
@ -52,4 +148,106 @@ IN: compiler.cfg.intrinsics.simd
]
[ byte-array inline-alien-setter? ]
inline-alien
] with emit-vector-op ;
] 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 :> swap? :> cc
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 :> not? :> ccs
ccs empty?
[ rep not? [ ^^fill-vector ] [ ^^zero-vector ] if ]
[
ccs unclip :> first-cc :> rest-ccs
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 ;
:: generate-unpack-vector-head ( src rep -- dst )
{
{
[ rep %unpack-vector-head-reps member? ]
[ src rep ^^unpack-vector-head ]
}
[
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 ^^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 ;
:: generate-blend-vector ( mask true false rep -- dst )
mask true rep ^^and-vector
mask false rep ^^andn-vector
rep ^^or-vector ;
:: generate-abs-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
]
}
[
rep ^^zero-vector :> zero
zero src rep ^^sub-vector :> -src
zero src rep cc> ^^compare-vector :> sign
sign -src src rep generate-blend-vector
]
} cond ;

View File

@ -8,9 +8,12 @@ IN: compiler.cfg.intrinsics.slots
: value-tag ( info -- n ) class>> class-tag ; inline
: ^^tag-offset>slot ( slot tag -- vreg' )
[ ^^offset>slot ] dip ^^sub-imm ;
: (emit-slot) ( infos -- dst )
[ 2inputs ^^offset>slot ] [ first value-tag ] bi*
^^slot ;
[ 2inputs ] [ first value-tag ] bi*
^^tag-offset>slot ^^slot ;
: (emit-slot-imm) ( infos -- dst )
ds-drop
@ -28,8 +31,8 @@ IN: compiler.cfg.intrinsics.slots
] [ drop emit-primitive ] if ;
: (emit-set-slot) ( infos -- obj-reg )
[ 3inputs ^^offset>slot ] [ second value-tag ] bi*
pick [ next-vreg ##set-slot ] dip ;
[ 3inputs ] [ second value-tag ] bi*
^^tag-offset>slot over [ ##set-slot ] dip ;
: (emit-set-slot-imm) ( infos -- obj-reg )
ds-drop

View File

@ -34,11 +34,15 @@ IN: compiler.cfg.linear-scan.allocation
[ drop assign-blocked-register ]
} cond ;
: spill-at-sync-point ( live-interval n -- ? )
! If the live interval has a usage at 'n', don't spill it,
! since this means its being defined by the sync point
! instruction. Output t if this is the case.
2dup [ uses>> ] dip swap member? [ 2drop t ] [ spill f ] if ;
: handle-sync-point ( n -- )
[ active-intervals get values ] dip
[ '[ [ _ spill ] each ] each ]
[ drop [ delete-all ] each ]
2bi ;
'[ [ _ spill-at-sync-point ] filter-here ] each ;
:: handle-progress ( n sync? -- )
n {

View File

@ -1,7 +1,7 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs combinators fry hints kernel locals
math sequences sets sorting splitting namespaces
math sequences sets sorting splitting namespaces linked-assocs
combinators.short-circuit compiler.utilities
compiler.cfg.linear-scan.allocation.state
compiler.cfg.linear-scan.allocation.splitting
@ -83,7 +83,7 @@ ERROR: bad-live-ranges interval ;
find-use-positions ;
: spill-status ( new -- use-pos )
H{ } clone
H{ } <linked-assoc>
[ inactive-positions ] [ active-positions ] [ nip ] 2tri
>alist alist-max ;

View File

@ -2,8 +2,8 @@
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs combinators cpu.architecture fry heaps
kernel math math.order namespaces sequences vectors
compiler.cfg compiler.cfg.registers
compiler.cfg.linear-scan.live-intervals ;
linked-assocs compiler.cfg compiler.cfg.registers
compiler.cfg.instructions compiler.cfg.linear-scan.live-intervals ;
IN: compiler.cfg.linear-scan.allocation.state
! Start index of current live interval. We ensure that all
@ -118,7 +118,8 @@ SYMBOL: unhandled-intervals
: next-spill-slot ( rep -- n )
rep-size cfg get
[ swap [ align dup ] [ + ] bi ] change-spill-area-size drop ;
[ swap [ align dup ] [ + ] bi ] change-spill-area-size drop
<spill-slot> ;
! Minheap of sync points which still need to be processed
SYMBOL: unhandled-sync-points
@ -126,7 +127,7 @@ SYMBOL: unhandled-sync-points
! Mapping from vregs to spill slots
SYMBOL: spill-slots
: vreg-spill-slot ( vreg -- n )
: vreg-spill-slot ( vreg -- spill-slot )
spill-slots get [ rep-of next-spill-slot ] cache ;
: init-allocator ( registers -- )
@ -147,7 +148,8 @@ SYMBOL: spill-slots
! A utility used by register-status and spill-status words
: free-positions ( new -- assoc )
vreg>> rep-of reg-class-of registers get at [ 1/0. ] H{ } map>assoc ;
vreg>> rep-of reg-class-of registers get at
[ 1/0. ] H{ } <linked-assoc> map>assoc ;
: add-use-position ( n reg assoc -- ) [ [ min ] when* ] change-at ;

View File

@ -2,7 +2,7 @@
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel math assocs namespaces sequences heaps
fry make combinators sets locals arrays
cpu.architecture
cpu.architecture layouts
compiler.cfg
compiler.cfg.def-use
compiler.cfg.liveness
@ -33,7 +33,7 @@ ERROR: bad-vreg vreg ;
: (vreg>reg) ( vreg pending -- reg )
! If a live vreg is not in the pending set, then it must
! have been spilled.
?at [ spill-slots get ?at [ <spill-slot> ] [ bad-vreg ] if ] unless ;
?at [ spill-slots get ?at [ ] [ bad-vreg ] if ] unless ;
: vreg>reg ( vreg -- reg )
pending-interval-assoc get (vreg>reg) ;
@ -117,8 +117,6 @@ RENAMING: assign [ vreg>reg ] [ vreg>reg ] [ vreg>reg ]
M: vreg-insn assign-registers-in-insn
[ assign-insn-defs ] [ assign-insn-uses ] [ assign-insn-temps ] tri ;
! TODO: needs tagged-rep
: trace-on-gc ( assoc -- assoc' )
! When a GC occurs, virtual registers which contain tagged data
! are traced by the GC. Outputs a sequence physical registers.
@ -141,12 +139,16 @@ M: vreg-insn assign-registers-in-insn
] assoc-each
] { } make ;
: gc-root-offsets ( registers -- alist )
! Outputs a sequence of { offset register/spill-slot } pairs
[ length iota [ cell * ] map ] keep zip ;
M: ##gc assign-registers-in-insn
! Since ##gc is always the first instruction in a block, the set of
! values live at the ##gc is just live-in.
dup call-next-method
basic-block get register-live-ins get at
[ trace-on-gc >>tagged-values ] [ spill-on-gc >>data-values ] bi
[ trace-on-gc gc-root-offsets >>tagged-values ] [ spill-on-gc >>data-values ] bi
drop ;
M: insn assign-registers-in-insn drop ;

View File

@ -92,7 +92,7 @@ H{
{ end 2 }
{ uses V{ 0 1 } }
{ ranges V{ T{ live-range f 0 2 } } }
{ spill-to 0 }
{ spill-to T{ spill-slot f 0 } }
}
T{ live-interval
{ vreg 1 }
@ -100,7 +100,7 @@ H{
{ end 5 }
{ uses V{ 5 } }
{ ranges V{ T{ live-range f 5 5 } } }
{ reload-from 0 }
{ reload-from T{ spill-slot f 0 } }
}
] [
T{ live-interval
@ -119,7 +119,7 @@ H{
{ end 1 }
{ uses V{ 0 } }
{ ranges V{ T{ live-range f 0 1 } } }
{ spill-to 4 }
{ spill-to T{ spill-slot f 4 } }
}
T{ live-interval
{ vreg 2 }
@ -127,7 +127,7 @@ H{
{ end 5 }
{ uses V{ 1 5 } }
{ ranges V{ T{ live-range f 1 5 } } }
{ reload-from 4 }
{ reload-from T{ spill-slot f 4 } }
}
] [
T{ live-interval
@ -146,7 +146,7 @@ H{
{ end 1 }
{ uses V{ 0 } }
{ ranges V{ T{ live-range f 0 1 } } }
{ spill-to 8 }
{ spill-to T{ spill-slot f 8 } }
}
T{ live-interval
{ vreg 3 }
@ -154,7 +154,7 @@ H{
{ end 30 }
{ uses V{ 20 30 } }
{ ranges V{ T{ live-range f 20 30 } } }
{ reload-from 8 }
{ reload-from T{ spill-slot f 8 } }
}
] [
T{ live-interval
@ -1042,8 +1042,8 @@ V{
[ _spill ] [ 1 get instructions>> second class ] unit-test
[ _reload ] [ 4 get instructions>> 4 swap nth class ] unit-test
[ V{ 3 2 1 } ] [ 8 get instructions>> [ _spill? ] filter [ n>> cell / ] map ] unit-test
[ V{ 3 2 1 } ] [ 9 get instructions>> [ _reload? ] filter [ n>> cell / ] map ] unit-test
[ V{ 3 2 1 } ] [ 8 get instructions>> [ _spill? ] filter [ dst>> n>> cell / ] map ] unit-test
[ V{ 3 2 1 } ] [ 9 get instructions>> [ _reload? ] filter [ src>> n>> cell / ] map ] unit-test
! Resolve pass should insert this
[ _reload ] [ 5 get predecessors>> first instructions>> first class ] unit-test
@ -1465,7 +1465,7 @@ V{
[ ] [ { 1 2 3 } test-linear-scan-on-cfg ] unit-test
[ { 3 } ] [ 1 get instructions>> first tagged-values>> ] unit-test
[ { { 0 1 } } ] [ 1 get instructions>> first tagged-values>> ] unit-test
V{
T{ ##peek f 0 D 0 }
@ -1487,4 +1487,4 @@ V{
[ ] [ { 1 2 3 } test-linear-scan-on-cfg ] unit-test
[ { 3 } ] [ 1 get instructions>> first tagged-values>> ] unit-test
[ { { 0 1 } } ] [ 1 get instructions>> first tagged-values>> ] unit-test

View File

@ -17,7 +17,7 @@ IN: compiler.cfg.linear-scan.resolve.tests
[
{
T{ _reload { dst 1 } { rep int-rep } { n 0 } }
T{ _reload { dst 1 } { rep int-rep } { src T{ spill-slot f 0 } } }
}
] [
[
@ -27,7 +27,7 @@ IN: compiler.cfg.linear-scan.resolve.tests
[
{
T{ _spill { src 1 } { rep int-rep } { n 0 } }
T{ _spill { src 1 } { rep int-rep } { dst T{ spill-slot f 0 } } }
}
] [
[
@ -54,14 +54,14 @@ H{ } clone spill-temps set
{ { { 0 int-rep } { 1 int-rep } } { { 1 int-rep } { 0 int-rep } } }
mapping-instructions {
{
T{ _spill { src 0 } { rep int-rep } { n 8 } }
T{ _spill { src 0 } { rep int-rep } { dst T{ spill-slot f 8 } } }
T{ ##copy { dst 0 } { src 1 } { rep int-rep } }
T{ _reload { dst 1 } { rep int-rep } { n 8 } }
T{ _reload { dst 1 } { rep int-rep } { src T{ spill-slot f 8 } } }
}
{
T{ _spill { src 1 } { rep int-rep } { n 8 } }
T{ _spill { src 1 } { rep int-rep } { dst T{ spill-slot f 8 } } }
T{ ##copy { dst 1 } { src 0 } { rep int-rep } }
T{ _reload { dst 0 } { rep int-rep } { n 8 } }
T{ _reload { dst 0 } { rep int-rep } { src T{ spill-slot f 8 } } }
}
} member?
] unit-test

View File

@ -34,10 +34,10 @@ SYMBOL: spill-temps
] if ;
: memory->register ( from to -- )
swap [ first2 ] [ first n>> ] bi* _reload ;
swap [ first2 ] [ first ] bi* _reload ;
: register->memory ( from to -- )
[ first2 ] [ first n>> ] bi* _spill ;
[ first2 ] [ first ] bi* _spill ;
: temp->register ( from to -- )
nip [ first ] [ second ] [ second spill-temp ] tri _reload ;

View File

@ -2,7 +2,7 @@
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math accessors sequences namespaces make
combinators assocs arrays locals layouts hashtables
cpu.architecture
cpu.architecture generalizations
compiler.cfg
compiler.cfg.comparisons
compiler.cfg.stack-frame
@ -42,14 +42,26 @@ M: ##branch linearize-insn
: successors ( bb -- first second ) successors>> first2 ; inline
:: conditional ( bb insn n conditional-quot negate-cc-quot -- bb successor label ... )
bb insn
conditional-quot
[ drop dup successors>> second useless-branch? ] 2bi
[ [ swap block-number ] n ndip ]
[ [ block-number ] n ndip negate-cc-quot call ] if ; inline
: (binary-conditional) ( bb insn -- bb successor1 successor2 src1 src2 cc )
[ dup successors ]
[ [ src1>> ] [ src2>> ] [ cc>> ] tri ] bi* ; inline
: binary-conditional ( bb insn -- bb successor label2 src1 src2 cc )
[ (binary-conditional) ]
[ drop dup successors>> second useless-branch? ] 2bi
[ [ swap block-number ] 3dip ] [ [ block-number ] 3dip negate-cc ] if ;
3 [ (binary-conditional) ] [ negate-cc ] conditional ;
: (test-vector-conditional) ( bb insn -- bb successor1 successor2 src1 temp rep vcc )
[ dup successors ]
[ { [ src1>> ] [ temp>> ] [ rep>> ] [ vcc>> ] } cleave ] bi* ; inline
: test-vector-conditional ( bb insn -- bb successor label src1 temp rep vcc )
4 [ (test-vector-conditional) ] [ negate-vcc ] conditional ;
M: ##compare-branch linearize-insn
binary-conditional _compare-branch emit-branch ;
@ -63,6 +75,9 @@ M: ##compare-float-ordered-branch linearize-insn
M: ##compare-float-unordered-branch linearize-insn
binary-conditional _compare-float-unordered-branch emit-branch ;
M: ##test-vector-branch linearize-insn
test-vector-conditional _test-vector-branch emit-branch ;
: overflow-conditional ( bb insn -- bb successor label2 dst src1 src2 )
[ dup successors block-number ]
[ [ dst>> ] [ src1>> ] [ src2>> ] tri ] bi* ; inline
@ -82,21 +97,6 @@ M: ##dispatch linearize-insn
[ successors>> [ block-number _dispatch-label ] each ]
bi* ;
: gc-root-offsets ( registers -- alist )
! Outputs a sequence of { offset register/spill-slot } pairs
[ length iota [ cell * ] map ] keep zip ;
M: ##gc linearize-insn
nip
{
[ temp1>> ]
[ temp2>> ]
[ data-values>> ]
[ tagged-values>> gc-root-offsets ]
[ uninitialized-locs>> ]
} cleave
_gc ;
: linearize-basic-blocks ( cfg -- insns )
[
[

View File

@ -12,7 +12,6 @@ compiler.cfg.copy-prop
compiler.cfg.dce
compiler.cfg.write-barrier
compiler.cfg.representations
compiler.cfg.two-operand
compiler.cfg.ssa.destruction
compiler.cfg.empty-blocks
compiler.cfg.checker ;
@ -37,7 +36,6 @@ SYMBOL: check-optimizer?
eliminate-dead-code
eliminate-write-barriers
select-representations
convert-two-operand
destruct-ssa
delete-empty-blocks
?check ;

View File

@ -3,8 +3,8 @@
USING: kernel accessors sequences arrays fry namespaces generic
words sets combinators generalizations cpu.architecture compiler.units
compiler.cfg.utilities compiler.cfg compiler.cfg.rpo
compiler.cfg.instructions compiler.cfg.instructions.syntax
compiler.cfg.def-use ;
compiler.cfg.instructions compiler.cfg.def-use ;
FROM: compiler.cfg.instructions.syntax => insn-def-slot insn-use-slots insn-temp-slots scalar-rep ;
IN: compiler.cfg.representations.preferred
GENERIC: defs-vreg-rep ( insn -- rep/f )

View File

@ -1,8 +1,10 @@
! Copyright (C) 2009 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: kernel fry accessors sequences assocs sets namespaces
arrays combinators make locals deques dlists
cpu.architecture compiler.utilities
arrays combinators combinators.short-circuit math make locals
deques dlists layouts byte-arrays cpu.architecture
compiler.utilities
compiler.constants
compiler.cfg
compiler.cfg.rpo
compiler.cfg.hats
@ -22,28 +24,44 @@ ERROR: bad-conversion dst src dst-rep src-rep ;
GENERIC: emit-box ( dst src rep -- )
GENERIC: emit-unbox ( dst src rep -- )
M: float-rep emit-box
drop
[ double-rep next-vreg-rep dup ] dip ##single>double-float
int-rep next-vreg-rep ##box-float ;
M:: float-rep emit-box ( dst src rep -- )
double-rep next-vreg-rep :> temp
temp src ##single>double-float
dst temp double-rep emit-box ;
M: float-rep emit-unbox
drop
[ double-rep next-vreg-rep dup ] dip ##unbox-float
##double>single-float ;
M:: float-rep emit-unbox ( dst src rep -- )
double-rep next-vreg-rep :> temp
temp src double-rep emit-unbox
dst temp ##double>single-float ;
M: double-rep emit-box
drop
int-rep next-vreg-rep ##box-float ;
[ drop 16 float int-rep next-vreg-rep ##allot ]
[ float-offset swap ##set-alien-double ]
2bi ;
M: double-rep emit-unbox
drop ##unbox-float ;
drop float-offset ##alien-double ;
M: vector-rep emit-box
int-rep next-vreg-rep ##box-vector ;
M:: vector-rep emit-box ( dst src rep -- )
int-rep next-vreg-rep :> temp
dst 16 2 cells + byte-array int-rep next-vreg-rep ##allot
temp 16 tag-fixnum ##load-immediate
temp dst 1 byte-array tag-number ##set-slot-imm
dst byte-array-offset src rep ##set-alien-vector ;
M: vector-rep emit-unbox
##unbox-vector ;
[ byte-array-offset ] dip ##alien-vector ;
M:: scalar-rep emit-box ( dst src rep -- )
int-rep next-vreg-rep :> temp
temp src rep ##scalar>integer
dst temp tag-bits get ##shl-imm ;
M:: scalar-rep emit-unbox ( dst src rep -- )
int-rep next-vreg-rep :> temp
temp src tag-bits get ##sar-imm
dst temp rep ##integer>scalar ;
: emit-conversion ( dst src dst-rep src-rep -- )
{
@ -87,9 +105,8 @@ SYMBOL: always-boxed
H{ } clone [
'[
[
dup ##load-reference? [ drop ] [
[ _ (compute-always-boxed) ] each-def-rep
] if
dup [ ##load-reference? ] [ ##load-constant? ] bi or
[ drop ] [ [ _ (compute-always-boxed) ] each-def-rep ] if
] each-non-phi
] each-basic-block
] keep ;
@ -135,6 +152,9 @@ SYMBOL: costs
! Insert conversions. This introduces new temporaries, so we need
! to rename opearands too.
! Mapping from vreg,rep pairs to vregs
SYMBOL: alternatives
:: emit-def-conversion ( dst preferred required -- new-dst' )
! If an instruction defines a register with representation 'required',
! but the register has preferred representation 'preferred', then
@ -147,7 +167,13 @@ SYMBOL: costs
! but the register has preferred representation 'preferred', then
! we rename the instruction's input to a new register, which
! becomes the output of a conversion instruction.
required next-vreg-rep [ src required preferred emit-conversion ] keep ;
preferred required eq? [ src ] [
src required alternatives get [
required next-vreg-rep :> new-src
[ new-src ] 2dip preferred emit-conversion
new-src
] 2cache
] if ;
SYMBOLS: renaming-set needs-renaming? ;
@ -200,6 +226,41 @@ SYMBOL: phi-mappings
M: ##phi conversions-for-insn
[ , ] [ [ inputs>> values ] [ dst>> ] bi phi-mappings get set-at ] bi ;
! When a literal zeroes/ones vector is unboxed, we replace the ##load-reference
! with a ##zero-vector or ##fill-vector instruction since this is more efficient.
: convert-to-zero-vector? ( insn -- ? )
{
[ dst>> rep-of vector-rep? ]
[ obj>> B{ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } = ]
} 1&& ;
: convert-to-fill-vector? ( insn -- ? )
{
[ dst>> rep-of vector-rep? ]
[ obj>> B{ 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 } = ]
} 1&& ;
: (convert-to-zero/fill-vector) ( insn -- dst rep )
dst>> dup rep-of ; inline
: conversions-for-load-insn ( insn -- ?insn )
{
{
[ dup convert-to-zero-vector? ]
[ (convert-to-zero/fill-vector) ##zero-vector f ]
}
{
[ dup convert-to-fill-vector? ]
[ (convert-to-zero/fill-vector) ##fill-vector f ]
}
[ ]
} cond ;
M: ##load-reference conversions-for-insn
conversions-for-load-insn [ call-next-method ] when* ;
M: ##load-constant conversions-for-insn
conversions-for-load-insn [ call-next-method ] when* ;
M: vreg-insn conversions-for-insn
[ compute-renaming-set ] [ perform-renaming ] bi ;
@ -209,6 +270,7 @@ M: insn conversions-for-insn , ;
dup kill-block? [ drop ] [
[
[
H{ } clone alternatives set
[ conversions-for-insn ] each
] V{ } make
] change-instructions drop
@ -266,4 +328,4 @@ PRIVATE>
[ insert-conversions ]
[ ]
} cleave
representations get cfg get (>>reps) ;
representations get cfg get (>>reps) ;

View File

@ -1,8 +1,9 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs kernel locals fry
USING: accessors assocs kernel locals fry sequences
cpu.architecture
compiler.cfg.rpo
compiler.cfg.def-use
compiler.cfg.utilities
compiler.cfg.registers
compiler.cfg.instructions
@ -13,10 +14,19 @@ IN: compiler.cfg.ssa.cssa
! selection, so it must keep track of representations when introducing
! new values.
: insert-copy? ( bb vreg -- ? )
! If the last instruction defines a value (which means it is
! ##fixnum-add, ##fixnum-sub or ##fixnum-mul) then we don't
! need to insert a copy since in fact doing so will result
! in incorrect code.
[ instructions>> last defs-vreg ] dip eq? not ;
:: insert-copy ( bb src rep -- bb dst )
rep next-vreg-rep :> dst
bb [ dst src rep src rep-of emit-conversion ] add-instructions
bb dst ;
bb src insert-copy? [
rep next-vreg-rep :> dst
bb [ dst src rep src rep-of emit-conversion ] add-instructions
bb dst
] [ bb src ] if ;
: convert-phi ( ##phi -- )
dup dst>> rep-of '[ [ _ insert-copy ] assoc-map ] change-inputs drop ;

View File

@ -6,6 +6,7 @@ sets vectors
compiler.cfg.rpo
compiler.cfg.def-use
compiler.cfg.renaming
compiler.cfg.registers
compiler.cfg.dominance
compiler.cfg.instructions
compiler.cfg.liveness.ssa
@ -60,15 +61,23 @@ SYMBOL: copies
GENERIC: prepare-insn ( insn -- )
: try-to-coalesce ( dst src -- ) 2array copies get push ;
M: insn prepare-insn
[ defs-vreg ] [ uses-vregs ] bi
2dup empty? not and [
first
2dup [ rep-of ] bi@ eq?
[ try-to-coalesce ] [ 2drop ] if
] [ 2drop ] if ;
M: ##copy prepare-insn
[ dst>> ] [ src>> ] bi 2array copies get push ;
[ dst>> ] [ src>> ] bi try-to-coalesce ;
M: ##phi prepare-insn
[ dst>> ] [ inputs>> values ] bi
[ eliminate-copy ] with each ;
M: insn prepare-insn drop ;
: prepare-block ( bb -- )
instructions>> [ prepare-insn ] each ;

Some files were not shown because too many files have changed in this diff Show More