Chromium Code Reviews| 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..0f6f71ce7514d4daacb5eaad7547c9d9f134c999 |
| --- /dev/null |
| +++ b/mojo/public/bindings/js/codec.js |
| @@ -0,0 +1,394 @@ |
| +// 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. |
| + |
| +// Memory --------------------------------------------------------------------- |
| + |
| +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
|
| + memory[ptr] = val; |
| +} |
| + |
| +function load8(memory, ptr, val) { |
| + return memory[ptr]; |
| +} |
| + |
| +function store16(memory, ptr, val) { |
| + memory[ptr + 0] = val >> 0; |
| + memory[ptr + 1] = val >> 8; |
| +} |
| + |
| +function load16(memory, ptr, val) { |
| + return memory[ptr + 0] << 0 + |
| + memory[ptr + 1] << 8; |
| +} |
| + |
| +function store32(memory, ptr, val) { |
| + memory[ptr + 0] = val >> 0; |
| + memory[ptr + 1] = val >> 8; |
| + memory[ptr + 2] = val >> 16; |
| + memory[ptr + 3] = val >> 24; |
| +} |
| + |
| +function load32(memory, ptr, val) { |
| + return memory[ptr + 0] << 0 + |
| + memory[ptr + 1] << 8 + |
| + memory[ptr + 2] << 16 + |
| + memory[ptr + 3] << 24; |
| +} |
| + |
| +function store64(memory, ptr, val) { |
| + memory[ptr + 0] = val >> 0; |
| + memory[ptr + 1] = val >> 8; |
| + memory[ptr + 2] = val >> 16; |
| + memory[ptr + 3] = val >> 24; |
| + memory[ptr + 4] = val >> 32; |
| + memory[ptr + 5] = val >> 40; |
| + memory[ptr + 6] = val >> 48; |
| + memory[ptr + 7] = val >> 56; |
| +} |
| + |
| +function load64(memory, ptr, val) { |
| + return memory[ptr + 0] << 0 + |
| + memory[ptr + 1] << 8 + |
| + memory[ptr + 2] << 16 + |
| + memory[ptr + 3] << 24 + |
| + memory[ptr + 4] << 32 + |
| + memory[ptr + 5] << 40 + |
| + memory[ptr + 6] << 48 + |
| + memory[ptr + 7] << 56; |
| +} |
| + |
| +function align(size) { |
| + var kAlignment = 8; |
| + 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
|
| +} |
| + |
| +// Serialization -------------------------------------------------------------- |
| + |
| +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
|
| + if (!ptr) { |
| + store64(memory, offsetPtr, 0); |
| + return; |
| + } |
| + var offset = ptr - offsetPtr; |
| + store64(memory, offsetPtr, offset); |
| +} |
| + |
| +function decodePointer(memory, offsetPtr) { |
| + var offset = load64(memory, offsetPtr); |
| + if (!offset) |
| + return 0; |
| + return offsetPtr + offset; |
| +} |
| + |
| +function encodeHandle(memory, handlePtr, handles) { |
| + handles.push(load32(memory, handlePtr)); |
| + store32(memory, handlePtr, handles.length - 1); |
| +} |
| + |
| +function decodeHandle(memory, handlePtr, handles) { |
| + var index = load32(memory, handlePtr); |
| + store32(memory, handlePtr, handles[index]); |
| +} |
| + |
| +// Record --------------------------------------------------------------------- |
| + |
| +function Record(memory, ptr) { |
| + this.memory = memory; |
| + this.base = ptr; |
| + this.next = ptr; |
| +} |
| + |
| +Record.prototype.advance = function(offset) { |
| + this.next += offset; |
| +} |
| + |
| +Record.prototype.readPtr = function() { |
| + var ptr = decodePointer(this.memory, this.next); |
| + this.next += 8; |
| + return ptr; |
| +} |
| + |
| +Record.prototype.writePtr = function(ptr) { |
| + encodePointer(this.memory, ptr, this.next); |
| + this.next += 8; |
| +} |
| + |
| +Record.prototype.readRecord = function() { |
| + return new Record(this.memory, this.readPtr()); |
| +} |
| + |
| +Record.prototype.readString = function(len) { |
| + // 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. |
|
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
|
| + var result = ""; |
| + var memory = this.memory; |
| + var base = this.next; |
| + for (var i = 0; i < len; ++i) { |
| + result += String.fromCharCode(memory[base + i] & 0x7F); |
| + } |
| + this.next += len; |
| + return result; |
| +} |
| + |
| +Record.prototype.read8 = function() { |
| + var result = load8(this.memory, this.next); |
| + this.next += 1; |
| + return result; |
| +} |
| + |
| +Record.prototype.read32 = function() { |
| + var result = load32(this.memory, this.next); |
| + this.next += 4; |
| + return result; |
| +} |
| + |
| +Record.prototype.read64 = function() { |
| + var result = load64(this.memory, this.next); |
| + this.next += 8; |
| + return result; |
| +} |
| + |
| +Record.prototype.write8 = function(val) { |
| + store8(this.memory, this.next, val); |
| + this.next += 1; |
| +} |
| + |
| +Record.prototype.write32 = function(val) { |
| + var after = this.next + 4; |
| + store32(this.memory, this.next, val); |
| + this.next += 4; |
| +}; |
| + |
| +Record.prototype.write64 = function(val) { |
| + store64(this.memory, this.next, val); |
| + this.next += 8; |
| +}; |
| + |
| +// Buffer --------------------------------------------------------------------- |
| + |
| +function Buffer(size) { |
| + this.memory = new Uint8Array(size); |
| + this.nextAllocation = 0; |
| +} |
| + |
| +Buffer.prototype.alloc = function(size) { |
| + var ptr = this.nextAllocation; |
| + this.nextAllocation += size; |
| + if (this.nextAllocation > this.memory.length) |
| + throw "Buffer full."; |
| + return new Record(this.memory, ptr); |
| +}; |
| + |
| +// Fields --------------------------------------------------------------------- |
| + |
| +var kArrayHeaderSize = 8; |
| +var kStructHeaderSize = 8; |
| + |
| +function encodeArray(record, class, val) { |
| + var numberOfElements = val.length; |
| + record.write32(kArrayHeaderSize + class.encodedSize * numberOfElements); |
| + record.write32(numberOfElements); |
| + for (var i = 0; i < numberOfElements; ++i) { |
| + class.encode(record, val[i]); |
| + } |
| + // TODO(abarth): We should sanity check that everthing fits. |
| +} |
| + |
| +function decodeArray(record, class) { |
| + var numberOfBytes = record.read32(); |
| + var numberOfElements = record.read32(); |
| + var val = []; |
| + for (var i = 0; i < numberOfElements; ++i) { |
| + val.push(class.decode(record)); |
| + } |
| + // TODO(abarth): We should sanity check that everthing fits. |
| + return val; |
| +} |
| + |
| +function decodeString(record) { |
| + var numberOfBytes = record.read32(); |
| + var numberOfElements = record.read32(); |
| + return record.readString(numberOfElements); |
| +} |
| + |
| +// Message -------------------------------------------------------------------- |
| + |
| +var kMessageHeaderSize = 8; |
| + |
| +function Message() { |
| + this.memory = null; |
| + this.handles = []; |
| +} |
| + |
| +Message.prototype.dispose = function() { |
| + var len = this.handles.length; |
| + for (var i = 0; i < len; ++i) { |
| + mojo.core.close(this.handles[i]); |
| + this.handles[i] = mojo.core.HANDLE_INVALID; |
| + } |
| +}; |
| + |
| +// MessageBuilder ------------------------------------------------------------- |
| + |
| +function MessageBuilder(messageName, payloadSize) { |
| + var buffer = new Buffer(kMessageHeaderSize + payloadSize); |
| + var header = buffer.alloc(kMessageHeaderSize); |
| + header.write32(buffer.length); |
| + header.write32(messageName); |
| + |
| + this.buffer = buffer; |
| +} |
| + |
| +MessageBuilder.prototype.takeBuffer = function() { |
| + var buffer = this.buffer; |
| + this.buffer = null; |
| + return buffer; |
| +}; |
| + |
| +// Basic types ---------------------------------------------------------------- |
| + |
| +function Uint8() { |
| +} |
| + |
| +Uint8.encodedSize = 1; |
| + |
| +Uint8.decode = function(record) { |
| + return record.read8(); |
| +}; |
| + |
| +Uint8.encode = function(record, val) { |
| + record.write8(val); |
| +}; |
| + |
| +function Ptr(class) { |
| + this.class = class; |
| +}; |
| + |
| +Ptr.prototype.encodedSize = 8; |
| + |
| +Ptr.prototype.decode = function(record) { |
| + return class.decode(record.readRecord()); |
| +}; |
| + |
| +Ptr.prototype.encode = function(record, val) { |
| + // TODO(abarth): Where does |buffer| come from? |
| + objectRecord = buffer.alloc(class.encodedSize); |
| + class.encode(objectRecord, val); |
| + record.writePtr(objectRecord.base); |
| +}; |
| + |
| +function Handle() { |
| +} |
| + |
| +// TOOD(abarth): Implement handles. |
| + |
| +// "Generated" code =========================================================== |
| + |
| +function Bar() { |
| + this.alpha = 0; |
| + this.beta = 0; |
| + this.gamma = 0; |
| +} |
| + |
| +Bar.encodedSize = kStructHeaderSize + 8; |
| + |
| +Bar.decode = function(record) { |
| + var val = new Bar(); |
| + // TODO(abarth): We need to support optional fields. |
| + record.advance(kStructHeaderSize); |
| + val.alpha = record.read8(); |
| + val.beta = record.read8(); |
| + val.gamma = record.read8(); |
| + record.advance(5); |
| + return val; |
| +}; |
| + |
| +Bar.encode = function(record, val) { |
| + record.write32(Bar.encodedSize); |
| + record.write32(3); |
| + record.write8(val.alpha); |
| + record.write8(val.beta); |
| + record.write8(val.gamma); |
| + record.advance(5); |
| +}; |
| + |
| + // int32_t x_; |
| + // int32_t y_; |
| + // uint8_t a_ : 1; |
| + // uint8_t b_ : 1; |
| + // uint8_t c_ : 1; |
| + // uint8_t _pad0_[7]; |
| + // mojo::internal::StructPointer<Bar> bar_; |
| + // mojo::internal::ArrayPointer<uint8_t> data_; |
| + // mojo::internal::ArrayPointer<Bar*> extra_bars_; |
| + // mojo::internal::StringPointer name_; |
| + // mojo::internal::ArrayPointer<mojo::Handle> files_; |
| + |
| +function Foo() { |
| + this.x = 0; |
| + this.y = 0; |
| + this.a = 0; |
| + this.b = 0; |
| + this.c = 0; |
| + this.bar = null; |
| + this.data = null; |
| + this.extra_bars = null; |
| + this.name = null; |
| + this.files = null; |
| +} |
| + |
| +Foo.encodedSize = 64; |
| + |
| +Foo.decode = function(record) { |
| + var val = new Foo(); |
| + // TODO(abarth): We need to support optional fields. |
| + record.advance(kStructHeaderSize); |
| + val.x = record.read32(); |
| + val.y = record.read32(); |
| + var packed = record.read8(); |
| + val.a = (packed >> 0) & 1; |
| + val.b = (packed >> 1) & 1; |
| + val.c = (packed >> 2) & 1; |
| + record.advance(7); |
| + val.bar = Bar.decode(record.readRecord()); |
| + val.data = decodeArray(record.readRecord(), Uint8); |
| + val.extra_bars = decodeArray(record.readRecord(), new Ptr(Bar)); |
| + val.name = decodeString(record.readRecord()); |
| + val.files = decodeArray(record.readRecord(), Handle); |
| +} |
| + |
| +Foo.encode = function(record, val) { |
| + record.write32(Foo.encodedSize); |
| + record.write32(10); |
| + record.write32(val.x); |
| + record.write32(val.y); |
| + var packed = (val.a & 1) << 0 | |
| + (val.b & 1) << 1 | |
| + (val.c & 1) << 2; |
| + record.write8(packed); |
| + record.advance(7); |
| + |
| + // TODO(abarth): Where does buffer come from? |
| + var barRecord = buffer.alloc(Bar.encodedSize); |
| + Bar.encode(barRecord, val.bar); |
| + record.writePtr(barRecord.base); |
| + |
| + var dataRecord = buffer.alloc(Uint8.encodedSize); |
| + encodeArray(dataRecord, Uint8, this.data); |
| + record.writePtr(dataRecord.base); |
| + |
| + var extra_barsClass = new Ptr(Bar); |
| + var extra_barsRecord = buffer.alloc(extra_barsClass.encodedSize); |
| + encodeArray(dataRecord, extra_barsClass, this.data); |
| + record.writePtr(extra_barsRecord.base); |
| + |
| + // TODO(abarth): We'll need something fancier here to support UTF-8. |
| + var nameLength = val.name.length; |
| + nameRecord = buffer.alloc(nameLength); |
| + encodeString(nameRecord, val.name); |
| + record.writePtr(nameRecord.base); |
| + |
| + // TODO(abarth): We need to be able to encode handles. |
| +}; |