windows


FillChar under Delphi 10.2 for Win64 Release Target


I have a question about a specific programming problem in Delphi 10.2 Pascal programming language.
The StringOfChar and FillChar don’t work properly under Win64 Release build on CPUs released before year 2012.
Expected result of FillChar is just plain sequence of just repeating 8-bit characters in a given memory buffer.
Expected result of StringOfChar is the same, but the result is stored inside a string type.
But, in fact, when I compile our applications that worked in Delphi prior to 10.2 by the 10.2 version of Delphi, our applications compiled for Win64 stop working properly on CPUs released before year 2012.
The StringOfChar and FillChar don’t work properly – they return a string of different characters, although in a repeating pattern – not just a sequence of the same character as they should.
Here is the minimal code enough to demonstrate the issue. Please note that the length of the sequence should be at least 16 characters, and the character should not be nul (#0). The code is below:
procedure TestStringOfChar;
var
a: AnsiString;
ac: AnsiChar;
begin
ac := #1;
a := StringOfChar(ac, 43);
if a <> #1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1 then
begin
raise Exception.Create('ANSI StringOfChar Failed!!');
end;
end;
I know that there are lots of Delphi programmers at StackOverflow. Are you experiencing the same problem? If yes, how you resolve it? What is the solution? By the way, I have contacted the developers of Delphi but they didn’t confirm nor deny the issue so far. I'm using Embarcadero Delphi 10.2 Version 25.0.26309.314.
Update:
If your CPU is manufactured in 2012 or later, additionally include the following lines before calling StringOfChar to reproduce the issue:
const
ERMSBBit = 1 shl 9; //$0200
begin
CPUIDTable[7].EBX := CPUIDTable[7].EBX and not ERMSBBit;
As about the April 2017 RAD Studio 10.2 Hotfix for Toolchain Issues - have tried with it and without it - it didn't help. The issue exists regardless of the Hotfix.
StringOfChar(A: AnsiChar, count) uses FillChar under the hood.
You can use the following code to fix the issue:
(*******************************************************
System.FastSystem
A fast drop-in addition to speed up function in system.pas
It should compile and run in XE2 and beyond.
Alpha version 0.5, fully tested in Win64
(c) Copyright 2016 J. Bontes
This Source Code Form is subject to the terms of the
Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,
You can obtain one at http://mozilla.org/MPL/2.0/.
********************************************************
FillChar code is an altered version FillCharsse2 SynCommons.pas
which is part of Synopse framework by Arnaud Bouchez
********************************************************
Changelog
0.5 Initial version:
********************************************************)
unit FastSystem;
interface
procedure FillChar(var Dest; Count: NativeInt; Value: ansichar); inline; overload;
procedure FillChar(var Dest; Count: NativeInt; Value: Byte); overload;
procedure FillMemory(Destination: Pointer; Length: NativeUInt; Fill: Byte); inline;
{$EXTERNALSYM FillMemory}
procedure ZeroMemory(Destination: Pointer; Length: NativeUInt); inline;
{$EXTERNALSYM ZeroMemory}
implementation
procedure FillChar(var Dest; Count: NativeInt; Value: ansichar); inline; overload;
begin
FillChar(Dest, Count, byte(Value));
end;
procedure FillMemory(Destination: Pointer; Length: NativeUInt; Fill: Byte);
begin
FillChar(Destination^, Length, Fill);
end;
procedure ZeroMemory(Destination: Pointer; Length: NativeUInt); inline;
begin
FillChar(Destination^, Length, 0);
end;
//This code is 3x faster than System.FillChar on x64.
{$ifdef CPUX64}
procedure FillChar(var Dest; Count: NativeInt; Value: Byte);
//rcx = dest
//rdx=count
//r8b=value
asm
.noframe
.align 16
movzx r8,r8b //There's no need to optimize for count <= 3
mov rax,$0101010101010101
mov r9d,edx
imul rax,r8 //fill rax with value.
cmp rdx,59 //Use simple code for small blocks.
jl #Below32
#Above32: mov r11,rcx
mov r8b,7 //code shrink to help alignment.
lea r9,[rcx+rdx] //r9=end of array
sub rdx,8
rep mov [rcx],rax
add rcx,8
and r11,r8 //and 7 See if dest is aligned
jz #tail
#NotAligned: xor rcx,r11 //align dest
lea rdx,[rdx+r11]
#tail: test r9,r8 //and 7 is tail aligned?
jz #alignOK
#tailwrite: mov [r9-8],rax //no, we need to do a tail write
and r9,r8 //and 7
sub rdx,r9 //dec(count, tailcount)
#alignOK: mov r10,rdx
and edx,(32+16+8) //count the partial iterations of the loop
mov r8b,64 //code shrink to help alignment.
mov r9,rdx
jz #Initloop64
#partialloop: shr r9,1 //every instruction is 4 bytes
lea r11,[rip + #partial +(4*7)] //start at the end of the loop
sub r11,r9 //step back as needed
add rcx,rdx //add the partial loop count to dest
cmp r10,r8 //do we need to do more loops?
jmp r11 //do a partial loop
#Initloop64: shr r10,6 //any work left?
jz #done //no, return
mov rdx,r10
shr r10,(19-6) //use non-temporal move for > 512kb
jnz #InitFillHuge
#Doloop64: add rcx,r8
dec edx
mov [rcx-64+00H],rax
mov [rcx-64+08H],rax
mov [rcx-64+10H],rax
mov [rcx-64+18H],rax
mov [rcx-64+20H],rax
mov [rcx-64+28H],rax
mov [rcx-64+30H],rax
mov [rcx-64+38H],rax
jnz #DoLoop64
#done: rep ret
//db $66,$66,$0f,$1f,$44,$00,$00 //nop7
#partial: mov [rcx-64+08H],rax
mov [rcx-64+10H],rax
mov [rcx-64+18H],rax
mov [rcx-64+20H],rax
mov [rcx-64+28H],rax
mov [rcx-64+30H],rax
mov [rcx-64+38H],rax
jge #Initloop64 //are we done with all loops?
rep ret
db $0F,$1F,$40,$00
#InitFillHuge:
#FillHuge: add rcx,r8
dec rdx
db $48,$0F,$C3,$41,$C0 // movnti [rcx-64+00H],rax
db $48,$0F,$C3,$41,$C8 // movnti [rcx-64+08H],rax
db $48,$0F,$C3,$41,$D0 // movnti [rcx-64+10H],rax
db $48,$0F,$C3,$41,$D8 // movnti [rcx-64+18H],rax
db $48,$0F,$C3,$41,$E0 // movnti [rcx-64+20H],rax
db $48,$0F,$C3,$41,$E8 // movnti [rcx-64+28H],rax
db $48,$0F,$C3,$41,$F0 // movnti [rcx-64+30H],rax
db $48,$0F,$C3,$41,$F8 // movnti [rcx-64+38H],rax
jnz #FillHuge
#donefillhuge:mfence
rep ret
db $0F,$1F,$44,$00,$00 //db $0F,$1F,$40,$00
#Below32: and r9d,not(3)
jz #SizeIs3
#FillTail: sub edx,4
lea r10,[rip + #SmallFill + (15*4)]
sub r10,r9
jmp r10
#SmallFill: rep mov [rcx+56], eax
rep mov [rcx+52], eax
rep mov [rcx+48], eax
rep mov [rcx+44], eax
rep mov [rcx+40], eax
rep mov [rcx+36], eax
rep mov [rcx+32], eax
rep mov [rcx+28], eax
rep mov [rcx+24], eax
rep mov [rcx+20], eax
rep mov [rcx+16], eax
rep mov [rcx+12], eax
rep mov [rcx+08], eax
rep mov [rcx+04], eax
mov [rcx],eax
#Fallthough: mov [rcx+rdx],eax //unaligned write to fix up tail
rep ret
#SizeIs3: shl edx,2 //r9 <= 3 r9*4
lea r10,[rip + #do3 + (4*3)]
sub r10,rdx
jmp r10
#do3: rep mov [rcx+2],al
#do2: mov [rcx],ax
ret
#do1: mov [rcx],al
rep ret
#do0: rep ret
end;
{$endif}
The easiest way to fix your issue is to Download Mormot and include SynCommon.pas into your problem. This will patch FillChar to the above code and include a couple of other performance improvements as well.
Note that you don't need all of Mormot, just SynCommons by itself.

Related Links

How to append to the PATH variable in Visual studio 2013
UI Response Monitoring Tools
Renaming specific files in windows batch file
SolrException: field name_tag has no indexed data
Trying to create a batch file that counts the time it takes to open another batch file
CreateProcessAsUser doesn't run the application
How to import pfx certificate and set private key permissions for all users
Windows Git issue with Network Path
How to enforce certain control panel changes to all users
Filenames with . in batch file
how to find out who is running the runas application?
QT 5.6.0 MSVC2015 32bit “Qt Creator needs a compiler set up to build” [duplicate]
Smalltalk Windows application works in debug mode; .exe hangs
Delete certain and previous line from textfile using batch file?
Use stunnel to support GOST on Windows
windows command-line usage or creating a bat file with specific commands [duplicate]

Categories

HOME
azure-stream-analytics
turing-machines
nvd3.js
angular-formly
pascal
knitr
grafana
newrelic
xbee
carousel
soa
rom
regular-language
maxscript
jax-ws
character
qpython
spin
supervisor
favicon
gkturnbasedmatch
code-generation
atlassian
scrolltop
mongodb-csharp
atlassian-stash
video-editing
asciidoctor-pdf
rubymotion
hta
tosca
moses
fable-f#
event-flow
xbox
wacom
mailkit
carriage-return
roblox
raft
alphabetical
git-rewrite-history
sim-card
apns-php
google-data-api
magento-1.9.3
ssrs-2014
smoothstate.js
avcapturedevice
strftime
pom.xml
linter
tf
convex-optimization
trojan
java-6
seq
filenet
testrail
redistributable
async.js
neon
cifilter
udpclient
shopping
jtwig
lua-telegram-bot
uiactionsheet
django-urls
google-books
ocra
jsvc
teamcity-9.1
nsurlsessiondatatask
rrule
dbaccess
boost-program-options
post-commit-hook
sql-scripts
wcm
ss7
decoupling
accesscontrolexception
openargs
ie8-compatibility-mode
unit-of-work
observium
css-reset
swfobject
apache-abdera
idn
extreme-programming
midlet
veracity
faye
django-piston
lobo-cobra
cuda.net
complex-event-processing
leader

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App