js/src/vm/Xdr.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef vm_Xdr_h
michael@0 8 #define vm_Xdr_h
michael@0 9
michael@0 10 #include "mozilla/Endian.h"
michael@0 11 #include "mozilla/TypeTraits.h"
michael@0 12
michael@0 13 #include "jsatom.h"
michael@0 14
michael@0 15 namespace js {
michael@0 16
michael@0 17 /*
michael@0 18 * Bytecode version number. Increment the subtrahend whenever JS bytecode
michael@0 19 * changes incompatibly.
michael@0 20 *
michael@0 21 * This version number is XDR'd near the front of xdr bytecode and
michael@0 22 * aborts deserialization if there is a mismatch between the current
michael@0 23 * and saved versions. If deserialization fails, the data should be
michael@0 24 * invalidated if possible.
michael@0 25 */
michael@0 26 static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 172);
michael@0 27
michael@0 28 class XDRBuffer {
michael@0 29 public:
michael@0 30 XDRBuffer(JSContext *cx)
michael@0 31 : context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { }
michael@0 32
michael@0 33 JSContext *cx() const {
michael@0 34 return context;
michael@0 35 }
michael@0 36
michael@0 37 void *getData(uint32_t *lengthp) const {
michael@0 38 JS_ASSERT(size_t(cursor - base) <= size_t(UINT32_MAX));
michael@0 39 *lengthp = uint32_t(cursor - base);
michael@0 40 return base;
michael@0 41 }
michael@0 42
michael@0 43 void setData(const void *data, uint32_t length) {
michael@0 44 base = static_cast<uint8_t *>(const_cast<void *>(data));
michael@0 45 cursor = base;
michael@0 46 limit = base + length;
michael@0 47 }
michael@0 48
michael@0 49 const uint8_t *read(size_t n) {
michael@0 50 JS_ASSERT(n <= size_t(limit - cursor));
michael@0 51 uint8_t *ptr = cursor;
michael@0 52 cursor += n;
michael@0 53 return ptr;
michael@0 54 }
michael@0 55
michael@0 56 const char *readCString() {
michael@0 57 char *ptr = reinterpret_cast<char *>(cursor);
michael@0 58 cursor = reinterpret_cast<uint8_t *>(strchr(ptr, '\0')) + 1;
michael@0 59 JS_ASSERT(base < cursor);
michael@0 60 JS_ASSERT(cursor <= limit);
michael@0 61 return ptr;
michael@0 62 }
michael@0 63
michael@0 64 uint8_t *write(size_t n) {
michael@0 65 if (n > size_t(limit - cursor)) {
michael@0 66 if (!grow(n))
michael@0 67 return nullptr;
michael@0 68 }
michael@0 69 uint8_t *ptr = cursor;
michael@0 70 cursor += n;
michael@0 71 return ptr;
michael@0 72 }
michael@0 73
michael@0 74 static bool isUint32Overflow(size_t n) {
michael@0 75 return size_t(-1) > size_t(UINT32_MAX) && n > size_t(UINT32_MAX);
michael@0 76 }
michael@0 77
michael@0 78 void freeBuffer();
michael@0 79
michael@0 80 private:
michael@0 81 bool grow(size_t n);
michael@0 82
michael@0 83 JSContext *const context;
michael@0 84 uint8_t *base;
michael@0 85 uint8_t *cursor;
michael@0 86 uint8_t *limit;
michael@0 87 };
michael@0 88
michael@0 89 /*
michael@0 90 * XDR serialization state. All data is encoded in little endian.
michael@0 91 */
michael@0 92 template <XDRMode mode>
michael@0 93 class XDRState {
michael@0 94 public:
michael@0 95 XDRBuffer buf;
michael@0 96
michael@0 97 protected:
michael@0 98 JSPrincipals *originPrincipals_;
michael@0 99
michael@0 100 XDRState(JSContext *cx)
michael@0 101 : buf(cx), originPrincipals_(nullptr) {
michael@0 102 }
michael@0 103
michael@0 104 public:
michael@0 105 JSContext *cx() const {
michael@0 106 return buf.cx();
michael@0 107 }
michael@0 108
michael@0 109 JSPrincipals *originPrincipals() const {
michael@0 110 return originPrincipals_;
michael@0 111 }
michael@0 112
michael@0 113 bool codeUint8(uint8_t *n) {
michael@0 114 if (mode == XDR_ENCODE) {
michael@0 115 uint8_t *ptr = buf.write(sizeof *n);
michael@0 116 if (!ptr)
michael@0 117 return false;
michael@0 118 *ptr = *n;
michael@0 119 } else {
michael@0 120 *n = *buf.read(sizeof *n);
michael@0 121 }
michael@0 122 return true;
michael@0 123 }
michael@0 124
michael@0 125 bool codeUint16(uint16_t *n) {
michael@0 126 if (mode == XDR_ENCODE) {
michael@0 127 uint8_t *ptr = buf.write(sizeof *n);
michael@0 128 if (!ptr)
michael@0 129 return false;
michael@0 130 mozilla::LittleEndian::writeUint16(ptr, *n);
michael@0 131 } else {
michael@0 132 const uint8_t *ptr = buf.read(sizeof *n);
michael@0 133 *n = mozilla::LittleEndian::readUint16(ptr);
michael@0 134 }
michael@0 135 return true;
michael@0 136 }
michael@0 137
michael@0 138 bool codeUint32(uint32_t *n) {
michael@0 139 if (mode == XDR_ENCODE) {
michael@0 140 uint8_t *ptr = buf.write(sizeof *n);
michael@0 141 if (!ptr)
michael@0 142 return false;
michael@0 143 mozilla::LittleEndian::writeUint32(ptr, *n);
michael@0 144 } else {
michael@0 145 const uint8_t *ptr = buf.read(sizeof *n);
michael@0 146 *n = mozilla::LittleEndian::readUint32(ptr);
michael@0 147 }
michael@0 148 return true;
michael@0 149 }
michael@0 150
michael@0 151 bool codeUint64(uint64_t *n) {
michael@0 152 if (mode == XDR_ENCODE) {
michael@0 153 uint8_t *ptr = buf.write(sizeof(*n));
michael@0 154 if (!ptr)
michael@0 155 return false;
michael@0 156 mozilla::LittleEndian::writeUint64(ptr, *n);
michael@0 157 } else {
michael@0 158 const uint8_t *ptr = buf.read(sizeof(*n));
michael@0 159 *n = mozilla::LittleEndian::readUint64(ptr);
michael@0 160 }
michael@0 161 return true;
michael@0 162 }
michael@0 163
michael@0 164 /*
michael@0 165 * Use SFINAE to refuse any specialization which is not an enum. Uses of
michael@0 166 * this function do not have to specialize the type of the enumerated field
michael@0 167 * as C++ will extract the parameterized from the argument list.
michael@0 168 */
michael@0 169 template <typename T>
michael@0 170 bool codeEnum32(T *val, typename mozilla::EnableIf<mozilla::IsEnum<T>::value, T>::Type * = NULL)
michael@0 171 {
michael@0 172 uint32_t tmp;
michael@0 173 if (mode == XDR_ENCODE)
michael@0 174 tmp = *val;
michael@0 175 if (!codeUint32(&tmp))
michael@0 176 return false;
michael@0 177 if (mode == XDR_DECODE)
michael@0 178 *val = T(tmp);
michael@0 179 return true;
michael@0 180 }
michael@0 181
michael@0 182 bool codeDouble(double *dp) {
michael@0 183 union DoublePun {
michael@0 184 double d;
michael@0 185 uint64_t u;
michael@0 186 } pun;
michael@0 187 if (mode == XDR_ENCODE)
michael@0 188 pun.d = *dp;
michael@0 189 if (!codeUint64(&pun.u))
michael@0 190 return false;
michael@0 191 if (mode == XDR_DECODE)
michael@0 192 *dp = pun.d;
michael@0 193 return true;
michael@0 194 }
michael@0 195
michael@0 196 bool codeBytes(void *bytes, size_t len) {
michael@0 197 if (mode == XDR_ENCODE) {
michael@0 198 uint8_t *ptr = buf.write(len);
michael@0 199 if (!ptr)
michael@0 200 return false;
michael@0 201 memcpy(ptr, bytes, len);
michael@0 202 } else {
michael@0 203 memcpy(bytes, buf.read(len), len);
michael@0 204 }
michael@0 205 return true;
michael@0 206 }
michael@0 207
michael@0 208 /*
michael@0 209 * During encoding the string is written into the buffer together with its
michael@0 210 * terminating '\0'. During decoding the method returns a pointer into the
michael@0 211 * decoding buffer and the caller must copy the string if it will outlive
michael@0 212 * the decoding buffer.
michael@0 213 */
michael@0 214 bool codeCString(const char **sp) {
michael@0 215 if (mode == XDR_ENCODE) {
michael@0 216 size_t n = strlen(*sp) + 1;
michael@0 217 uint8_t *ptr = buf.write(n);
michael@0 218 if (!ptr)
michael@0 219 return false;
michael@0 220 memcpy(ptr, *sp, n);
michael@0 221 } else {
michael@0 222 *sp = buf.readCString();
michael@0 223 }
michael@0 224 return true;
michael@0 225 }
michael@0 226
michael@0 227 bool codeChars(jschar *chars, size_t nchars);
michael@0 228
michael@0 229 bool codeFunction(JS::MutableHandleObject objp);
michael@0 230 bool codeScript(MutableHandleScript scriptp);
michael@0 231 bool codeConstValue(MutableHandleValue vp);
michael@0 232 };
michael@0 233
michael@0 234 class XDREncoder : public XDRState<XDR_ENCODE> {
michael@0 235 public:
michael@0 236 XDREncoder(JSContext *cx)
michael@0 237 : XDRState<XDR_ENCODE>(cx) {
michael@0 238 }
michael@0 239
michael@0 240 ~XDREncoder() {
michael@0 241 buf.freeBuffer();
michael@0 242 }
michael@0 243
michael@0 244 const void *getData(uint32_t *lengthp) const {
michael@0 245 return buf.getData(lengthp);
michael@0 246 }
michael@0 247
michael@0 248 void *forgetData(uint32_t *lengthp) {
michael@0 249 void *data = buf.getData(lengthp);
michael@0 250 buf.setData(nullptr, 0);
michael@0 251 return data;
michael@0 252 }
michael@0 253 };
michael@0 254
michael@0 255 class XDRDecoder : public XDRState<XDR_DECODE> {
michael@0 256 public:
michael@0 257 XDRDecoder(JSContext *cx, const void *data, uint32_t length,
michael@0 258 JSPrincipals *originPrincipals);
michael@0 259
michael@0 260 };
michael@0 261
michael@0 262 } /* namespace js */
michael@0 263
michael@0 264 #endif /* vm_Xdr_h */

mercurial