OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 define(function() { |
| 6 |
| 7 // Memory ------------------------------------------------------------------- |
| 8 |
| 9 function store8(memory, pointer, val) { |
| 10 memory[pointer] = val; |
| 11 } |
| 12 |
| 13 function store16(memory, pointer, val) { |
| 14 memory[pointer + 0] = val >> 0; |
| 15 memory[pointer + 1] = val >> 8; |
| 16 } |
| 17 |
| 18 function store32(memory, pointer, val) { |
| 19 memory[pointer + 0] = val >> 0; |
| 20 memory[pointer + 1] = val >> 8; |
| 21 memory[pointer + 2] = val >> 16; |
| 22 memory[pointer + 3] = val >> 24; |
| 23 } |
| 24 |
| 25 function store64(memory, pointer, val) { |
| 26 store32(memory, pointer, val); |
| 27 var high = (val / 0x10000) | 0; |
| 28 store32(memory, pointer + 4, high); |
| 29 } |
| 30 |
| 31 function load8(memory, pointer) { |
| 32 return memory[pointer]; |
| 33 } |
| 34 |
| 35 function load16(memory, pointer) { |
| 36 return (memory[pointer + 0] << 0) + |
| 37 (memory[pointer + 1] << 8); |
| 38 } |
| 39 |
| 40 function load32(memory, pointer) { |
| 41 return (memory[pointer + 0] << 0) + |
| 42 (memory[pointer + 1] << 8) + |
| 43 (memory[pointer + 2] << 16) + |
| 44 (memory[pointer + 3] << 24); |
| 45 } |
| 46 |
| 47 function load64(memory, pointer) { |
| 48 var low = load32(memory, pointer); |
| 49 var high = load32(memory, pointer + 4); |
| 50 return low + high * 0x10000; |
| 51 } |
| 52 |
| 53 // Buffer ------------------------------------------------------------------- |
| 54 |
| 55 function Buffer(size) { |
| 56 this.memory = new Uint8Array(size); |
| 57 this.next = 0; |
| 58 } |
| 59 |
| 60 Buffer.prototype.alloc = function(size) { |
| 61 var pointer = this.next; |
| 62 this.next += size; |
| 63 if (this.next > this.memory.length) { |
| 64 var newSize = (1.5 * (this.memory.length + size)) | 0; |
| 65 this.grow(newSize); |
| 66 } |
| 67 return pointer; |
| 68 }; |
| 69 |
| 70 Buffer.prototype.grow = function(size) { |
| 71 var newMemory = new Uint8Array(size); |
| 72 var oldMemory = this.memory; |
| 73 for (var i = 0; i < oldMemory.length; ++i) |
| 74 newMemory[i] = oldMemory[i]; |
| 75 this.memory = newMemory; |
| 76 }; |
| 77 |
| 78 // Constants ---------------------------------------------------------------- |
| 79 |
| 80 var kArrayHeaderSize = 8; |
| 81 var kStructHeaderSize = 8; |
| 82 var kMessageHeaderSize = 8; |
| 83 |
| 84 // Decoder ------------------------------------------------------------------ |
| 85 |
| 86 function Decoder(memory, handles, base) { |
| 87 this.memory = memory; |
| 88 this.handles = handles; |
| 89 this.base = base; |
| 90 this.next = base; |
| 91 } |
| 92 |
| 93 Decoder.prototype.skip = function(offset) { |
| 94 this.next += offset; |
| 95 }; |
| 96 |
| 97 Decoder.prototype.read8 = function() { |
| 98 var result = load8(this.memory, this.next); |
| 99 this.next += 1; |
| 100 return result; |
| 101 }; |
| 102 |
| 103 Decoder.prototype.read32 = function() { |
| 104 var result = load32(this.memory, this.next); |
| 105 this.next += 4; |
| 106 return result; |
| 107 }; |
| 108 |
| 109 Decoder.prototype.read64 = function() { |
| 110 var result = load64(this.memory, this.next); |
| 111 this.next += 8; |
| 112 return result; |
| 113 }; |
| 114 |
| 115 Decoder.prototype.decodePointer = function() { |
| 116 // TODO(abarth): To correctly decode a pointer, we need to know the real |
| 117 // base address of the array buffer. |
| 118 var offsetPointer = this.next; |
| 119 var offset = this.read64(); |
| 120 if (!offset) |
| 121 return 0; |
| 122 return offsetPointer + offset; |
| 123 }; |
| 124 |
| 125 Decoder.prototype.decodeAndCreateDecoder = function() { |
| 126 return new Decoder(this.memory, this.handles, this.decodePointer()); |
| 127 }; |
| 128 |
| 129 Decoder.prototype.decodeHandle = function() { |
| 130 return this.handles[this.read32()]; |
| 131 }; |
| 132 |
| 133 Decoder.prototype.decodeString = function() { |
| 134 // TODO(abarth): We should really support UTF-8. We might want to |
| 135 // jump out of the VM to decode the string directly from the array |
| 136 // buffer using v8::String::NewFromUtf8. |
| 137 var numberOfBytes = this.read32(); |
| 138 var numberOfElements = this.read32(); |
| 139 var val = new Array(numberOfElements); |
| 140 var memory = this.memory; |
| 141 var base = this.next; |
| 142 for (var i = 0; i < numberOfElements; ++i) { |
| 143 val[i] = String.fromCharCode(memory[base + i] & 0x7F); |
| 144 } |
| 145 this.next += numberOfElements; |
| 146 return val.join(''); |
| 147 }; |
| 148 |
| 149 Decoder.prototype.decodeArray = function(cls) { |
| 150 var numberOfBytes = this.read32(); |
| 151 var numberOfElements = this.read32(); |
| 152 var val = new Array(numberOfElements); |
| 153 for (var i = 0; i < numberOfElements; ++i) { |
| 154 val[i] = cls.decode(this); |
| 155 } |
| 156 return val; |
| 157 }; |
| 158 |
| 159 Decoder.prototype.decodeStructPointer = function(cls) { |
| 160 return cls.decode(this.decodeAndCreateDecoder()); |
| 161 }; |
| 162 |
| 163 Decoder.prototype.decodeArrayPointer = function(cls) { |
| 164 return this.decodeAndCreateDecoder().decodeArray(cls); |
| 165 }; |
| 166 |
| 167 Decoder.prototype.decodeStringPointer = function() { |
| 168 return this.decodeAndCreateDecoder().decodeString(); |
| 169 }; |
| 170 |
| 171 // Encoder ------------------------------------------------------------------ |
| 172 |
| 173 function Encoder(buffer, handles, base) { |
| 174 this.buffer = buffer; |
| 175 this.handles = handles; |
| 176 this.base = base; |
| 177 this.next = base; |
| 178 } |
| 179 |
| 180 Encoder.prototype.skip = function(offset) { |
| 181 this.next += offset; |
| 182 }; |
| 183 |
| 184 Encoder.prototype.write8 = function(val) { |
| 185 store8(this.buffer.memory, this.next, val); |
| 186 this.next += 1; |
| 187 }; |
| 188 |
| 189 Encoder.prototype.write32 = function(val) { |
| 190 store32(this.buffer.memory, this.next, val); |
| 191 this.next += 4; |
| 192 }; |
| 193 |
| 194 Encoder.prototype.write64 = function(val) { |
| 195 store64(this.buffer.memory, this.next, val); |
| 196 this.next += 8; |
| 197 }; |
| 198 |
| 199 Encoder.prototype.encodePointer = function(pointer) { |
| 200 if (!pointer) |
| 201 return this.write64(0); |
| 202 // TODO(abarth): To correctly encode a pointer, we need to know the real |
| 203 // base address of the array buffer. |
| 204 var offset = pointer - this.next; |
| 205 this.write64(offset); |
| 206 }; |
| 207 |
| 208 Encoder.prototype.createAndEncodeEncoder = function(size) { |
| 209 var pointer = this.buffer.alloc(size); |
| 210 this.encodePointer(pointer); |
| 211 return new Encoder(this.buffer, this.handles, pointer); |
| 212 }; |
| 213 |
| 214 Encoder.prototype.encodeHandle = function(handle) { |
| 215 this.handles.push(handle); |
| 216 this.write32(this.handles.length - 1); |
| 217 }; |
| 218 |
| 219 Encoder.prototype.encodeString = function(val) { |
| 220 var numberOfElements = val.length; |
| 221 var numberOfBytes = kArrayHeaderSize + numberOfElements; |
| 222 this.write32(numberOfBytes); |
| 223 this.write32(numberOfElements); |
| 224 // TODO(abarth): We should really support UTF-8. We might want to |
| 225 // jump out of the VM to encode the string directly from the array |
| 226 // buffer using v8::String::WriteUtf8. |
| 227 var memory = this.buffer.memory; |
| 228 var base = this.next; |
| 229 var len = val.length; |
| 230 for (var i = 0; i < len; ++i) { |
| 231 memory[base + i] = val.charCodeAt(i) & 0x7F; |
| 232 } |
| 233 this.next += len; |
| 234 }; |
| 235 |
| 236 Encoder.prototype.encodeArray = function(cls, val) { |
| 237 var numberOfElements = val.length; |
| 238 var numberOfBytes = kArrayHeaderSize + cls.encodedSize * numberOfElements; |
| 239 this.write32(numberOfBytes); |
| 240 this.write32(numberOfElements); |
| 241 for (var i = 0; i < numberOfElements; ++i) { |
| 242 cls.encode(this, val[i]); |
| 243 } |
| 244 }; |
| 245 |
| 246 Encoder.prototype.encodeStructPointer = function(cls, val) { |
| 247 var encoder = this.createAndEncodeEncoder(cls.encodedSize); |
| 248 cls.encode(encoder, val); |
| 249 }; |
| 250 |
| 251 Encoder.prototype.encodeArrayPointer = function(cls, val) { |
| 252 var encodedSize = kArrayHeaderSize + cls.encodedSize * val.length; |
| 253 var encoder = this.createAndEncodeEncoder(encodedSize); |
| 254 encoder.encodeArray(cls, val); |
| 255 }; |
| 256 |
| 257 Encoder.prototype.encodeStringPointer = function(val) { |
| 258 // TODO(abarth): This won't be right once we support UTF-8. |
| 259 var encodedSize = kArrayHeaderSize + val.length; |
| 260 var encoder = this.createAndEncodeEncoder(encodedSize); |
| 261 encoder.encodeString(val); |
| 262 }; |
| 263 |
| 264 // Message ------------------------------------------------------------------ |
| 265 |
| 266 function Message(memory, handles) { |
| 267 this.memory = memory; |
| 268 this.handles = handles; |
| 269 } |
| 270 |
| 271 // MessageBuilder ----------------------------------------------------------- |
| 272 |
| 273 function MessageBuilder(messageName, payloadSize) { |
| 274 var numberOfBytes = kMessageHeaderSize + payloadSize; |
| 275 this.buffer = new Buffer(numberOfBytes); |
| 276 this.handles = []; |
| 277 var encoder = this.createEncoder(kMessageHeaderSize); |
| 278 encoder.write32(numberOfBytes); |
| 279 encoder.write32(messageName); |
| 280 } |
| 281 |
| 282 MessageBuilder.prototype.createEncoder = function(size) { |
| 283 var pointer = this.buffer.alloc(size); |
| 284 return new Encoder(this.buffer, this.handles, pointer); |
| 285 } |
| 286 |
| 287 MessageBuilder.prototype.encodeStruct = function(cls, val) { |
| 288 cls.encode(this.createEncoder(cls.encodedSize), val); |
| 289 }; |
| 290 |
| 291 MessageBuilder.prototype.finish = function() { |
| 292 var message = new Message(this.buffer.memory, this.handles); |
| 293 this.buffer = null; |
| 294 this.handles = null; |
| 295 this.encoder = null; |
| 296 return message; |
| 297 }; |
| 298 |
| 299 // MessageReader ------------------------------------------------------------ |
| 300 |
| 301 function MessageReader(message) { |
| 302 this.decoder = new Decoder(message.memory, message.handles, 0); |
| 303 this.payloadSize = this.decoder.read32() - kMessageHeaderSize; |
| 304 this.messageName = this.decoder.read32(); |
| 305 } |
| 306 |
| 307 MessageReader.prototype.decodeStruct = function(cls) { |
| 308 return cls.decode(this.decoder); |
| 309 }; |
| 310 |
| 311 // Built-in types ----------------------------------------------------------- |
| 312 |
| 313 function Uint8() { |
| 314 } |
| 315 |
| 316 Uint8.encodedSize = 1; |
| 317 |
| 318 Uint8.decode = function(decoder) { |
| 319 return decoder.read8(); |
| 320 }; |
| 321 |
| 322 Uint8.encode = function(encoder, val) { |
| 323 encoder.write8(val); |
| 324 }; |
| 325 |
| 326 function Uint16() { |
| 327 } |
| 328 |
| 329 Uint16.encodedSize = 2; |
| 330 |
| 331 Uint16.decode = function(decoder) { |
| 332 return decoder.read16(); |
| 333 }; |
| 334 |
| 335 Uint16.encode = function(encoder, val) { |
| 336 encoder.write16(val); |
| 337 }; |
| 338 |
| 339 function Uint32() { |
| 340 } |
| 341 |
| 342 Uint32.encodedSize = 4; |
| 343 |
| 344 Uint32.decode = function(decoder) { |
| 345 return decoder.read32(); |
| 346 }; |
| 347 |
| 348 Uint32.encode = function(encoder, val) { |
| 349 encoder.write32(val); |
| 350 }; |
| 351 |
| 352 function Uint64() { |
| 353 }; |
| 354 |
| 355 Uint64.encodedSize = 8; |
| 356 |
| 357 Uint64.decode = function(decoder) { |
| 358 return decoder.read64(); |
| 359 }; |
| 360 |
| 361 Uint64.encode = function(encoder, val) { |
| 362 encoder.write64(val); |
| 363 }; |
| 364 |
| 365 function PointerTo(cls) { |
| 366 this.cls = cls; |
| 367 }; |
| 368 |
| 369 PointerTo.prototype.encodedSize = 8; |
| 370 |
| 371 PointerTo.prototype.decode = function(decoder) { |
| 372 return this.cls.decode(decoder.decodeAndCreateDecoder()); |
| 373 }; |
| 374 |
| 375 PointerTo.prototype.encode = function(encoder, val) { |
| 376 var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize); |
| 377 this.cls.encode(objectEncoder, val); |
| 378 }; |
| 379 |
| 380 function Handle() { |
| 381 } |
| 382 |
| 383 Handle.encodedSize = 4; |
| 384 |
| 385 Handle.decode = function(decoder) { |
| 386 return decoder.decodeHandle(); |
| 387 }; |
| 388 |
| 389 Handle.encode = function(encoder, val) { |
| 390 encoder.encodeHandle(val); |
| 391 }; |
| 392 |
| 393 var exports = {}; |
| 394 exports.load32 = load32; |
| 395 exports.MessageBuilder = MessageBuilder; |
| 396 exports.MessageReader = MessageReader; |
| 397 exports.kArrayHeaderSize = kArrayHeaderSize; |
| 398 exports.kStructHeaderSize = kStructHeaderSize; |
| 399 exports.kMessageHeaderSize = kMessageHeaderSize; |
| 400 exports.Uint8 = Uint8; |
| 401 exports.Uint16 = Uint16; |
| 402 exports.Uint32 = Uint32; |
| 403 exports.Uint64 = Uint64; |
| 404 exports.PointerTo = PointerTo; |
| 405 exports.Handle = Handle; |
| 406 return exports; |
| 407 }); |
OLD | NEW |