diff --git a/toolkit/components/osfile/osfile_async_front.jsm b/toolkit/components/osfile/osfile_async_front.jsm index 2ee584c226e..39ad18aecdc 100644 --- a/toolkit/components/osfile/osfile_async_front.jsm +++ b/toolkit/components/osfile/osfile_async_front.jsm @@ -240,37 +240,13 @@ File.prototype = { * @resolves {Uint8Array} An array containing the bytes read. */ read: function read(nbytes) { - // FIXME: Once bug 720949 has landed, we might be able to simplify - // the implementation of |readAll| - let self = this; - let promise; - if (nbytes != null) { - promise = Promise.resolve(nbytes); - } else { - promise = this.stat(); - promise = promise.then(function withStat(stat) { - return stat.size; + let promise = Scheduler.post("File_prototype_read", + [this._fdmsg, + nbytes]); + return promise.then( + function onSuccess(data) { + return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); }); - } - let array; - let size; - promise = promise.then( - function withSize(aSize) { - size = aSize; - array = new Uint8Array(size); - return self.readTo(array); - } - ); - promise = promise.then( - function afterReadTo(bytes) { - if (bytes == size) { - return array; - } else { - return array.subarray(0, bytes); - } - } - ); - return promise; }, /** @@ -475,8 +451,12 @@ File.makeDir = function makeDir(path, options) { * read from the file. */ File.read = function read(path, bytes) { - return Scheduler.post("read", + let promise = Scheduler.post("read", [Type.path.toMsg(path), bytes], path); + return promise.then( + function onSuccess(data) { + return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + }); }; /** diff --git a/toolkit/components/osfile/osfile_async_worker.js b/toolkit/components/osfile/osfile_async_worker.js index 495fc4e8fe3..41c5609c28b 100644 --- a/toolkit/components/osfile/osfile_async_worker.js +++ b/toolkit/components/osfile/osfile_async_worker.js @@ -62,7 +62,12 @@ if (this.Components) { if (DEBUG) { LOG("Sending positive reply", JSON.stringify(result), "id is", id); } - self.postMessage({ok: result, id:id}); + if (result instanceof Transfer) { + // Take advantage of zero-copy transfers + self.postMessage({ok: result.data, id: id}, result.transfers); + } else { + self.postMessage({ok: result, id:id}); + } } else if (exn == StopIteration) { // StopIteration cannot be serialized automatically if (DEBUG) { @@ -173,6 +178,21 @@ if (this.Components) { let File = exports.OS.File; + /** + * A constructor used to transfer data to the caller + * without copy. + * + * @param {*} data The data to return to the caller. + * @param {Array} transfers An array of Transferable + * values that should be moved instead of being copied. + * + * @constructor + */ + let Transfer = function Transfer(data, transfers) { + this.data = data; + this.transfers = transfers; + }; + /** * The agent. * @@ -214,7 +234,8 @@ if (this.Components) { return OpenedFiles.add(file); }, read: function read(path, bytes) { - return File.read(Type.path.fromMsg(path), bytes); + let data = File.read(Type.path.fromMsg(path), bytes); + return new Transfer({buffer: data.buffer, byteOffset: data.byteOffset, byteLength: data.byteLength}, [data.buffer]); }, exists: function exists(path) { return File.exists(Type.path.fromMsg(path)); @@ -249,6 +270,14 @@ if (this.Components) { return exports.OS.File.Info.toMsg(this.stat()); }); }, + File_prototype_read: function read(fd, nbytes, options) { + return withFile(fd, + function do_read() { + let data = this.read(nbytes, options); + return new Transfer({buffer: data.buffer, byteOffset: data.byteOffset, byteLength: data.byteLength}, [data.buffer]); + } + ); + }, File_prototype_readTo: function readTo(fd, buffer, options) { return withFile(fd, function do_readTo() {