Chromium Code Reviews| 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 // Memory --------------------------------------------------------------------- | |
| 6 | |
| 7 function store8(memory, ptr, val) { | |
|
Aaron Boodman
2013/11/13 19:32:36
What is intended to be the public API out of all t
abarth-chromium
2013/11/13 19:41:51
Definitely! I was hoping we'd have a module syste
| |
| 8 memory[ptr] = val; | |
| 9 } | |
| 10 | |
| 11 function load8(memory, ptr, val) { | |
| 12 return memory[ptr]; | |
| 13 } | |
| 14 | |
| 15 function store16(memory, ptr, val) { | |
| 16 memory[ptr + 0] = val >> 0; | |
| 17 memory[ptr + 1] = val >> 8; | |
| 18 } | |
| 19 | |
| 20 function load16(memory, ptr, val) { | |
| 21 return memory[ptr + 0] << 0 + | |
| 22 memory[ptr + 1] << 8; | |
| 23 } | |
| 24 | |
| 25 function store32(memory, ptr, val) { | |
| 26 memory[ptr + 0] = val >> 0; | |
| 27 memory[ptr + 1] = val >> 8; | |
| 28 memory[ptr + 2] = val >> 16; | |
| 29 memory[ptr + 3] = val >> 24; | |
| 30 } | |
| 31 | |
| 32 function load32(memory, ptr, val) { | |
| 33 return memory[ptr + 0] << 0 + | |
| 34 memory[ptr + 1] << 8 + | |
| 35 memory[ptr + 2] << 16 + | |
| 36 memory[ptr + 3] << 24; | |
| 37 } | |
| 38 | |
| 39 function store64(memory, ptr, val) { | |
| 40 memory[ptr + 0] = val >> 0; | |
| 41 memory[ptr + 1] = val >> 8; | |
| 42 memory[ptr + 2] = val >> 16; | |
| 43 memory[ptr + 3] = val >> 24; | |
| 44 memory[ptr + 4] = val >> 32; | |
| 45 memory[ptr + 5] = val >> 40; | |
| 46 memory[ptr + 6] = val >> 48; | |
| 47 memory[ptr + 7] = val >> 56; | |
| 48 } | |
| 49 | |
| 50 function load64(memory, ptr, val) { | |
| 51 return memory[ptr + 0] << 0 + | |
| 52 memory[ptr + 1] << 8 + | |
| 53 memory[ptr + 2] << 16 + | |
| 54 memory[ptr + 3] << 24 + | |
| 55 memory[ptr + 4] << 32 + | |
| 56 memory[ptr + 5] << 40 + | |
| 57 memory[ptr + 6] << 48 + | |
| 58 memory[ptr + 7] << 56; | |
| 59 } | |
| 60 | |
| 61 function align(size) { | |
| 62 var kAlignment = 8; | |
| 63 return size + (kAlignment - (size % kAlignment)) % kAlignment; | |
|
Aaron Boodman
2013/11/13 19:32:36
I think the "% kAlignment" at the end is unnecessa
abarth-chromium
2013/11/13 19:41:51
I haven't found any callers for this function, so
| |
| 64 } | |
| 65 | |
| 66 // Serialization -------------------------------------------------------------- | |
| 67 | |
| 68 function encodePointer(memory, ptr, offsetPtr) { | |
|
Aaron Boodman
2013/11/13 19:32:36
Weird to use both 'ptr' and 'pointer'. Google styl
abarth-chromium
2013/11/13 19:41:51
Ok. I was thinking about switching to addr, but w
| |
| 69 if (!ptr) { | |
| 70 store64(memory, offsetPtr, 0); | |
| 71 return; | |
| 72 } | |
| 73 var offset = ptr - offsetPtr; | |
| 74 store64(memory, offsetPtr, offset); | |
| 75 } | |
| 76 | |
| 77 function decodePointer(memory, offsetPtr) { | |
| 78 var offset = load64(memory, offsetPtr); | |
| 79 if (!offset) | |
| 80 return 0; | |
| 81 return offsetPtr + offset; | |
| 82 } | |
| 83 | |
| 84 function encodeHandle(memory, handlePtr, handles) { | |
| 85 handles.push(load32(memory, handlePtr)); | |
| 86 store32(memory, handlePtr, handles.length - 1); | |
| 87 } | |
| 88 | |
| 89 function decodeHandle(memory, handlePtr, handles) { | |
| 90 var index = load32(memory, handlePtr); | |
| 91 store32(memory, handlePtr, handles[index]); | |
| 92 } | |
| 93 | |
| 94 // Record --------------------------------------------------------------------- | |
| 95 | |
| 96 function Record(memory, ptr) { | |
| 97 this.memory = memory; | |
| 98 this.base = ptr; | |
| 99 this.next = ptr; | |
| 100 } | |
| 101 | |
| 102 Record.prototype.advance = function(offset) { | |
| 103 this.next += offset; | |
| 104 } | |
| 105 | |
| 106 Record.prototype.readPtr = function() { | |
| 107 var ptr = decodePointer(this.memory, this.next); | |
| 108 this.next += 8; | |
| 109 return ptr; | |
| 110 } | |
| 111 | |
| 112 Record.prototype.writePtr = function(ptr) { | |
| 113 encodePointer(this.memory, ptr, this.next); | |
| 114 this.next += 8; | |
| 115 } | |
| 116 | |
| 117 Record.prototype.readRecord = function() { | |
| 118 return new Record(this.memory, this.readPtr()); | |
| 119 } | |
| 120 | |
| 121 Record.prototype.readString = function(len) { | |
| 122 // TODO(abarth): We should really support UTF-8. We might want to | |
| 123 // jump out of the VM to decode the string directly from the array | |
| 124 // buffer using v8::String::NewFromUtf8. | |
|
Aaron Boodman
2013/11/13 19:32:36
There are javascript implementations of utf8! I wr
abarth-chromium
2013/11/13 19:41:51
Link? :)
I'd like to start with a pure JS implem
Aaron Boodman
2013/11/18 18:34:48
I believe that there is one I wrote internally as
| |
| 125 var result = ""; | |
| 126 var memory = this.memory; | |
| 127 var base = this.next; | |
| 128 for (var i = 0; i < len; ++i) { | |
| 129 result += String.fromCharCode(memory[base + i] & 0x7F); | |
| 130 } | |
| 131 this.next += len; | |
| 132 return result; | |
| 133 } | |
| 134 | |
| 135 Record.prototype.read8 = function() { | |
| 136 var result = load8(this.memory, this.next); | |
| 137 this.next += 1; | |
| 138 return result; | |
| 139 } | |
| 140 | |
| 141 Record.prototype.read32 = function() { | |
| 142 var result = load32(this.memory, this.next); | |
| 143 this.next += 4; | |
| 144 return result; | |
| 145 } | |
| 146 | |
| 147 Record.prototype.read64 = function() { | |
| 148 var result = load64(this.memory, this.next); | |
| 149 this.next += 8; | |
| 150 return result; | |
| 151 } | |
| 152 | |
| 153 Record.prototype.write8 = function(val) { | |
| 154 store8(this.memory, this.next, val); | |
| 155 this.next += 1; | |
| 156 } | |
| 157 | |
| 158 Record.prototype.write32 = function(val) { | |
| 159 var after = this.next + 4; | |
| 160 store32(this.memory, this.next, val); | |
| 161 this.next += 4; | |
| 162 }; | |
| 163 | |
| 164 Record.prototype.write64 = function(val) { | |
| 165 store64(this.memory, this.next, val); | |
| 166 this.next += 8; | |
| 167 }; | |
| 168 | |
| 169 // Buffer --------------------------------------------------------------------- | |
| 170 | |
| 171 function Buffer(size) { | |
| 172 this.memory = new Uint8Array(size); | |
| 173 this.nextAllocation = 0; | |
| 174 } | |
| 175 | |
| 176 Buffer.prototype.alloc = function(size) { | |
| 177 var ptr = this.nextAllocation; | |
| 178 this.nextAllocation += size; | |
| 179 if (this.nextAllocation > this.memory.length) | |
| 180 throw "Buffer full."; | |
| 181 return new Record(this.memory, ptr); | |
| 182 }; | |
| 183 | |
| 184 // Fields --------------------------------------------------------------------- | |
| 185 | |
| 186 var kArrayHeaderSize = 8; | |
| 187 var kStructHeaderSize = 8; | |
| 188 | |
| 189 function encodeArray(record, class, val) { | |
| 190 var numberOfElements = val.length; | |
| 191 record.write32(kArrayHeaderSize + class.encodedSize * numberOfElements); | |
| 192 record.write32(numberOfElements); | |
| 193 for (var i = 0; i < numberOfElements; ++i) { | |
| 194 class.encode(record, val[i]); | |
| 195 } | |
| 196 // TODO(abarth): We should sanity check that everthing fits. | |
| 197 } | |
| 198 | |
| 199 function decodeArray(record, class) { | |
| 200 var numberOfBytes = record.read32(); | |
| 201 var numberOfElements = record.read32(); | |
| 202 var val = []; | |
| 203 for (var i = 0; i < numberOfElements; ++i) { | |
| 204 val.push(class.decode(record)); | |
| 205 } | |
| 206 // TODO(abarth): We should sanity check that everthing fits. | |
| 207 return val; | |
| 208 } | |
| 209 | |
| 210 function decodeString(record) { | |
| 211 var numberOfBytes = record.read32(); | |
| 212 var numberOfElements = record.read32(); | |
| 213 return record.readString(numberOfElements); | |
| 214 } | |
| 215 | |
| 216 // Message -------------------------------------------------------------------- | |
| 217 | |
| 218 var kMessageHeaderSize = 8; | |
| 219 | |
| 220 function Message() { | |
| 221 this.memory = null; | |
| 222 this.handles = []; | |
| 223 } | |
| 224 | |
| 225 Message.prototype.dispose = function() { | |
| 226 var len = this.handles.length; | |
| 227 for (var i = 0; i < len; ++i) { | |
| 228 mojo.core.close(this.handles[i]); | |
| 229 this.handles[i] = mojo.core.HANDLE_INVALID; | |
| 230 } | |
| 231 }; | |
| 232 | |
| 233 // MessageBuilder ------------------------------------------------------------- | |
| 234 | |
| 235 function MessageBuilder(messageName, payloadSize) { | |
| 236 var buffer = new Buffer(kMessageHeaderSize + payloadSize); | |
| 237 var header = buffer.alloc(kMessageHeaderSize); | |
| 238 header.write32(buffer.length); | |
| 239 header.write32(messageName); | |
| 240 | |
| 241 this.buffer = buffer; | |
| 242 } | |
| 243 | |
| 244 MessageBuilder.prototype.takeBuffer = function() { | |
| 245 var buffer = this.buffer; | |
| 246 this.buffer = null; | |
| 247 return buffer; | |
| 248 }; | |
| 249 | |
| 250 // Basic types ---------------------------------------------------------------- | |
| 251 | |
| 252 function Uint8() { | |
| 253 } | |
| 254 | |
| 255 Uint8.encodedSize = 1; | |
| 256 | |
| 257 Uint8.decode = function(record) { | |
| 258 return record.read8(); | |
| 259 }; | |
| 260 | |
| 261 Uint8.encode = function(record, val) { | |
| 262 record.write8(val); | |
| 263 }; | |
| 264 | |
| 265 function Ptr(class) { | |
| 266 this.class = class; | |
| 267 }; | |
| 268 | |
| 269 Ptr.prototype.encodedSize = 8; | |
| 270 | |
| 271 Ptr.prototype.decode = function(record) { | |
| 272 return class.decode(record.readRecord()); | |
| 273 }; | |
| 274 | |
| 275 Ptr.prototype.encode = function(record, val) { | |
| 276 // TODO(abarth): Where does |buffer| come from? | |
| 277 objectRecord = buffer.alloc(class.encodedSize); | |
| 278 class.encode(objectRecord, val); | |
| 279 record.writePtr(objectRecord.base); | |
| 280 }; | |
| 281 | |
| 282 function Handle() { | |
| 283 } | |
| 284 | |
| 285 // TOOD(abarth): Implement handles. | |
| 286 | |
| 287 // "Generated" code =========================================================== | |
| 288 | |
| 289 function Bar() { | |
| 290 this.alpha = 0; | |
| 291 this.beta = 0; | |
| 292 this.gamma = 0; | |
| 293 } | |
| 294 | |
| 295 Bar.encodedSize = kStructHeaderSize + 8; | |
| 296 | |
| 297 Bar.decode = function(record) { | |
| 298 var val = new Bar(); | |
| 299 // TODO(abarth): We need to support optional fields. | |
| 300 record.advance(kStructHeaderSize); | |
| 301 val.alpha = record.read8(); | |
| 302 val.beta = record.read8(); | |
| 303 val.gamma = record.read8(); | |
| 304 record.advance(5); | |
| 305 return val; | |
| 306 }; | |
| 307 | |
| 308 Bar.encode = function(record, val) { | |
| 309 record.write32(Bar.encodedSize); | |
| 310 record.write32(3); | |
| 311 record.write8(val.alpha); | |
| 312 record.write8(val.beta); | |
| 313 record.write8(val.gamma); | |
| 314 record.advance(5); | |
| 315 }; | |
| 316 | |
| 317 // int32_t x_; | |
| 318 // int32_t y_; | |
| 319 // uint8_t a_ : 1; | |
| 320 // uint8_t b_ : 1; | |
| 321 // uint8_t c_ : 1; | |
| 322 // uint8_t _pad0_[7]; | |
| 323 // mojo::internal::StructPointer<Bar> bar_; | |
| 324 // mojo::internal::ArrayPointer<uint8_t> data_; | |
| 325 // mojo::internal::ArrayPointer<Bar*> extra_bars_; | |
| 326 // mojo::internal::StringPointer name_; | |
| 327 // mojo::internal::ArrayPointer<mojo::Handle> files_; | |
| 328 | |
| 329 function Foo() { | |
| 330 this.x = 0; | |
| 331 this.y = 0; | |
| 332 this.a = 0; | |
| 333 this.b = 0; | |
| 334 this.c = 0; | |
| 335 this.bar = null; | |
| 336 this.data = null; | |
| 337 this.extra_bars = null; | |
| 338 this.name = null; | |
| 339 this.files = null; | |
| 340 } | |
| 341 | |
| 342 Foo.encodedSize = 64; | |
| 343 | |
| 344 Foo.decode = function(record) { | |
| 345 var val = new Foo(); | |
| 346 // TODO(abarth): We need to support optional fields. | |
| 347 record.advance(kStructHeaderSize); | |
| 348 val.x = record.read32(); | |
| 349 val.y = record.read32(); | |
| 350 var packed = record.read8(); | |
| 351 val.a = (packed >> 0) & 1; | |
| 352 val.b = (packed >> 1) & 1; | |
| 353 val.c = (packed >> 2) & 1; | |
| 354 record.advance(7); | |
| 355 val.bar = Bar.decode(record.readRecord()); | |
| 356 val.data = decodeArray(record.readRecord(), Uint8); | |
| 357 val.extra_bars = decodeArray(record.readRecord(), new Ptr(Bar)); | |
| 358 val.name = decodeString(record.readRecord()); | |
| 359 val.files = decodeArray(record.readRecord(), Handle); | |
| 360 } | |
| 361 | |
| 362 Foo.encode = function(record, val) { | |
| 363 record.write32(Foo.encodedSize); | |
| 364 record.write32(10); | |
| 365 record.write32(val.x); | |
| 366 record.write32(val.y); | |
| 367 var packed = (val.a & 1) << 0 | | |
| 368 (val.b & 1) << 1 | | |
| 369 (val.c & 1) << 2; | |
| 370 record.write8(packed); | |
| 371 record.advance(7); | |
| 372 | |
| 373 // TODO(abarth): Where does buffer come from? | |
| 374 var barRecord = buffer.alloc(Bar.encodedSize); | |
| 375 Bar.encode(barRecord, val.bar); | |
| 376 record.writePtr(barRecord.base); | |
| 377 | |
| 378 var dataRecord = buffer.alloc(Uint8.encodedSize); | |
| 379 encodeArray(dataRecord, Uint8, this.data); | |
| 380 record.writePtr(dataRecord.base); | |
| 381 | |
| 382 var extra_barsClass = new Ptr(Bar); | |
| 383 var extra_barsRecord = buffer.alloc(extra_barsClass.encodedSize); | |
| 384 encodeArray(dataRecord, extra_barsClass, this.data); | |
| 385 record.writePtr(extra_barsRecord.base); | |
| 386 | |
| 387 // TODO(abarth): We'll need something fancier here to support UTF-8. | |
| 388 var nameLength = val.name.length; | |
| 389 nameRecord = buffer.alloc(nameLength); | |
| 390 encodeString(nameRecord, val.name); | |
| 391 record.writePtr(nameRecord.base); | |
| 392 | |
| 393 // TODO(abarth): We need to be able to encode handles. | |
| 394 }; | |
| OLD | NEW |