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. |
+}; |