How many bytes would a petabyte bite if a petabyte could bite bytes?
The CompactFlash association has just released a new specification for future CompactFlash cards. It involves big numbers. 144 petabytes big, to be specific. But how big is that really?
144 petabytes = 150,994,944 gigabytes.
Production quality 1080p video: 3 gigabits per second which equals 0.375 gigabytes per second.So, using that:
150,994,944 / 0.375 = 402,653,184 seconds of video = 6,710,886.4 minutes of video = 111,848.106. hours of video = 4,660.337. days of video = 12.768 years of continuous video
Got that? 12 years of continuous 1080p video. Slap around 9 of those in a camera and you can continuously video almost anyone for their entire life. May as well be generous and use 10 - that should let you stick some low quality sound recording of their entire life on it too.
I suspect the future will see an increased number of murders due to screenings of family holiday videos...
The curious case of Eclipse, msysgit, and the obstinate dot files
Just a quick tip if you are having problems with Eclipse, FDT or other Eclipse based tool and writing to dot files cloned from a git repository.
If you are seeing messages about not have permission to write to ".project", ".as3_classpath" and so on, there's a reasonable chance that msysgit (or potentially TortoiseGit) automatically set the dot files to hidden to mimic what you see on a real^h^h^h^h 'nix based machine. While this is nice, for some reason Eclipse, or possibly the underlying Java file calls, can't write to hidden files on Windows so you get access denied messages.
Fortunately, the solution is very simple. Open up a git Bash prompt, and enter this:
git config --global core.hidedotfiles false
And that's it. With core.hidedotfiles set to false, msysgit will no longer set the hidden property on dot files, and Eclipse should be ready to rock.
Of course, this only affects newly fetched files, so if you want to clear the hidden flag on existing files, jump into a cmd prompt (or this may work from the git bash prompt) and type:
cd folder_containing_the_repositoryattrib /s /d -H *
Compound operators, new and You.
Pop quiz time!
What appears on stage with the following code:
public function newChild() :void
{
addChild(new CircleSprite()).x += 50;
}
Wrong. This is what appears:
Of course, all you clever observant folks will have noticed that that the circle's x coordinate is being set using a compound operator, +=. That's the culprit in this unusual case.
Now, putting aside any crazy reasons for wanting to write code like that in the first place, what's actually going on here? Well, one way to find that out is by shrinking ourselves down and entering Inner (ABC) Space! (SPACE... SPAce... space...)
Yep, it's time to get roll up our sleeves and get oh, so dirty rooting around in the ActionScript Bytecode (herein known as ABC to spare my keyboard). It's not going to be pretty, and I'll probably misinterpret some of it but, just like a good orbital nuking, it's the only way to be sure. Also, like an orbital nuking, it's a little bit over the top, but I wanted an excuse to start becoming a little more au fait with ABC because, well, because I'm a geek and I like knowing how things work.
So, here are those lines once more, but in a format closer to what the Flash player VM sees:
function :CompoundOperatorsAndNew:::newChild()::void
maxStack:3 localCount:1 initScopeDepth:9 maxScopeDepth:10
getlocal0
pushscope
findpropstrict :addChild
findpropstrict :CircleSprite
constructprop :CircleSprite (0)
callproperty :addChild (1)
findpropstrict :addChild
findpropstrict :CircleSprite
constructprop :CircleSprite (0)
callproperty :addChild (1)
getproperty :x
pushbyte 50
add
setproperty :x
returnvoid
0 Extras
0 Traits Entries
Highlighted are the 2 groups of lines that cause the problem. 2 circle classes are being created with the lines "constructprop :CircleSprite (0)", and both are being added as children with "callproperty :addChild (1)".
Before we muse on why Flash compiled the ActionScript at the top of the article into this ABC, let's have a closer look at the bytecode and try and work out what it is doing.
In general bytecode, like assembler, is pretty straightforward. There's just an awful lot of it to trek through. So don't be intimidated.
One thing to be aware of however are the values on the stack. The stack is just a last in - first out list of items which operands (the word before the colon in the ABC listing) have access to. Different operands affect different numbers of items on the stack. The AVM 2 Overview document Adobe provide will tell you exactly how many, and what it'll do to them.
Ok, let's take them a line at a time. I'll stick in comments to the right of the lines showing the contents of the stack before and after the line is executed, like this: // [stack contents before line] => [stack contents after line].
function :CompoundOperatorsAndNew:::newChild()::void maxStack:3 localCount:1 initScopeDepth:9 maxScopeDepth:10
Ok, we're going to ignore this bit. All it's doing is setting up the stack and a few other bits so the code in the function can start to execute in a sane fashion. The most important thing here is localCount which tells us how many arguments are in the registers having been passed to the function. You may notice there are no arguments, but localCount is 1. Well, that's because the instance of the object that the method was called on is always passed as the first argument. That's what the "this" keyword refers to. The compiler passes it for you automatically.
getlocal0 // [empty] => this
Grabs the item in register 0 and puts it on the stack. As mentioned above, the "this" object is in register 0, so that is what is put on the stack.
pushscope // this => [empty]
Moves "this" onto the scope stack. The scope stack holds the objects to be searched when certain items and properties are requested. You can think of this little code flourish as what allows you to refer to a variable or method in the current instance of the class, more or less.
findpropstrict :addChild // [empty] => this
This line searches the objects in the scope stack for a property called "addChild", and puts it on the stack. In this case, since the class we're in inherits from DisplayObjectContainer, it's instance is pushed onto the stack.
findpropstrict :CircleSprite // this => this, class CircleSprite
Here the class definition for CircleSprite is being searched for.
constructprop :CircleSprite (0) // this, class CircleSprite => this, circle0
This grabs the class definition which was found for CircleSprite and constructs a new object from it and places it on the stack. I've numbered the instance, just so things are clearer later on. The number in brackets after the class name indicates how many arguments to pop off the stack and pass to the class constructor as arguments - in this case, there are none.
callproperty :addChild (1) // this, circle0 => circle0
Here, addChild is called on the object found by "findpropstrict :addChild" above. As you can see, the call has (1) argument - in this case the circle0 instance. circle0 appears on the stack afterwards because it is returned from addChild.
Just in case you are wondering, the number of arguments specified are popped off the stack and put into registers before the property, addChild is called. That's why addChild is called on "this" rather than circle0.
findpropstrict :addChild // circle0 => circle0, this
Behaves exactly as described earlier. Also, this is where the confusion starts.
findpropstrict :CircleSprite // circle0, this => circle0, this, class CircleSprite
Again, the same as before.
constructprop :CircleSprite (0) // circle0, this, class CircleSprite => circle0, this, circle1
Ditto.
This is why we have 2 circles. Note, I've called this instance circle1 in order to differentiate it from the previously constructed instance. Internally, CircleSprite counts it's instances, so circle0 matches the circle marked 0 on the screen, and circle1 matches the circle marked 1.
callproperty :addChild (1) // circle0, this, circle1 => circle0, circle1
Looking familiar? Good! That means you're paying attention...
Remember, addChild returns what was passed to it, so that's why circle1 is back on the stack.
getproperty :x // circle0, circle1 => circle0, 0
This line is reading the value of x from circle1, which will be 0. It's shoved on to the stack.
pushbyte 50 // circle0, 0 => circle0, 0, 50
Pushes are pretty straightforward - it's pushing the literal value onto the stack. It's interesting to note here that this code is pushing a byte, rather than an int or a number - the compiler seems to choose the "narrowest" possible type for a literal.
add // circle0, 0, 50 => circle0, 50
Does exactly what it says on the tin, which is to add things. In this case, the two most recent items on the stack are added, and the result is pushed back onto the stack.
setproperty :x // circle0, 50 => [empty]
Here, x is set to the value which is popped from the stack, and it's set on the object that's popped next. So, in this case, circle0.x is set to 50 - hence the movie having circle 0 to the right of circle 1.
returnvoid // [empty] => [empty]
It, er, returns void...
So there you have it. Your first dive into ABC. *prod*. Are you still awake? Honestly, this stuff is interesting. Really.
One nice thing about looking at ABC is that you can see which idioms compile to more terse ABC code. As a very general rule of thumb, the terser the code, the faster it will run. This is not a law though - you still have to profile things. Unfortunately, Adobe don't provide any normalised speed of execution for each operand, so it is hard to get a good grasp of what operand sequence is fastest, except by experience.
Hopefully, I'll be taking a bit more of a look at what ABC is output by the flex compiler over the next few months. I may even get around comparing the quality of the output to that of Haxe. If I'm feeling particularly daring, I may even write some bytecode. I know, the party never stops around me...
[Those of you who actually make it this far may have noticed that I haven't actually answered the "why" of my initial problem. I've left that as an exercise for the reader. Or, more honestly, I'm still thinking about it...]
