The RTL is getting a bit of attention these days, with plenty of visual effects, tweens and more being added to it. It’s easy to forget that sometimes even the smallest things can be of utmost importance. Like how to tell a single from a double via code!
As you may have noticed, Smart Mobile suddenly got support for streams, memory allocation and the ability to manipulate data on byte and bit level. This may sound trivial but it actually changes how we write and deal with data completely. Under vanilla JavaScript working with bits and bytes can be a huge problem. Most JS developers shun native, raw data like the plauge – because they cant do much with it. Well, thats not going to be a problem for us! Buffers, streams, memory allocation, move, copy — easy as apple pie 🙂
Effect Virtual Machine
Today I was fiddling with a “mini language” module I have been working on. Actually it’s an effect module that allows you to script and compile effect logic in smart pascal itself, so almost like a second language. If you ever played around with Amos Basic on the Amiga home computer back in the 90’s, you may remember that Amos had a secondary animation language? Well, on that old computer sprites and animation was interrupt based (just think threads if you dont have any idea what hardware interrupts are). This allowed the creator of Amos Basic, Francois Lionet, to add a really cool animation language which was executed in the background — allowing your main program to run in parallell to your animation code.
I dont know how many months and years I spent coding Amos and BlitzBasic in my teens, but let’s just say it was A LOT! Francois Lionet and Mark Sibly, the author of BlitzBasic and the Blitz compiler chain were my absolute childhood heroes.
Well, that animation language (but better naturally) is in effect what I am hoping to achieve with my little virtual machine. I really want it to be super-easy to create awesome effects, and I want it to be fast, flicker free and smooth as a baby’s bottom. So a mini bytecode system seems like just the ticket to get that working – and naturally it’s written in smart itself, so you can play around with it when it’s done.
But back to the problem: I had to extend the TReader and TWriter class with the abillity to handle variant datatypes. This also meant adding “word” as a new RTL datatype to handle those 16 bit values. And last but not least — detecting the difference between 32 and 64 bit floating points.
I mean, if you get that wrong it’s going to cause havoc!
CodeSeg and DataSeg
In a bytecode virtual machine like, say, Java or CLR (common language runtime, .NET style) your compiler have to deal with two different things: code and data. One thing is variables (both global and local), but what about constants? Whenever you pass a fixed value to a procedure, that value is actually a constant. It doesnt change and it will be compiled with your program. Well this is where the compiler get’s smart and picks that up, and the value is stored in a special list. So when the program runs, it will fetch that constant from storage and use it. Or, in case of the CLR, it will be compiled directly into the bytecode if it’s an intrinsic value (long story).
As you probably guess, that’s called a dataseg (data segment), which is different from a codeseg, where the opcode and “asm” is stored.
So thats when i suddenly realized: we have no function in the RTL to tell the difference between a 32bit float and a 64bit float !
Well here is one way of telling the difference. It’s already incorporated into the Read/Write variant, which are functions I added to TReader and TWriter. So you dont have to worry about it. But for those that have (for some odd reason) been looking for this — here it is:
function IsFloat32(const x:variant):Boolean; begin asm @result = isFinite(@x) && @x == Math.fround(@x); end; end;
Not much is it? But yet so important.
IMHO this is a working, but weird and uneffective approach.
AFAIK In modern JVM, a float is always stored as a double. See http://jayconrod.com/posts/52/a-tour-of-v8-object-representation and https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_Reference/JS::Value
What you check here is not that the value “is” a single, but that the value “could be stored” as a single, without precision lost.
For instance,
– Math.fround(1.5) = 1.5 so 1.5 would return true
– Math.fround(1.337) = 1.3370000123977661 so 1.337 would return false
You should not trust such a function for TReader and TWriter classes, but use the RTTI, i.e. the explicit type defined in source code. AFAIR, there is no such information in SMS (since there is no “single” type), so you should let the application supply the expected precision type to be used for each float field. If there is no such information, use double.
I’m afraid its not that straight-shooting. If it was, we would naturally have done so.
If you look in the RTL and the TDatatype class and have a peek at the code you will see it. Especially the methods Float32ToBytes() and Float64ToBytes(). These are stored quite differently in memory by the browser, so what the JVM does behind the scenes have little effect on how we can work with these types.
When you are looking to store a value, be it a single byte or a 64bit float, there are other rules that kick in. Also, when I write code for the RTL i have two sides to care for: the first is the SMS user and the pascal side of things, the second is how data is presented from the JS side and various libraries.
The code presented here allows me to tell the difference between double and single, which is paramount when storing these values as binary data. Nothing more nothing less 🙂