MAINSAIL Language Manual, Chapter 27

previous   next   top   contents   index   framed top   this page unframed


27. Potential Pitfalls in Moving a 32-Bit MAINSAIL Application to 64-Bit MAINSAIL

64-bit implementations of MAINSAIL are newer than 32-bit implementations and have somewhat different characteristics, so there some potential problems you should be aware of when writing 64-bit code or porting existing 32-bit applications to a 64-bit platform.

A 64-bit implementation of MAINSAIL provides a much larger address space than a 32-bit implementation, and also a greatly expanded range of values for the data types LONG INTEGER and LONG BITS. However, to take advantage of these features, you must make sure that your code does not contain implicit assumptions that it is running on a 32-bit implementation of MAINSAIL.

Theoretically, a carefully coded 32-bit MAINSAIL program should not need any changes when ported to a 64-bit platform, but it is not difficult for some 32-bit dependencies to creep into your code.

It is uncertain when, or whether, machines with 128-bit address spaces will be introduced. If MAINSAIL is ever ported to such a machine, it may be necessary to eliminate 64-bit dependencies from your code. However, XIDAK does not anticipate the need to do so anytime soon.

27.1. Constants

Beware of constants that are 32-bit dependent, like those in the following examples:

Possibly32-Bit-Dependent Works for 32-Bit and 64-Bit MAINSAIL
4 size(longIntegerCode)
31 $sizeInBits(longIntegerCode) - 1
32 $sizeInBits(longIntegerCode)
2L ^ 31 - 1L $maxLongInteger
'HFFFFFFFFL $lbOnes
'H80000000L '1L SHL ($sizeInBits(longIntegerCode) - 1)
DEFINE hexDigitsInAddress = 8; DEFINE hexDigitsInAddress = size(addressCode) * 2;

27.2. Alignment Gaps

Currently, no 32-bit MAINSAIL compiler pads record layouts with gaps for alignment purposes (see Section 10.13), but all 64-bit systems do. Alignment gaps used by 64-bit MAINSAIL can affect existing code. For example, consider the following code where INTEGERs are 4 bytes, LONG INTEGERs are 8 bytes, and both must be aligned to their size boundary:

i := iLoad(a);
a := displace(a,size(integerCode));
li := liLoad(a);

If a is initially at an 8-byte alignment, the liLoad fails since a is only at a 4-byte alignment when the liLoad is executed. This code works on 32-bit MAINSAIL implementations, but must be changed before being executed on 64-bit MAINSAIL. The programmer has incorrectly assumed that a LONG INTEGER can immediately follow an INTEGER in memory, with no alignment gaps.

27.3. Relationship between MAINSAIL and C Data Types

In the 32-bit world, MAINSAIL INTEGERs and LONG INTEGERs, and C ints and longs, are all 4 bytes.

Consider the following C struct:

struct cFoo {int f;};

Assuming a C int is 4 bytes, in 32-bit MAINSAIL the following class accurately represent cFoo:

CLASS mFoo (LONG INTEGER f);

In 64-bit MAINSAIL, with an LP64 C model (in which C longs and pointers are each 64 bits), mFoo does not represent cFoo since mFoo.f is 8 bytes whereas cFoo.f is 4 bytes. The correct approach is to use the C data type names introduced in Version 15 of MAINSAIL:

$ALIGN CLASS mFoo ($CINT f);

This works for both 32-bit MAINSAIL and 64-bit MAINSAIL.

Similarly, a C procedure that takes an int array could be declared in 32-bit MAINSAIL as:

PROCEDURE foo (LONG INTEGER ARRAY(0 TO *) ary);

This should be declared as:

PROCEDURE foo ($CINT ARRAY(0 TO *) ary);

which works for both 32-bit and 64-bit MAINSAIL.

A MAINSAIL entry FLI procedure that takes an ADDRESS a of a C int and accesses the int using liLoad(a) should instead use $liLoadSized(a,0,$cIntCode).

Another example is a buffer created by C, packed with C shorts. If MAINSAIL has been passed an ADDRESS a that points to the buffer, then the following code can be used in 32-bit MAINSAIL on big-endian machines to access the shorts:

DOB read(a,bb);
    
firstShort := bb SHR 16; secondShort := bb MSK 'HFFFFL;
    ... 
END;

This code assumes a C short is 16 bits and a MAINSAIL long bits is 32 bits; this assumption is incorrect in 64-bit MAINSAIL. Portable code for the above is as follows:

