1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
| The first type of attry to talk about in javascript is the TypedArray
So TypedArrays are going to make a lot of aense to you if you are coming from a C background
They are contiguous blocks of memory that are specified for a particylar data type.
So you have Uint32Array, Float64Array, Unit8Array, and so on, and so forth, which actually, if you are familiar with Javascript,is sort of unusual. Because most things in Javascript have no type.
So this idea that we are specifying a very specific size for our numbers id actually like pretty unique. And that's because the TypedArray specification grew up alongside the WebGL specification.
And you can inagine how you need that level of specificity if you are doing graphics programming.
So that's sort of where the TypedArray specification came from.
But it's been adopted into other things now that it's there.
So agein, they're memory efficient. You don't have to box them.
They behave as you'd expect.
They're a very nice option for arrays.
But if you can't use TypedArrays for whatever reason, you need to use Javascript Arrays.
SO Javascript Array object --Array with a captital A-- has an API which is going to look a little weird to you if you are used to C-style arrays.
It's going to have operations that are different.
It's going to have like push and pop.
It's going to allow you to index out of bounds.
It's going to have just sort of odd behavior to me as somebody coming from C.
So as you can imagine, because the API allows all these non-C array-like things, the backing storage in V8 is not always somethings that looks like array. There are actually two diffent types of backing storage for arrays. Thewe are sparse arrays and dense arrays, which map to either something tach looks like a C-style array. like you'd expect, or a hash table. And if you array is backed by a V8 hash table, that's called being in dictionary mode, and it's considerably less efficient. It's case that you want to avoid.
There are many factors in V8 that causes you to be kicked into dictionary mode or not.
So it's kind of complicated to define them all.
But one of them, for instance, is space efficiency.
So is the codes you wrote will be three times more effcient, use three times less space if it was backed by a hash table than an array, then it'll be a hsah table on back end. So there are criteria like that.
js allows you to create a new uninitialized array and then just suddenly index into it at whatever index.
This, doesn't make any sense in C. It's not something you'd actually do. And in V8, it will immediately trigger dictionary mode. So this, you will now have a nice, slow array to waok with, not something you want.
So real simple change.
All you have to do is declare how much storage you want up font.Now you have declared to V8 that you actually want an array of a certain size. V8 will back your array by a contigous array of that size, and you can go from there.
Veay sensible, kind of no-brainerish, but again, Javascript allows you to do it in a way that ends up being very inefficient, so it's important to know.
So that is the numeric representation and the immediate representation of objects.
------------------------------- Object in V8 -------------------------------
So objects in JavaScript are there very poorly defined things.
They are associative arrays.
They're just bundles of key value pairs of properties.
So you have string balue for key, property value.
And all property values are these undefined whatevers, because Javascript doesn't have a notion of type.
Object have prototype chains. You can add and remove properties anywhere at the prototype chain and on the object inself at any point.
Javascript doesn't enforce any specificity or structure in your code.
So if you wanted to, you could make every single object in your whole program absolutely a unique set of properties.
Nothing in Javascript will enforce structure or self-similarity.
But just because JavaScript allows you to do that, you really,really shouldn't.
That's actually a terrible thing to do for performance.
And I'll explain why in a minute.
So in V8,the V8 team looked at trying to write a large-scale application in JavaScript and thought, hey, you know what's important in large-scale systems is object-orientenness.
And if you have object-orientenness in your system, then now, property access is one of the key things that you need to make fast.
So V8 designed its structure to make property access on objects as efficient as it could be.
So the internal representation of an object in V8 is three words.
So first, we have a hidden class pointer, which is an internal notion of type, which I'll explain in a second.
And then we have two pointers to different kinds of properties.
We have properties that have string names and then properties that have int names.
But really, the only thing that's important is your have a type, and then you have property storage.
So waht's this hidden class thing?
So hidden classes, again, ther're V8's interbal notion of type.
JavaScript itself isn't going to enforce any kind of notionof type on you.
BUt in order to make things effcient, V8itself need to have some sort of structure in whst it things you're doing.
So it introduces a type system.
And that type system froups objects with the same structure.
So as you're adding properties to objects, which you can do in JavaScript, V8 will be looking at the properties on each object and mapping ta=hat bundle of properties to a hidden class, which defines an object with exactly those properties.
So, dor instance, if I have this constructor in JavaScript where I have a point, and it has an x and y, and the way those values are added by first adding x to the object and then adding y, thay's going to generate a hidden class that backs objects that are created from this function that has exactle the properties x and y.
And that really seems sort of obvious.
But then, the first time this function is run, that hidden class is going to be built for the first time. And then, all subsequent times this dunction is run, those new objects can share the same hidden class.So you only pay the price for building it the very first time.
After that, you can just use the same object.
So we went through all this trouble of building up a notion of type.
So now, we have types that correspond to specifically what exact properties are on an object.
We can use taht notion of type to make property access quick using something called inline caching.
So if yoiu want to look up a property on an object in Javascript, you're going to say, I am looking for property with name x on object y.
The first thing you do whrn you're trying to look up a property is check the hidden class of the object.
If you're never tried to look up that property on an object of that type before, then what you're going to have to do is a fully generic search for that property.
So again, we just have a bundle of properties somewhere.
They all have string names.
You have a string of the property you're looking for.
And you're going to have to look through taht list for the property that has a matching name.
That's a pretty slow operation.
But once you found thst property once, you can remember the offset to it. you can remember where you found that property and use it later, which means that you can use that to generate new optimized code which specifies how you look up that particular property on that particular object.
And next time you want to look up property with that name on an object of that type, you can have direct access You know exactly where to go in an object of that type.
And it's much much much faster.
So thst's really what the notion of having hidden class is getting us, is now we can make property access really fast through inline caching.
So this is a classic example of bad idea.
function Vec2(x,y){ this.x = x; this.y = y; } var v0 = new Vec2(5,8); v0.z = 34;
So I have another constructor. It's creating a vector object.
But then, after I go through the trouble of doing that, I decide that I now wanted property z on this object.
The problem with that is that if you add a property z to that object at some future point, if you just dynamically do that, you're going to change the hidden class of the object, which means that all this nice caching you're done and building up a notion of where the properties are, that's just blown away because now you have a new hidden class.
You have to pay to build the new hidden class, and now you have to deal with a new hidden class.
So one of the best things you can do to make you code efficient is to create a few well-defined types.
Don't do alot of dynamic property adding and removing outside of constructors.
Pretty much set things up once, have them look alike so that they can share the same hidden class, and don't mess with the properties they have.
------------------------------- Object properties storage -------------------------------
So now we know an object has properties.
those properties can be in different storage states.
So the first state ,the default, is that they can be stored directly in an array on the object.
that great, that's fast. that's where you want to be.
A second state they can be in is being stored in array off the objects. still great. No problem.
The third case, which is the one you really have to look out for, is when they're stored in a hash table.
So mush like just the array case in general where arrays can have different types of backing storage, properties can have different types of backing storage too.
So properties can either be in normal mode where they're stored as an array or a dictionary mode where they're stored as a hash table.
And if you have an object in dictionary mode, it's going to be mush slower to interact with.
So you don't want that.
So what triggers dictionary mode ,and how do you avoid it? Well, one thing that triggers itis toomany properties.
So if you have so many properties that they won't fit into the internal storage for properties, then you have to have a hash table elsewhere. And that number of too many properties is somewhere around 30. It's quite generous, but you mighe hit it in some cases.
The other things you can do to confuse your object and kick it into dictionary mode are to change the properties on the object.
You can change the attribute, you can delete properties, that kind of thing. Those things are all going to kick you straight to dictionary mode.
Again, and now you're going to make your object mush slower to interact with.
|