OSStructure protocols
This section describes the protocols supported by OSStructure.
Class methods: layout info
members
Answer an Array of in-order member names.
typeDescriptors
Answer an Array of type descriptors in member order
alignmentType
Answer one of the enumerated values from the OSAlignments Pool Dictionary.
structureAlignment
Answer the computed structure alignment.
Note: To force a specific structure alignment, the OSStructure subclass may override the method OSStructure class>>structureAlignmentOverride to answer a specific Integer byte value.
Class methods: query
typeAt: aSymbol
Answer the type descriptor at the field named aSymbol
Class methods: initialization
members: aMemberArray types: aTypeDescriptorArray alignmentType: theAlignmentType
Initialization method to allow for structure objects to have their fixed size and offsets computed dynamically based on aMemberArray, aTypeDescriptorArray and theAlignmentType.
aMemberArray - Array of <Symbol>s describing the names of the struct members. These must be in member order.
aTypeDescriptorArray - Array of <Symbol>s describing the data types of the members. These must also be in member order. Below is a classification of the various type descriptors.
Base Types - These are the default primitive base types that are found the the TypeMappings class variable of OSStructure. These can also be extended by the user by injecting new types into TypeMappings.
Examples: bool8, bool16, bool32, char8, char16, double, float, float32, float64, int8, int16, int32, int64, pad, pointer, spointer, ssize, uint8, uint16, uint32, uint64, upointer, usize
Nested Structures/Unions - If a member is a nested structure/union which has been modeled by an OSStructure/OSUnion subclass, then the name of the OSStructure/OSUnion can be used as the type descriptor.
Example: Given struct Foo { int a; int b; } and struct Bar { Foo x; int y; }, then the definitions for OSStructure Foo and Bar would be:
Foo members: #(a b) types: #(int32 int32)
Bar members: #(x y) types: #(Foo int32)
Anonymous Structures/Unions - Anonymous Unions are represented by grouping the member names and type descriptors with a single set of parentheses. Anonymous Structures also require a single set of parentheses for the member array, but a double set of parentheses for the type descriptor array. This is easier to understand by example:
Example 1: Given struct Foo { union { char x; double y; }; char z; }, then the definition for OSStructure Foo would be:
Foo members: #( (x y) z ) types: #( (char8 double) char8).
Example 2: Given struct Foo { struct { char x; double y; }; char z; }, then the definition of OSStructure Foo would be:
Foo members: #( (x y) z ) types: #( ((char8 double)) char8).
theAlignmentType - One of the enumerated values from the OSAlignments pool dictionary. These include:
AlignNone - No alignment computation is performed. Members are aligned on nearest 1-byte boundary. This can be used in conjunction with custom padding types to achieve specialized alignments
AlignDefault - Alignment will be automatically computed based on the rules of the current platform.
AlignMsvc - Alignment Rules for Windows/MSVC
AlignGnuc - Alignment Rules for GNU C
Align2 - Alignment on 2-byte boundaries
Align4 - Alignment on 4-byte boundaries
Align8 - Alignment on 8-byte boundaries
Align16 - Alignment on 16-byte boundaries
members: aMemberArray types: aTypeDescriptorArray
Initialization method to allow for structure objects to have their fixed size and offsets computed dynamically based on aMemberArray and aTypeDescriptorArray. AlignDefault will be used as the default alignment type.
indirectionLevel
Answer the receiver's indirection level.
Protocol Usage Examples
OSStructures have an auto-layout generation capability that radically simplifies writing code to access native structures. This simplification is due to the fact that developers no longer need to compute member offsets by hand. Instead, all OSStructure subclasses do this automatically.
In order to have VA Smalltalk generate the layout of an OSStructure subclass automatically, a definition of the native structure must be provided. Typically, this is done at load time meaning that once an OSStructure is loaded into the running image, then its definition should be defined.
OSStructure subclasses may also override a class side method called regenerateDefinition. This method is called at image startUp and allows for dynamically adjusting the definition based on some criteria. While the criteria is user-defined, the motivation is for 32-bit images being loaded on a 64-bit virtual machine. In this scenario, some structures may have a different definition when compiled with a 64-bit compiler and therefore certain OSStructures may need to redefine themselves before the image finishes starting up.
Separately, the layout of an OSStructure may need to be recomputed even though its definition is the same. This occurs for all OSStructures when loading a 32-bit image on a 64-bit virtual machine. The reason has to do with the change in native pointer sizes which impacts member offsets. For example, given the struct Foo { char *x; char y; }, y has a (0-based) offset of 4 in a 32-bit environment, but an offset of 8 in a 64-bit environment. In both environments the definition of the structure is exactly the same, however the layout is different.
Below are some examples to help understand how to define various native structures.
Base Types
Native: struct Foo { int x; double y; char * z; }
Smalltalk: Foo members: #(x y z) types: #(int32 double pointer)
 
Native: struct Foo { int x; double y; char * z; }
Smalltalk: Foo members: #(x y z) types: #(int32 double 'char *') "Alternative Pointer Syntax"
 
Arrays
Native: struct Foo { int x[10]; double y }
Smalltalk: Foo members: #(x y) types: #('int32[10]' double)
 
Native: struct Foo { char * x[10]; }
Smalltalk: Foo members: #(x) types: #('char8 * [10]') "Array of Pointers"
 
Nested
Native:
struct Foo { char x; char y; }
struct Bar { Foo foo; }
 
Smalltalk:
Foo members: #(x y) types: #(char8 char8).
Bar members: #(foo) types: #(Foo). "Name of an OSStructure subclass treated as a type"
 
Anonymous Structs
Native: struct Foo { struct { int x; char y; }; double z; }
Smalltalk: Foo members: #( (x y) z ) types: #( ((int32 char8)) double ). "Double-Parens in type specification"
 
Anonymous Unions
Native: struct Foo { union { int x; char y; }; double z; }
Smalltalk: Foo members: #( (x y) z ) types: #( (int32 char8) double ). "Single-Parens in type specification"
 
Manual Padding
Native: struct Foo { char x; void * y; }
Smalltalk: Foo members: #(x y) types: #(char8 pad pad pad pointer) alignmentType: AlignNone. "Specify 3-bytes of manual padding between the members"
 
Native: struct Foo { char x; void * y; }
Smalltalk: Foo members: #(x y) types: #(char8 'pad[3]' pointer) alignmentType: AlignNone. "Alternative Padding Syntax"
 
Packing
Native:
#pragma pack(2) // 2-byte packing rules
struct Foo { char x; unsigned int y; }
 
Smalltalk:
Foo members: #(x y) types: #(char8 uint32) alignmentType: Align2 "2-byte packing rules"
 
Last modified date: 11/05/2019