DOB firstShort := $lbLoadSized(a,0,$cShortCode);
    
a := displace(a,$shortSize);
    
secondShort := $lbLoadSized(a,0,$cShortCode);
    
a := displace(a,$shortSize);
    ... 
END;

27.4. Assumption That size(realCode) = size(longBitsCode))

Even though it was never documented that size(realCode) = size(longBitsCode), this was true until the first implementation of 64-bit MAINSAIL. The following procedure is not portable:

LONG BITS PROCEDURE realToLb (REAL r);
BEGIN
OWN ADDRESS a;
IF NOT a THEN a := newScratch(size(realCode));
store(a,r); RETURN(lbLoad(a)) END;

The following version currently works on both 32-bit and 64-bit MAINSAILs:

LONG BITS PROCEDURE realToLb (REAL r);
BEGIN
OWN ADDRESS a;
IF NOT a THEN a := newScratch(size(realCode));
store(a,r);
following IFC allows for case that a MAINSAIL real is 8 bytes
RETURN(
    
IFC size(realCode) = 4 THENC
    
$lbLoadSized(a,0,$longBits4Code)
    
$EFC size(longBitsCode) = size(realCodeTHENC
    
lbLoad(a)
    
ELSEC MESSAGE "realToLbimpossible","error"; '0L ENDC);
END;

Note that the language does not guarantee that the REAL data type occupies only 4 bytes. It is possible that a future implementation of MAINSAIL might provide 8-byte REALs.

27.5. Assumption That size(longBitsCode) = 32

The following procedure works for 32-bit but not for 64-bit MAINSAIL:

INTEGER PROCEDURE findFirstSetBit (LONG BITS bb);
BEGIN
INTEGER n;
IF NOT bb THEN RETURN(-1); # no bits set
n _ 0;
IF bb NTST 'HFFFFL THENB bb .SHR 16; n .+ 16 END;
IF bb NTST 'HFFL THENB bb .SHR 8; n .+ 8 END;
IF bb NTST 'HFL THENB bb .SHR 4; n .+ 4 END;
IF bb NTST '3L THENB bb .SHR 2; n .+ 2 END;
IF bb NTST '1L THEN n .+ 1;
RETURN(nEND;

To allow it to work on 64-bit machines, add the following as the first statement:

IFC size(longBitsCode) = 8 THENC
IF bb NTST 'HFFFFFFFFL THENB bb .SHR 32; n .+ 32 END;
ENDC

27.6. Data Files

Data files that contain LONG INTEGERs and long bits are not portable between 32-bit and 64-bit MAINSAIL.

27.7. FLI Parameter Data Types and C Data Type Macros

It is strongly recommended (starting with Version 16.29 of MAINSAIL) that you use the appropriate C data type macros ($CSHORT, $CINT, etc.; see
Appendix L) when declaring parameter types for FLI procedures (this is not recommended in earlier versions of MAINSAIL because the FLI compiler did not take explicit sizes of parameter data types into account). For example, instead of declaring an FLI procedure:

PROCEDURE p (MODIFIES LONG INTEGER s);       # WRONG!

declare:

PROCEDURE p (MODIFIES $CINT s);

because the latter will work on any platform, provided that the corresponding C function declares its parameter as a int, whereas the first form would not work on any current 64-bit platform, because MAINSAIL's LONG INTEGER is the same size as a C long, but not an int, on those platforms.

For FLI code that predates Version 16.29 and therefore does not use the C data type macros, consult the appropriate operating-system-specific documentation (e.g., Table 10–1 of the User's Guide for MAINSAIL on UNIX for UNIX) for the correspondence of MAINSAIL and C data types in FLI procedures.

27.8. PDF

MAINSAIL'S PDF (portable data format) uses 2-byte BOOLEANs, INTEGERs and BITS, 4-byte LONG INTEGERs and LONG BITS, and 8-byte LONG REALs. This results in restrictions on the range of INTEGER and BITS values in PDF data for 32-bit MAINSAIL, and, in addition, LONG INTEGER and LONG BITS values for 64-bit MAINSAIL.

If you attempt to write out to a PDF file a LONG INTEGER or LONG BITS value that exceeds the 32-bit range, the value will be silently truncated to 32 bits. If this poses a problem, please contact XIDAK for assistance.


previous   next   top   contents   index   framed top   this page unframed

MAINSAIL Language Manual, Chapter 27