Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(318)

Side by Side Diff: mojo/public/bindings/js/codec.js

Issue 223233002: Mojo: Move mojo/public/bindings/js to mojo/public/js/bindings. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase & restore ordering Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 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("mojo/public/bindings/js/codec", 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 var kAlignment = 8;
48
49 function align(size) {
50 return size + (kAlignment - (size % kAlignment)) % kAlignment;
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 Buffer.prototype.createViewOfAllocatedMemory = function() {
79 return new Uint8Array(this.memory.buffer, 0, this.next);
80 };
81
82 // Constants ----------------------------------------------------------------
83
84 var kArrayHeaderSize = 8;
85 var kStructHeaderSize = 8;
86 var kMessageHeaderSize = 16;
87 var kMessageWithRequestIDHeaderSize = 24;
88
89 // Decoder ------------------------------------------------------------------
90
91 function Decoder(memory, handles, base) {
92 this.memory = memory;
93 this.handles = handles;
94 this.base = base;
95 this.next = base;
96 this.viewU32 = new Uint32Array(
97 this.memory.buffer, 0,
98 Math.floor(this.memory.length / Uint32Array.BYTES_PER_ELEMENT));
99 this.viewFloat = new Float32Array(
100 this.memory.buffer, 0,
101 Math.floor(this.memory.length / Float32Array.BYTES_PER_ELEMENT));
102 }
103
104 Decoder.prototype.skip = function(offset) {
105 this.next += offset;
106 };
107
108 Decoder.prototype.read8 = function() {
109 var result = load8(this.memory, this.next);
110 this.next += 1;
111 return result;
112 };
113
114 Decoder.prototype.read32 = function() {
115 var result = this.viewU32[this.next / this.viewU32.BYTES_PER_ELEMENT];
116 this.next += this.viewU32.BYTES_PER_ELEMENT;
117 return result;
118 };
119
120 Decoder.prototype.read64 = function() {
121 var low = this.read32();
122 var high = this.read32();
123 return low + high * 0x100000000;
124 };
125
126 Decoder.prototype.decodeFloat = function() {
127 var result = this.viewFloat[this.next / this.viewFloat.BYTES_PER_ELEMENT];
128 this.next += this.viewFloat.BYTES_PER_ELEMENT;
129 return result;
130 };
131
132 Decoder.prototype.decodePointer = function() {
133 // TODO(abarth): To correctly decode a pointer, we need to know the real
134 // base address of the array buffer.
135 var offsetPointer = this.next;
136 var offset = this.read64();
137 if (!offset)
138 return 0;
139 return offsetPointer + offset;
140 };
141
142 Decoder.prototype.decodeAndCreateDecoder = function() {
143 return new Decoder(this.memory, this.handles, this.decodePointer());
144 };
145
146 Decoder.prototype.decodeHandle = function() {
147 return this.handles[this.read32()];
148 };
149
150 Decoder.prototype.decodeString = function() {
151 // TODO(abarth): We should really support UTF-8. We might want to
152 // jump out of the VM to decode the string directly from the array
153 // buffer using v8::String::NewFromUtf8.
154 var numberOfBytes = this.read32();
155 var numberOfElements = this.read32();
156 var val = new Array(numberOfElements);
157 var memory = this.memory;
158 var base = this.next;
159 for (var i = 0; i < numberOfElements; ++i) {
160 val[i] = String.fromCharCode(memory[base + i] & 0x7F);
161 }
162 this.next += numberOfElements;
163 return val.join('');
164 };
165
166 Decoder.prototype.decodeArray = function(cls) {
167 var numberOfBytes = this.read32();
168 var numberOfElements = this.read32();
169 var val = new Array(numberOfElements);
170 for (var i = 0; i < numberOfElements; ++i) {
171 val[i] = cls.decode(this);
172 }
173 return val;
174 };
175
176 Decoder.prototype.decodeStructPointer = function(cls) {
177 return cls.decode(this.decodeAndCreateDecoder());
178 };
179
180 Decoder.prototype.decodeArrayPointer = function(cls) {
181 return this.decodeAndCreateDecoder().decodeArray(cls);
182 };
183
184 Decoder.prototype.decodeStringPointer = function() {
185 return this.decodeAndCreateDecoder().decodeString();
186 };
187
188 // Encoder ------------------------------------------------------------------
189
190 function Encoder(buffer, handles, base) {
191 this.buffer = buffer;
192 this.handles = handles;
193 this.base = base;
194 this.next = base;
195 }
196
197 Encoder.prototype.skip = function(offset) {
198 this.next += offset;
199 };
200
201 Encoder.prototype.write8 = function(val) {
202 store8(this.buffer.memory, this.next, val);
203 this.next += 1;
204 };
205
206 Encoder.prototype.write32 = function(val) {
207 store32(this.buffer.memory, this.next, val);
208 this.next += 4;
209 };
210
211 Encoder.prototype.write64 = function(val) {
212 store64(this.buffer.memory, this.next, val);
213 this.next += 8;
214 };
215
216 Encoder.prototype.encodeFloat = function(val) {
217 var floatBuffer = new Float32Array(1);
218 floatBuffer[0] = val;
219 var buffer = new Uint8Array(floatBuffer.buffer, 0);
220 for (var i = 0; i < buffer.length; ++i)
221 this.buffer.memory[this.next++] = buffer[i];
222 };
223
224 Encoder.prototype.encodePointer = function(pointer) {
225 if (!pointer)
226 return this.write64(0);
227 // TODO(abarth): To correctly encode a pointer, we need to know the real
228 // base address of the array buffer.
229 var offset = pointer - this.next;
230 this.write64(offset);
231 };
232
233 Encoder.prototype.createAndEncodeEncoder = function(size) {
234 var pointer = this.buffer.alloc(align(size));
235 this.encodePointer(pointer);
236 return new Encoder(this.buffer, this.handles, pointer);
237 };
238
239 Encoder.prototype.encodeHandle = function(handle) {
240 this.handles.push(handle);
241 this.write32(this.handles.length - 1);
242 };
243
244 Encoder.prototype.encodeString = function(val) {
245 var numberOfElements = val.length;
246 var numberOfBytes = kArrayHeaderSize + numberOfElements;
247 this.write32(numberOfBytes);
248 this.write32(numberOfElements);
249 // TODO(abarth): We should really support UTF-8. We might want to
250 // jump out of the VM to encode the string directly from the array
251 // buffer using v8::String::WriteUtf8.
252 var memory = this.buffer.memory;
253 var base = this.next;
254 var len = val.length;
255 for (var i = 0; i < len; ++i) {
256 memory[base + i] = val.charCodeAt(i) & 0x7F;
257 }
258 this.next += len;
259 };
260
261 Encoder.prototype.encodeArray = function(cls, val) {
262 var numberOfElements = val.length;
263 var numberOfBytes = kArrayHeaderSize + cls.encodedSize * numberOfElements;
264 this.write32(numberOfBytes);
265 this.write32(numberOfElements);
266 for (var i = 0; i < numberOfElements; ++i) {
267 cls.encode(this, val[i]);
268 }
269 };
270
271 Encoder.prototype.encodeStructPointer = function(cls, val) {
272 var encoder = this.createAndEncodeEncoder(cls.encodedSize);
273 cls.encode(encoder, val);
274 };
275
276 Encoder.prototype.encodeArrayPointer = function(cls, val) {
277 var encodedSize = kArrayHeaderSize + cls.encodedSize * val.length;
278 var encoder = this.createAndEncodeEncoder(encodedSize);
279 encoder.encodeArray(cls, val);
280 };
281
282 Encoder.prototype.encodeStringPointer = function(val) {
283 // TODO(abarth): This won't be right once we support UTF-8.
284 var encodedSize = kArrayHeaderSize + val.length;
285 var encoder = this.createAndEncodeEncoder(encodedSize);
286 encoder.encodeString(val);
287 };
288
289 // Message ------------------------------------------------------------------
290
291 var kMessageExpectsResponse = 1 << 0;
292 var kMessageIsResponse = 1 << 1;
293
294 function Message(memory, handles) {
295 this.memory = memory;
296 this.handles = handles;
297 }
298
299 Message.prototype.setRequestID = function(requestID) {
300 // TODO(darin): Verify that space was reserved for this field!
301 store64(this.memory, 4 + 4 + 4 + 4, requestID);
302 };
303
304 Message.prototype.getFlags = function() {
305 // Skip over num_bytes, num_fields, and message_name.
306 return load32(this.memory, 4 + 4 + 4);
307 };
308
309 // MessageBuilder -----------------------------------------------------------
310
311 function MessageBuilder(messageName, payloadSize) {
312 // Currently, we don't compute the payload size correctly ahead of time.
313 // Instead, we resize the buffer at the end.
314 var numberOfBytes = kMessageHeaderSize + payloadSize;
315 this.buffer = new Buffer(numberOfBytes);
316 this.handles = [];
317 var encoder = this.createEncoder(kMessageHeaderSize);
318 encoder.write32(kMessageHeaderSize);
319 encoder.write32(2); // num_fields.
320 encoder.write32(messageName);
321 encoder.write32(0); // flags.
322 }
323
324 MessageBuilder.prototype.createEncoder = function(size) {
325 var pointer = this.buffer.alloc(size);
326 return new Encoder(this.buffer, this.handles, pointer);
327 };
328
329 MessageBuilder.prototype.encodeStruct = function(cls, val) {
330 cls.encode(this.createEncoder(cls.encodedSize), val);
331 };
332
333 MessageBuilder.prototype.finish = function() {
334 // TODO(abarth): Rather than resizing the buffer at the end, we could
335 // compute the size we need ahead of time, like we do in C++.
336 var memory = this.buffer.createViewOfAllocatedMemory();
337 var message = new Message(memory, this.handles);
338 this.buffer = null;
339 this.handles = null;
340 this.encoder = null;
341 return message;
342 };
343
344 // MessageWithRequestIDBuilder -----------------------------------------------
345
346 function MessageWithRequestIDBuilder(messageName, payloadSize, flags,
347 requestID) {
348 // Currently, we don't compute the payload size correctly ahead of time.
349 // Instead, we resize the buffer at the end.
350 var numberOfBytes = kMessageWithRequestIDHeaderSize + payloadSize;
351 this.buffer = new Buffer(numberOfBytes);
352 this.handles = [];
353 var encoder = this.createEncoder(kMessageWithRequestIDHeaderSize);
354 encoder.write32(kMessageWithRequestIDHeaderSize);
355 encoder.write32(3); // num_fields.
356 encoder.write32(messageName);
357 encoder.write32(flags);
358 encoder.write64(requestID);
359 }
360
361 MessageWithRequestIDBuilder.prototype =
362 Object.create(MessageBuilder.prototype);
363 MessageWithRequestIDBuilder.prototype.constructor =
364 MessageWithRequestIDBuilder;
365
366 // MessageReader ------------------------------------------------------------
367
368 function MessageReader(message) {
369 this.decoder = new Decoder(message.memory, message.handles, 0);
370 var messageHeaderSize = this.decoder.read32();
371 this.payloadSize = message.memory.length - messageHeaderSize;
372 var numFields = this.decoder.read32();
373 this.messageName = this.decoder.read32();
374 this.flags = this.decoder.read32();
375 if (numFields >= 3)
376 this.requestID = this.decoder.read64();
377 this.decoder.skip(messageHeaderSize - this.decoder.next);
378 }
379
380 MessageReader.prototype.decodeStruct = function(cls) {
381 return cls.decode(this.decoder);
382 };
383
384 // Built-in types -----------------------------------------------------------
385
386 function Uint8() {
387 }
388
389 Uint8.encodedSize = 1;
390
391 Uint8.decode = function(decoder) {
392 return decoder.read8();
393 };
394
395 Uint8.encode = function(encoder, val) {
396 encoder.write8(val);
397 };
398
399 function Uint16() {
400 }
401
402 Uint16.encodedSize = 2;
403
404 Uint16.decode = function(decoder) {
405 return decoder.read16();
406 };
407
408 Uint16.encode = function(encoder, val) {
409 encoder.write16(val);
410 };
411
412 function Uint32() {
413 }
414
415 Uint32.encodedSize = 4;
416
417 Uint32.decode = function(decoder) {
418 return decoder.read32();
419 };
420
421 Uint32.encode = function(encoder, val) {
422 encoder.write32(val);
423 };
424
425 function Uint64() {
426 };
427
428 Uint64.encodedSize = 8;
429
430 Uint64.decode = function(decoder) {
431 return decoder.read64();
432 };
433
434 Uint64.encode = function(encoder, val) {
435 encoder.write64(val);
436 };
437
438 function PointerTo(cls) {
439 this.cls = cls;
440 };
441
442 // TODO(abarth): Add missing types:
443 // * String
444 // * Float
445 // * Double
446 // * Signed integers
447
448 PointerTo.prototype.encodedSize = 8;
449
450 PointerTo.prototype.decode = function(decoder) {
451 return this.cls.decode(decoder.decodeAndCreateDecoder());
452 };
453
454 PointerTo.prototype.encode = function(encoder, val) {
455 var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize);
456 this.cls.encode(objectEncoder, val);
457 };
458
459 function ArrayOf(cls) {
460 this.cls = cls;
461 };
462
463 ArrayOf.prototype.encodedSize = 8;
464
465 ArrayOf.prototype.decode = function(decoder) {
466 return decoder.decodeArrayPointer(self.cls);
467 };
468
469 ArrayOf.prototype.encode = function(encoder, val) {
470 encoder.encodeArrayPointer(self.cls, val);
471 };
472
473 function Handle() {
474 }
475
476 Handle.encodedSize = 4;
477
478 Handle.decode = function(decoder) {
479 return decoder.decodeHandle();
480 };
481
482 Handle.encode = function(encoder, val) {
483 encoder.encodeHandle(val);
484 };
485
486 var exports = {};
487 exports.align = align;
488 exports.Message = Message;
489 exports.MessageBuilder = MessageBuilder;
490 exports.MessageWithRequestIDBuilder = MessageWithRequestIDBuilder;
491 exports.MessageReader = MessageReader;
492 exports.kArrayHeaderSize = kArrayHeaderSize;
493 exports.kStructHeaderSize = kStructHeaderSize;
494 exports.kMessageHeaderSize = kMessageHeaderSize;
495 exports.kMessageExpectsResponse = kMessageExpectsResponse;
496 exports.kMessageIsResponse = kMessageIsResponse;
497 exports.Uint8 = Uint8;
498 exports.Uint16 = Uint16;
499 exports.Uint32 = Uint32;
500 exports.Uint64 = Uint64;
501 exports.PointerTo = PointerTo;
502 exports.ArrayOf = ArrayOf;
503 exports.Handle = Handle;
504 return exports;
505 });
OLDNEW
« no previous file with comments | « mojo/public/bindings/generators/js_templates/module.js.tmpl ('k') | mojo/public/bindings/js/connection.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698