Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / src / vm / Xdr.cpp
blob0bf2adcd33a38a4be93a7d1bcf59f0a3ce726d21
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "vm/Xdr.h"
9 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_ASSERT_IF
10 #include "mozilla/EndianUtils.h" // mozilla::NativeEndian, MOZ_LITTLE_ENDIAN
11 #include "mozilla/Result.h" // mozilla::{Result, Ok, Err}, MOZ_TRY
12 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
14 #include <algorithm> // std::transform
15 #include <stddef.h> // size_t
16 #include <stdint.h> // uint8_t, uint32_t, uintptr_t
17 #include <string> // std::char_traits
18 #include <type_traits> // std::is_same_v
19 #include <utility> // std::move
21 #include "frontend/FrontendContext.h" // FrontendContext
22 #include "js/Transcoding.h" // JS::TranscodeResult, JS::TranscodeBuffer, JS::TranscodeRange
23 #include "js/UniquePtr.h" // UniquePtr
24 #include "js/Utility.h" // JS::FreePolicy, js_delete
25 #include "vm/JSContext.h" // JSContext, ReportAllocationOverflow
26 #include "vm/StringType.h" // JSString
28 using namespace js;
30 using mozilla::Utf8Unit;
32 #ifdef DEBUG
33 bool XDRCoderBase::validateResultCode(FrontendContext* fc,
34 JS::TranscodeResult code) const {
35 return fc->hadErrors() == bool(code == JS::TranscodeResult::Throw);
37 #endif
39 template <XDRMode mode>
40 XDRResult XDRState<mode>::codeChars(char* chars, size_t nchars) {
41 return codeBytes(chars, nchars);
44 template <XDRMode mode>
45 XDRResult XDRState<mode>::codeChars(Latin1Char* chars, size_t nchars) {
46 static_assert(sizeof(Latin1Char) == 1,
47 "Latin1Char must be 1 byte for nchars below to be the "
48 "proper count of bytes");
49 static_assert(std::is_same_v<Latin1Char, unsigned char>,
50 "Latin1Char must be unsigned char to C++-safely reinterpret "
51 "the bytes generically copied below as Latin1Char");
52 return codeBytes(chars, nchars);
55 template <XDRMode mode>
56 XDRResult XDRState<mode>::codeChars(Utf8Unit* units, size_t count) {
57 if (count == 0) {
58 return Ok();
61 if (mode == XDR_ENCODE) {
62 uint8_t* ptr = buf->write(count);
63 if (!ptr) {
64 return fail(JS::TranscodeResult::Throw);
67 std::transform(units, units + count, ptr,
68 [](const Utf8Unit& unit) { return unit.toUint8(); });
69 } else {
70 const uint8_t* ptr = buf->read(count);
71 if (!ptr) {
72 return fail(JS::TranscodeResult::Failure_BadDecode);
75 std::transform(ptr, ptr + count, units,
76 [](const uint8_t& value) { return Utf8Unit(value); });
79 return Ok();
82 template <XDRMode mode>
83 XDRResult XDRState<mode>::codeChars(char16_t* chars, size_t nchars) {
84 if (nchars == 0) {
85 return Ok();
88 size_t nbytes = nchars * sizeof(char16_t);
89 if (mode == XDR_ENCODE) {
90 uint8_t* ptr = buf->write(nbytes);
91 if (!ptr) {
92 return fail(JS::TranscodeResult::Throw);
95 // |mozilla::NativeEndian| correctly handles writing into unaligned |ptr|.
96 mozilla::NativeEndian::copyAndSwapToLittleEndian(ptr, chars, nchars);
97 } else {
98 const uint8_t* ptr = buf->read(nbytes);
99 if (!ptr) {
100 return fail(JS::TranscodeResult::Failure_BadDecode);
103 // |mozilla::NativeEndian| correctly handles reading from unaligned |ptr|.
104 mozilla::NativeEndian::copyAndSwapFromLittleEndian(chars, ptr, nchars);
106 return Ok();
109 template <XDRMode mode, typename CharT>
110 static XDRResult XDRCodeCharsZ(XDRState<mode>* xdr,
111 XDRTranscodeString<CharT>& buffer) {
112 MOZ_ASSERT_IF(mode == XDR_ENCODE, !buffer.empty());
113 MOZ_ASSERT_IF(mode == XDR_DECODE, buffer.empty());
115 using OwnedString = js::UniquePtr<CharT[], JS::FreePolicy>;
116 OwnedString owned;
118 static_assert(JSString::MAX_LENGTH <= INT32_MAX,
119 "String length must fit in int32_t");
121 uint32_t length = 0;
122 CharT* chars = nullptr;
124 if (mode == XDR_ENCODE) {
125 chars = const_cast<CharT*>(buffer.template ref<const CharT*>());
127 // Set a reasonable limit on string length.
128 size_t lengthSizeT = std::char_traits<CharT>::length(chars);
129 if (lengthSizeT > JSString::MAX_LENGTH) {
130 ReportAllocationOverflow(xdr->fc());
131 return xdr->fail(JS::TranscodeResult::Throw);
133 length = static_cast<uint32_t>(lengthSizeT);
135 MOZ_TRY(xdr->codeUint32(&length));
137 if (mode == XDR_DECODE) {
138 owned =
139 xdr->fc()->getAllocator()->template make_pod_array<CharT>(length + 1);
140 if (!owned) {
141 return xdr->fail(JS::TranscodeResult::Throw);
143 chars = owned.get();
146 MOZ_TRY(xdr->codeChars(chars, length));
147 if (mode == XDR_DECODE) {
148 // Null-terminate and transfer ownership to caller.
149 owned[length] = '\0';
150 buffer.template construct<OwnedString>(std::move(owned));
153 return Ok();
156 template <XDRMode mode>
157 XDRResult XDRState<mode>::codeCharsZ(XDRTranscodeString<char>& buffer) {
158 return XDRCodeCharsZ(this, buffer);
161 template <XDRMode mode>
162 XDRResult XDRState<mode>::codeCharsZ(XDRTranscodeString<char16_t>& buffer) {
163 return XDRCodeCharsZ(this, buffer);
166 template class js::XDRState<XDR_ENCODE>;
167 template class js::XDRState<XDR_DECODE>;