Hi Charles,
I swear in all honesty that everything I'm telling you is true to the last word.
The FBSL binaries currently carry about 50KB of tightly zipped data (mainly keyword and message tables, and a few auxiliary hash tables such as are usually used for cyclic redundancy checks, password creation and script obfuscation) that are the first to get decompressed and mapped into the process memory once the process starts. Then FBSL's built-in constants are created and the internal functions that are supposed to execute FBSL's high-level BASIC bytecode are mapped into the respective hash tables. All in all, it takes up to 20 milliseconds to launch FBSL proper including the time it takes the OS to connect all the relevant system libraries to the FBSL process.
It takes another 30 to 60 milliseconds to parse, precompile to bytecode and/or JIT machine code, and launch a medium sized BASIC+DynC+DynAsm scripted project of about 10 to 15 thousand code lines (that's my favorite size
) for execution. Anything less than a thousand code lines can hardly be benchmarked. It may take yet a couple milliseconds more to decompress and deobfuscate the same script if it is embedded in a precompiled executable in the form of an LZMA-compressed payload. Decompression/deobfuscation runs at about 15MB of scripted code per second. Then, code parsing and precompilation proper begins.
First, the four DLLs I told you about are scanned for the constituent API names and entry points, and an approx. 200KB large Windows.inc file for the BASIC preprocessor is scanned (that's roughly a WINDOWS_LEAN_AND_MEAN equivalent), and the respective hash tables are created.
Next, the BASIC compiler starts its work. It's a three-pass compiler with a multiply reentrant recursive descent parser. The first pass is used to tokenize the entire script including BASIC, C, and asm vocabulary. The second pass creates the actual binary bytecode tree and resolves cross-references between BASIC, C, asm, and external procedures. That's the heaviest pass of all the three, and it takes GCC almost a minute to compile that file alone on my 3.2GHz PC. The third pass is used for some simple optimization of BASIC bytecode like macro expansion and constant propagation.
At pass 2 of BASIC bytecode compiler, Dynamic C and Dynamic Asm jitters also compile their respective code blocks from the tokens prepared by the BASIC compiler during its pass 1. The Dynamic C JIT compiler is a deeply nested one-pass recursive descent compiler based on Fabrice Bellard's Tiny C Compiler v0.9.25. Its compilation speed on my PC is on the order of 50MB of raw C code per second; it's simply lightning fast. The Dynamic Asm compiler is my own "1.5-pass" recursive descent compiler that does only one level deep recursion when resolving a label, and runs only one pass unless assembly contains forward references, in which case it runs a brief additional half-pass to fill in the blanks with i) actual addresses of forward references it didn't know how to resolve on its first pass, and ii) 1-clock variable-length NOP padding dummies like
mov eax, eax etc. where necessary. I've worked out a habit of avoiding forward references in my asm code altogether to make the compiler do everything in one pass, if possible, and to also make my asm code run a few clocks faster avoiding NOPs associated with forward references.
The DynAsm jitter works at about 10MB of asm code per second if not monitored via the Asm Logger window that's available in a special build of Fbsl.exe binary, in which case the speed would drop to some 4 or 5K lines of asm code per second.
I have never seen any script that would take FBSL more than 80 milliseconds to start executing. Actually, the OpenGL render context initialization routine alone written in FBSL BASIC in my current Objector project takes two or three times longer to execute than it takes FBSL to parse, compile, and start to execute this entire project with its main script plus 19 include files of BASIC, C, and assembly code.