js/src/vm/Xdr.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/vm/Xdr.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,264 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef vm_Xdr_h
    1.11 +#define vm_Xdr_h
    1.12 +
    1.13 +#include "mozilla/Endian.h"
    1.14 +#include "mozilla/TypeTraits.h"
    1.15 +
    1.16 +#include "jsatom.h"
    1.17 +
    1.18 +namespace js {
    1.19 +
    1.20 +/*
    1.21 + * Bytecode version number. Increment the subtrahend whenever JS bytecode
    1.22 + * changes incompatibly.
    1.23 + *
    1.24 + * This version number is XDR'd near the front of xdr bytecode and
    1.25 + * aborts deserialization if there is a mismatch between the current
    1.26 + * and saved versions. If deserialization fails, the data should be
    1.27 + * invalidated if possible.
    1.28 + */
    1.29 +static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 172);
    1.30 +
    1.31 +class XDRBuffer {
    1.32 +  public:
    1.33 +    XDRBuffer(JSContext *cx)
    1.34 +      : context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { }
    1.35 +
    1.36 +    JSContext *cx() const {
    1.37 +        return context;
    1.38 +    }
    1.39 +
    1.40 +    void *getData(uint32_t *lengthp) const {
    1.41 +        JS_ASSERT(size_t(cursor - base) <= size_t(UINT32_MAX));
    1.42 +        *lengthp = uint32_t(cursor - base);
    1.43 +        return base;
    1.44 +    }
    1.45 +
    1.46 +    void setData(const void *data, uint32_t length) {
    1.47 +        base = static_cast<uint8_t *>(const_cast<void *>(data));
    1.48 +        cursor = base;
    1.49 +        limit = base + length;
    1.50 +    }
    1.51 +
    1.52 +    const uint8_t *read(size_t n) {
    1.53 +        JS_ASSERT(n <= size_t(limit - cursor));
    1.54 +        uint8_t *ptr = cursor;
    1.55 +        cursor += n;
    1.56 +        return ptr;
    1.57 +    }
    1.58 +
    1.59 +    const char *readCString() {
    1.60 +        char *ptr = reinterpret_cast<char *>(cursor);
    1.61 +        cursor = reinterpret_cast<uint8_t *>(strchr(ptr, '\0')) + 1;
    1.62 +        JS_ASSERT(base < cursor);
    1.63 +        JS_ASSERT(cursor <= limit);
    1.64 +        return ptr;
    1.65 +    }
    1.66 +
    1.67 +    uint8_t *write(size_t n) {
    1.68 +        if (n > size_t(limit - cursor)) {
    1.69 +            if (!grow(n))
    1.70 +                return nullptr;
    1.71 +        }
    1.72 +        uint8_t *ptr = cursor;
    1.73 +        cursor += n;
    1.74 +        return ptr;
    1.75 +    }
    1.76 +
    1.77 +    static bool isUint32Overflow(size_t n) {
    1.78 +        return size_t(-1) > size_t(UINT32_MAX) && n > size_t(UINT32_MAX);
    1.79 +    }
    1.80 +
    1.81 +    void freeBuffer();
    1.82 +
    1.83 +  private:
    1.84 +    bool grow(size_t n);
    1.85 +
    1.86 +    JSContext   *const context;
    1.87 +    uint8_t     *base;
    1.88 +    uint8_t     *cursor;
    1.89 +    uint8_t     *limit;
    1.90 +};
    1.91 +
    1.92 +/*
    1.93 + * XDR serialization state.  All data is encoded in little endian.
    1.94 + */
    1.95 +template <XDRMode mode>
    1.96 +class XDRState {
    1.97 +  public:
    1.98 +    XDRBuffer buf;
    1.99 +
   1.100 +  protected:
   1.101 +    JSPrincipals *originPrincipals_;
   1.102 +
   1.103 +    XDRState(JSContext *cx)
   1.104 +      : buf(cx), originPrincipals_(nullptr) {
   1.105 +    }
   1.106 +
   1.107 +  public:
   1.108 +    JSContext *cx() const {
   1.109 +        return buf.cx();
   1.110 +    }
   1.111 +
   1.112 +    JSPrincipals *originPrincipals() const {
   1.113 +        return originPrincipals_;
   1.114 +    }
   1.115 +
   1.116 +    bool codeUint8(uint8_t *n) {
   1.117 +        if (mode == XDR_ENCODE) {
   1.118 +            uint8_t *ptr = buf.write(sizeof *n);
   1.119 +            if (!ptr)
   1.120 +                return false;
   1.121 +            *ptr = *n;
   1.122 +        } else {
   1.123 +            *n = *buf.read(sizeof *n);
   1.124 +        }
   1.125 +        return true;
   1.126 +    }
   1.127 +
   1.128 +    bool codeUint16(uint16_t *n) {
   1.129 +        if (mode == XDR_ENCODE) {
   1.130 +            uint8_t *ptr = buf.write(sizeof *n);
   1.131 +            if (!ptr)
   1.132 +                return false;
   1.133 +            mozilla::LittleEndian::writeUint16(ptr, *n);
   1.134 +        } else {
   1.135 +            const uint8_t *ptr = buf.read(sizeof *n);
   1.136 +            *n = mozilla::LittleEndian::readUint16(ptr);
   1.137 +        }
   1.138 +        return true;
   1.139 +    }
   1.140 +
   1.141 +    bool codeUint32(uint32_t *n) {
   1.142 +        if (mode == XDR_ENCODE) {
   1.143 +            uint8_t *ptr = buf.write(sizeof *n);
   1.144 +            if (!ptr)
   1.145 +                return false;
   1.146 +            mozilla::LittleEndian::writeUint32(ptr, *n);
   1.147 +        } else {
   1.148 +            const uint8_t *ptr = buf.read(sizeof *n);
   1.149 +            *n = mozilla::LittleEndian::readUint32(ptr);
   1.150 +        }
   1.151 +        return true;
   1.152 +    }
   1.153 +
   1.154 +    bool codeUint64(uint64_t *n) {
   1.155 +        if (mode == XDR_ENCODE) {
   1.156 +            uint8_t *ptr = buf.write(sizeof(*n));
   1.157 +            if (!ptr)
   1.158 +                return false;
   1.159 +            mozilla::LittleEndian::writeUint64(ptr, *n);
   1.160 +        } else {
   1.161 +            const uint8_t *ptr = buf.read(sizeof(*n));
   1.162 +            *n = mozilla::LittleEndian::readUint64(ptr);
   1.163 +        }
   1.164 +        return true;
   1.165 +    }
   1.166 +
   1.167 +    /*
   1.168 +     * Use SFINAE to refuse any specialization which is not an enum.  Uses of
   1.169 +     * this function do not have to specialize the type of the enumerated field
   1.170 +     * as C++ will extract the parameterized from the argument list.
   1.171 +     */
   1.172 +    template <typename T>
   1.173 +    bool codeEnum32(T *val, typename mozilla::EnableIf<mozilla::IsEnum<T>::value, T>::Type * = NULL)
   1.174 +    {
   1.175 +        uint32_t tmp;
   1.176 +        if (mode == XDR_ENCODE)
   1.177 +            tmp = *val;
   1.178 +        if (!codeUint32(&tmp))
   1.179 +            return false;
   1.180 +        if (mode == XDR_DECODE)
   1.181 +            *val = T(tmp);
   1.182 +        return true;
   1.183 +    }
   1.184 +
   1.185 +    bool codeDouble(double *dp) {
   1.186 +        union DoublePun {
   1.187 +            double d;
   1.188 +            uint64_t u;
   1.189 +        } pun;
   1.190 +        if (mode == XDR_ENCODE)
   1.191 +            pun.d = *dp;
   1.192 +        if (!codeUint64(&pun.u))
   1.193 +            return false;
   1.194 +        if (mode == XDR_DECODE)
   1.195 +            *dp = pun.d;
   1.196 +        return true;
   1.197 +    }
   1.198 +
   1.199 +    bool codeBytes(void *bytes, size_t len) {
   1.200 +        if (mode == XDR_ENCODE) {
   1.201 +            uint8_t *ptr = buf.write(len);
   1.202 +            if (!ptr)
   1.203 +                return false;
   1.204 +            memcpy(ptr, bytes, len);
   1.205 +        } else {
   1.206 +            memcpy(bytes, buf.read(len), len);
   1.207 +        }
   1.208 +        return true;
   1.209 +    }
   1.210 +
   1.211 +    /*
   1.212 +     * During encoding the string is written into the buffer together with its
   1.213 +     * terminating '\0'. During decoding the method returns a pointer into the
   1.214 +     * decoding buffer and the caller must copy the string if it will outlive
   1.215 +     * the decoding buffer.
   1.216 +     */
   1.217 +    bool codeCString(const char **sp) {
   1.218 +        if (mode == XDR_ENCODE) {
   1.219 +            size_t n = strlen(*sp) + 1;
   1.220 +            uint8_t *ptr = buf.write(n);
   1.221 +            if (!ptr)
   1.222 +                return false;
   1.223 +            memcpy(ptr, *sp, n);
   1.224 +        } else {
   1.225 +            *sp = buf.readCString();
   1.226 +        }
   1.227 +        return true;
   1.228 +    }
   1.229 +
   1.230 +    bool codeChars(jschar *chars, size_t nchars);
   1.231 +
   1.232 +    bool codeFunction(JS::MutableHandleObject objp);
   1.233 +    bool codeScript(MutableHandleScript scriptp);
   1.234 +    bool codeConstValue(MutableHandleValue vp);
   1.235 +};
   1.236 +
   1.237 +class XDREncoder : public XDRState<XDR_ENCODE> {
   1.238 +  public:
   1.239 +    XDREncoder(JSContext *cx)
   1.240 +      : XDRState<XDR_ENCODE>(cx) {
   1.241 +    }
   1.242 +
   1.243 +    ~XDREncoder() {
   1.244 +        buf.freeBuffer();
   1.245 +    }
   1.246 +
   1.247 +    const void *getData(uint32_t *lengthp) const {
   1.248 +        return buf.getData(lengthp);
   1.249 +    }
   1.250 +
   1.251 +    void *forgetData(uint32_t *lengthp) {
   1.252 +        void *data = buf.getData(lengthp);
   1.253 +        buf.setData(nullptr, 0);
   1.254 +        return data;
   1.255 +    }
   1.256 +};
   1.257 +
   1.258 +class XDRDecoder : public XDRState<XDR_DECODE> {
   1.259 +  public:
   1.260 +    XDRDecoder(JSContext *cx, const void *data, uint32_t length,
   1.261 +               JSPrincipals *originPrincipals);
   1.262 +
   1.263 +};
   1.264 +
   1.265 +} /* namespace js */
   1.266 +
   1.267 +#endif /* vm_Xdr_h */

mercurial