BASM may not be in the Delphi 64 preview [1], but a proof of concept of “BASM-for-DWS” is now available for DWScript in the SVN!
It builds upon recently introduced “language extensions”, to allow “asm” blocks, which will be pre-parsed (to allow BASM-like references to local variables), and then fed to NASM [2] for actual assembling (which you’ll need to download).
const cOne = 1.0; function RSqrt(x : Float) : Float; begin asm // Result := 1/Sqrt(x); fld x; fsqrt; fld cOne; // could have used fld1 here fdivr; fstp Result; end; end; PrintLn(RSqrt(1/4));
You can have multiple asm sections, intersperse them with regular code, etc.
Language extensions for DWScript
The language extension mechanism allows to hook into the compiler, and handle part of the parsing on a source file. You can add to the language without affecting the DWS compiler core itself, and if not used explicitly, language extensions won’t be compiled, referred, or otherwise impact in any way DWS.
You activate extensions per TDelphiWebScript component, by dropping the relevant extension component (a subclass of TdwsCustomLangageExtension) anywhere you wish, and linking the relevant Script component via the Script property.
More pragmatic targets for extensions would be introducing unsafe features (like DLL imports), compile-time parsed SQL, opcodes for industrial automatons/printers, introducing constructs from other languages that may not fit with the general canon of Pascal, experimenting with alien syntaxes, etc. you name it.
Notes on DWScript’s asmExtension
BASM was picked to experiment with the extension mechanism, as it’s kind of a low hanging fruit: a block delimited by asm and end, with access to the symbol table, that generates a custom expression, and whose actual parsing can be handled by a ready-made tool.
Note that the BASM part introduced here, though usable, will likely remain minimalistic, at least until Delphi 64 comes around.
The assembler uses NASM, and so supports all the instructions NASM supports, though there are a few things to keep in mind:
- you must place nasm.exe in the same directory as your applications. Temporary files will be used during the assembly (in the temp folder). NASM may be bundled in a later version, but right now, it isn’t.
- a semi-colon ‘;’ is expected after instructions, a colon ‘:’ after labels, and comments are regular ones (not NASM-style).
- right now, BASM for DWS exposes constants, local variables, regular parameters (that are neither var nor const) and Result (for functions), when they are of type Integer (64bit), Float (double precision), String (pointer to the PChar) and Boolean (word).
- DWS variables are stored in variants, its arrays are thus array of variants, though the exposed address goes to the data portion of variants.
- the exposure mechanism is still simplistic, via defines, and if you have a local variable named ‘eax‘ f.i., it will take precedence over the similarly named register… Same goes for instructions.
- the EBP register with offsets is used to expose variables, constants are exposed with absolute addresses (and are unified, btw), if you want to return before the exit point, you’ll have to “pop ebp” manually. As usual, you can do whatever you wish with eax, edx & ecx, other registers have to be preserved.
- you can use @variable to get only the address of a variable, f.i. for a float variable, myfloat could be “qword [ebp-8]” and @myfloat would be “ebp-8“.
- you can only jump and call within the asm block.
Of course, using any asm makes the script execution wholly unsafe, that’s why it’s in a language extension.