I have been experimenting with the address a lot. Assembler in Flowstone does not have capabilities to do system calls - you can't save data from assembler to disc. Hell, you can't even allocate new memory form it.
However, ruby can pass pointers to its binary strings.
- Code: Select all
str= "abcdefg"
address=[str].pack("P") #returns new string with 4byte pointer to the contents "str" variable.
address.unpack("P7") #returns first 7 characters from the string to which the address points.
#you can convert the pointer into int or float and output it to flowstone.
#this way you can access the contents of the string in assembler
output address.unpack("L") #converts the address to integer and outputs it to flowstone
In fact, I do believe this is how the Frame class is implemented in flowstone. it has internal string containing the actual data. ".data" method outputs the address of that string, which flowstone then uses in mono-to-frame and frame-to-mono prims to write/read its contents. Evidence of this is, that when you change the implemnentation of data method in frame class, frames no longer work in FS until you restart it (which restores original Frame class implementation).
Only problem is, it works only one way. You can't convert arbitrary address to ruby string object - you get "no associated pointer" exception. This is because ruby handles the actual pointer internally. In the example above,
"address" string object internally holds hidden reference to the original "str" string object (the same kind of reference that is used by ruby garbage collector to free unused objects). When you call the "unpack("P")" method, the method checks if the address in this string matches any object that it internally references. If not, "no associated pointer" error is raised - even if actual string object exists at that address.
- Code: Select all
str= "abcdefg"
address=[str].pack("P")
int_address=address.unpack("L") #unpacks the address as a integer
#this integer no longer holds reference to "str" object
copy_of_address=int_address.pack("L") #packs the integer as new string
copy_of_address==address #returns true, because both of these contain the same data
address.unpack("P7") #returns "abcdefg" - the contents of "str" string, to which it holds hidden reference
copy_of_address.unpack("P7") #raises error, despite the fact it contains address, it doesn't secretly reference matching object.
What this allows us to do is to create string buffer in Ruby, pass its address and address of the frame to assembler. In assembler copy contents of the frame into the buffer. In ruby save the buffer to file. This allows us to skip conversion of frame to array.
However, I think it would be better if we would modify the Frame class. Specifically, we would add some kind of "rawData" method which would return its internal string directly. Unfortunately, it has proven to be easier said than done. Frame.new(n).instance_variables does return empty array, which means the data isn't stored in instance vars. Similarly Frame.constants and Frame.class_variables returns empty array, which means none of the data is actually stored anywhere in the class or its instances. I am trying to find a way to access the referenced objects which would allow me to pinpoint the location of the data.
Another approach would be to rewrite the Frame class entirely from scratch. Assuming what I said above is true, it should be possible to reverse-engineer all methods in the class and then add our own, now knowing where the data is...