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

Unified Diff: mojo/public/bindings/js/codec.js

Issue 69843003: Implement Mojo message codec in JavaScript (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Aaron's comments Created 7 years, 1 month 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mojo/mojo.gyp ('k') | mojo/public/bindings/js/codec_unittests.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mojo/public/bindings/js/codec.js
diff --git a/mojo/public/bindings/js/codec.js b/mojo/public/bindings/js/codec.js
new file mode 100644
index 0000000000000000000000000000000000000000..b7dcbeea6442a72443c518a7f6b73e4379da86c9
--- /dev/null
+++ b/mojo/public/bindings/js/codec.js
@@ -0,0 +1,407 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+define(function() {
+
+ // Memory -------------------------------------------------------------------
+
+ function store8(memory, pointer, val) {
+ memory[pointer] = val;
+ }
+
+ function store16(memory, pointer, val) {
+ memory[pointer + 0] = val >> 0;
+ memory[pointer + 1] = val >> 8;
+ }
+
+ function store32(memory, pointer, val) {
+ memory[pointer + 0] = val >> 0;
+ memory[pointer + 1] = val >> 8;
+ memory[pointer + 2] = val >> 16;
+ memory[pointer + 3] = val >> 24;
+ }
+
+ function store64(memory, pointer, val) {
+ store32(memory, pointer, val);
+ var high = (val / 0x10000) | 0;
+ store32(memory, pointer + 4, high);
+ }
+
+ function load8(memory, pointer) {
+ return memory[pointer];
+ }
+
+ function load16(memory, pointer) {
+ return (memory[pointer + 0] << 0) +
+ (memory[pointer + 1] << 8);
+ }
+
+ function load32(memory, pointer) {
+ return (memory[pointer + 0] << 0) +
+ (memory[pointer + 1] << 8) +
+ (memory[pointer + 2] << 16) +
+ (memory[pointer + 3] << 24);
+ }
+
+ function load64(memory, pointer) {
+ var low = load32(memory, pointer);
+ var high = load32(memory, pointer + 4);
+ return low + high * 0x10000;
+ }
+
+ // Buffer -------------------------------------------------------------------
+
+ function Buffer(size) {
+ this.memory = new Uint8Array(size);
+ this.next = 0;
+ }
+
+ Buffer.prototype.alloc = function(size) {
+ var pointer = this.next;
+ this.next += size;
+ if (this.next > this.memory.length) {
+ var newSize = (1.5 * (this.memory.length + size)) | 0;
+ this.grow(newSize);
+ }
+ return pointer;
+ };
+
+ Buffer.prototype.grow = function(size) {
+ var newMemory = new Uint8Array(size);
+ var oldMemory = this.memory;
+ for (var i = 0; i < oldMemory.length; ++i)
+ newMemory[i] = oldMemory[i];
+ this.memory = newMemory;
+ };
+
+ // Constants ----------------------------------------------------------------
+
+ var kArrayHeaderSize = 8;
+ var kStructHeaderSize = 8;
+ var kMessageHeaderSize = 8;
+
+ // Decoder ------------------------------------------------------------------
+
+ function Decoder(memory, handles, base) {
+ this.memory = memory;
+ this.handles = handles;
+ this.base = base;
+ this.next = base;
+ }
+
+ Decoder.prototype.skip = function(offset) {
+ this.next += offset;
+ };
+
+ Decoder.prototype.read8 = function() {
+ var result = load8(this.memory, this.next);
+ this.next += 1;
+ return result;
+ };
+
+ Decoder.prototype.read32 = function() {
+ var result = load32(this.memory, this.next);
+ this.next += 4;
+ return result;
+ };
+
+ Decoder.prototype.read64 = function() {
+ var result = load64(this.memory, this.next);
+ this.next += 8;
+ return result;
+ };
+
+ Decoder.prototype.decodePointer = function() {
+ // TODO(abarth): To correctly decode a pointer, we need to know the real
+ // base address of the array buffer.
+ var offsetPointer = this.next;
+ var offset = this.read64();
+ if (!offset)
+ return 0;
+ return offsetPointer + offset;
+ };
+
+ Decoder.prototype.decodeAndCreateDecoder = function() {
+ return new Decoder(this.memory, this.handles, this.decodePointer());
+ };
+
+ Decoder.prototype.decodeHandle = function() {
+ return this.handles[this.read32()];
+ };
+
+ Decoder.prototype.decodeString = function() {
+ // TODO(abarth): We should really support UTF-8. We might want to
+ // jump out of the VM to decode the string directly from the array
+ // buffer using v8::String::NewFromUtf8.
+ var numberOfBytes = this.read32();
+ var numberOfElements = this.read32();
+ var val = new Array(numberOfElements);
+ var memory = this.memory;
+ var base = this.next;
+ for (var i = 0; i < numberOfElements; ++i) {
+ val[i] = String.fromCharCode(memory[base + i] & 0x7F);
+ }
+ this.next += numberOfElements;
+ return val.join('');
+ };
+
+ Decoder.prototype.decodeArray = function(cls) {
+ var numberOfBytes = this.read32();
+ var numberOfElements = this.read32();
+ var val = new Array(numberOfElements);
+ for (var i = 0; i < numberOfElements; ++i) {
+ val[i] = cls.decode(this);
+ }
+ return val;
+ };
+
+ Decoder.prototype.decodeStructPointer = function(cls) {
+ return cls.decode(this.decodeAndCreateDecoder());
+ };
+
+ Decoder.prototype.decodeArrayPointer = function(cls) {
+ return this.decodeAndCreateDecoder().decodeArray(cls);
+ };
+
+ Decoder.prototype.decodeStringPointer = function() {
+ return this.decodeAndCreateDecoder().decodeString();
+ };
+
+ // Encoder ------------------------------------------------------------------
+
+ function Encoder(buffer, handles, base) {
+ this.buffer = buffer;
+ this.handles = handles;
+ this.base = base;
+ this.next = base;
+ }
+
+ Encoder.prototype.skip = function(offset) {
+ this.next += offset;
+ };
+
+ Encoder.prototype.write8 = function(val) {
+ store8(this.buffer.memory, this.next, val);
+ this.next += 1;
+ };
+
+ Encoder.prototype.write32 = function(val) {
+ store32(this.buffer.memory, this.next, val);
+ this.next += 4;
+ };
+
+ Encoder.prototype.write64 = function(val) {
+ store64(this.buffer.memory, this.next, val);
+ this.next += 8;
+ };
+
+ Encoder.prototype.encodePointer = function(pointer) {
+ if (!pointer)
+ return this.write64(0);
+ // TODO(abarth): To correctly encode a pointer, we need to know the real
+ // base address of the array buffer.
+ var offset = pointer - this.next;
+ this.write64(offset);
+ };
+
+ Encoder.prototype.createAndEncodeEncoder = function(size) {
+ var pointer = this.buffer.alloc(size);
+ this.encodePointer(pointer);
+ return new Encoder(this.buffer, this.handles, pointer);
+ };
+
+ Encoder.prototype.encodeHandle = function(handle) {
+ this.handles.push(handle);
+ this.write32(this.handles.length - 1);
+ };
+
+ Encoder.prototype.encodeString = function(val) {
+ var numberOfElements = val.length;
+ var numberOfBytes = kArrayHeaderSize + numberOfElements;
+ this.write32(numberOfBytes);
+ this.write32(numberOfElements);
+ // TODO(abarth): We should really support UTF-8. We might want to
+ // jump out of the VM to encode the string directly from the array
+ // buffer using v8::String::WriteUtf8.
+ var memory = this.buffer.memory;
+ var base = this.next;
+ var len = val.length;
+ for (var i = 0; i < len; ++i) {
+ memory[base + i] = val.charCodeAt(i) & 0x7F;
+ }
+ this.next += len;
+ };
+
+ Encoder.prototype.encodeArray = function(cls, val) {
+ var numberOfElements = val.length;
+ var numberOfBytes = kArrayHeaderSize + cls.encodedSize * numberOfElements;
+ this.write32(numberOfBytes);
+ this.write32(numberOfElements);
+ for (var i = 0; i < numberOfElements; ++i) {
+ cls.encode(this, val[i]);
+ }
+ };
+
+ Encoder.prototype.encodeStructPointer = function(cls, val) {
+ var encoder = this.createAndEncodeEncoder(cls.encodedSize);
+ cls.encode(encoder, val);
+ };
+
+ Encoder.prototype.encodeArrayPointer = function(cls, val) {
+ var encodedSize = kArrayHeaderSize + cls.encodedSize * val.length;
+ var encoder = this.createAndEncodeEncoder(encodedSize);
+ encoder.encodeArray(cls, val);
+ };
+
+ Encoder.prototype.encodeStringPointer = function(val) {
+ // TODO(abarth): This won't be right once we support UTF-8.
+ var encodedSize = kArrayHeaderSize + val.length;
+ var encoder = this.createAndEncodeEncoder(encodedSize);
+ encoder.encodeString(val);
+ };
+
+ // Message ------------------------------------------------------------------
+
+ function Message(memory, handles) {
+ this.memory = memory;
+ this.handles = handles;
+ }
+
+ // MessageBuilder -----------------------------------------------------------
+
+ function MessageBuilder(messageName, payloadSize) {
+ var numberOfBytes = kMessageHeaderSize + payloadSize;
+ this.buffer = new Buffer(numberOfBytes);
+ this.handles = [];
+ var encoder = this.createEncoder(kMessageHeaderSize);
+ encoder.write32(numberOfBytes);
+ encoder.write32(messageName);
+ }
+
+ MessageBuilder.prototype.createEncoder = function(size) {
+ var pointer = this.buffer.alloc(size);
+ return new Encoder(this.buffer, this.handles, pointer);
+ }
+
+ MessageBuilder.prototype.encodeStruct = function(cls, val) {
+ cls.encode(this.createEncoder(cls.encodedSize), val);
+ };
+
+ MessageBuilder.prototype.finish = function() {
+ var message = new Message(this.buffer.memory, this.handles);
+ this.buffer = null;
+ this.handles = null;
+ this.encoder = null;
+ return message;
+ };
+
+ // MessageReader ------------------------------------------------------------
+
+ function MessageReader(message) {
+ this.decoder = new Decoder(message.memory, message.handles, 0);
+ this.payloadSize = this.decoder.read32() - kMessageHeaderSize;
+ this.messageName = this.decoder.read32();
+ }
+
+ MessageReader.prototype.decodeStruct = function(cls) {
+ return cls.decode(this.decoder);
+ };
+
+ // Built-in types -----------------------------------------------------------
+
+ function Uint8() {
+ }
+
+ Uint8.encodedSize = 1;
+
+ Uint8.decode = function(decoder) {
+ return decoder.read8();
+ };
+
+ Uint8.encode = function(encoder, val) {
+ encoder.write8(val);
+ };
+
+ function Uint16() {
+ }
+
+ Uint16.encodedSize = 2;
+
+ Uint16.decode = function(decoder) {
+ return decoder.read16();
+ };
+
+ Uint16.encode = function(encoder, val) {
+ encoder.write16(val);
+ };
+
+ function Uint32() {
+ }
+
+ Uint32.encodedSize = 4;
+
+ Uint32.decode = function(decoder) {
+ return decoder.read32();
+ };
+
+ Uint32.encode = function(encoder, val) {
+ encoder.write32(val);
+ };
+
+ function Uint64() {
+ };
+
+ Uint64.encodedSize = 8;
+
+ Uint64.decode = function(decoder) {
+ return decoder.read64();
+ };
+
+ Uint64.encode = function(encoder, val) {
+ encoder.write64(val);
+ };
+
+ function PointerTo(cls) {
+ this.cls = cls;
+ };
+
+ PointerTo.prototype.encodedSize = 8;
+
+ PointerTo.prototype.decode = function(decoder) {
+ return this.cls.decode(decoder.decodeAndCreateDecoder());
+ };
+
+ PointerTo.prototype.encode = function(encoder, val) {
+ var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize);
+ this.cls.encode(objectEncoder, val);
+ };
+
+ function Handle() {
+ }
+
+ Handle.encodedSize = 4;
+
+ Handle.decode = function(decoder) {
+ return decoder.decodeHandle();
+ };
+
+ Handle.encode = function(encoder, val) {
+ encoder.encodeHandle(val);
+ };
+
+ var exports = {};
+ exports.load32 = load32;
+ exports.MessageBuilder = MessageBuilder;
+ exports.MessageReader = MessageReader;
+ exports.kArrayHeaderSize = kArrayHeaderSize;
+ exports.kStructHeaderSize = kStructHeaderSize;
+ exports.kMessageHeaderSize = kMessageHeaderSize;
+ exports.Uint8 = Uint8;
+ exports.Uint16 = Uint16;
+ exports.Uint32 = Uint32;
+ exports.Uint64 = Uint64;
+ exports.PointerTo = PointerTo;
+ exports.Handle = Handle;
+ return exports;
+});
« no previous file with comments | « mojo/mojo.gyp ('k') | mojo/public/bindings/js/codec_unittests.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698