chromium/chromium-74-2f28731.patch

325 lines
12 KiB
Diff

diff -up chromium-74.0.3729.169/base/values.cc.2f28731 chromium-74.0.3729.169/base/values.cc
--- chromium-74.0.3729.169/base/values.cc.2f28731 2019-05-31 15:03:32.200591044 -0400
+++ chromium-74.0.3729.169/base/values.cc 2019-05-31 15:13:39.546036829 -0400
@@ -12,6 +12,7 @@
#include <ostream>
#include <utility>
+#include "base/bit_cast.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
@@ -36,6 +37,9 @@ static_assert(std::is_standard_layout<Va
"base::Value should be a standard-layout C++ class in order "
"to avoid undefined behaviour in its implementation!");
+static_assert(sizeof(Value::DoubleStorage) == sizeof(double),
+ "The double and DoubleStorage types should have the same size");
+
namespace {
const char* const kTypeNames[] = {"null", "boolean", "integer", "double",
@@ -110,8 +114,6 @@ Value::Value(Value&& that) noexcept {
InternalMoveConstructFrom(std::move(that));
}
-Value::Value() noexcept : type_(Type::NONE) {}
-
Value::Value(Type type) : type_(type) {
// Initialize with the default value.
switch (type_) {
@@ -125,7 +127,7 @@ Value::Value(Type type) : type_(type) {
int_value_ = 0;
return;
case Type::DOUBLE:
- double_value_ = 0.0;
+ double_value_ = bit_cast<DoubleStorage>(0.0);
return;
case Type::STRING:
new (&string_value_) std::string();
@@ -149,21 +151,16 @@ Value::Value(Type type) : type_(type) {
CHECK(false);
}
-Value::Value(bool in_bool)
- : bool_type_(Type::BOOLEAN),
- bool_value_(in_bool) {}
-
-Value::Value(int in_int)
- : int_type_(Type::INTEGER),
- int_value_(in_int) {}
+Value::Value(bool in_bool) : type_(Type::BOOLEAN), bool_value_(in_bool) {}
+
+Value::Value(int in_int) : type_(Type::INTEGER), int_value_(in_int) {}
Value::Value(double in_double)
- : double_type_(Type::DOUBLE),
- double_value_(in_double) {
- if (!std::isfinite(double_value_)) {
+ : type_(Type::DOUBLE), double_value_(bit_cast<DoubleStorage>(in_double)) {
+ if (!std::isfinite(in_double)) {
NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) "
<< "values cannot be represented in JSON";
- double_value_ = 0.0;
+ double_value_ = bit_cast<DoubleStorage>(0.0);
}
}
@@ -172,8 +169,7 @@ Value::Value(const char* in_string) : Va
Value::Value(StringPiece in_string) : Value(std::string(in_string)) {}
Value::Value(std::string&& in_string) noexcept
- : string_type_(Type::STRING),
- string_value_(std::move(in_string)) {
+ : type_(Type::STRING), string_value_(std::move(in_string)) {
DCHECK(IsStringUTF8(string_value_));
}
@@ -182,19 +178,15 @@ Value::Value(const char16* in_string16)
Value::Value(StringPiece16 in_string16) : Value(UTF16ToUTF8(in_string16)) {}
Value::Value(const std::vector<char>& in_blob)
- : binary_type_(Type::BINARY),
- binary_value_(in_blob.begin(), in_blob.end()) {}
+ : type_(Type::BINARY), binary_value_(in_blob.begin(), in_blob.end()) {}
Value::Value(base::span<const uint8_t> in_blob)
- : binary_type_(Type::BINARY),
- binary_value_(in_blob.begin(), in_blob.end()) {}
+ : type_(Type::BINARY), binary_value_(in_blob.begin(), in_blob.end()) {}
Value::Value(BlobStorage&& in_blob) noexcept
- : binary_type_(Type::BINARY),
- binary_value_(std::move(in_blob)) {}
+ : type_(Type::BINARY), binary_value_(std::move(in_blob)) {}
-Value::Value(const DictStorage& in_dict)
- : dict_type_(Type::DICTIONARY), dict_() {
+Value::Value(const DictStorage& in_dict) : type_(Type::DICTIONARY), dict_() {
dict_.reserve(in_dict.size());
for (const auto& it : in_dict) {
dict_.try_emplace(dict_.end(), it.first,
@@ -203,18 +195,16 @@ Value::Value(const DictStorage& in_dict)
}
Value::Value(DictStorage&& in_dict) noexcept
- : dict_type_(Type::DICTIONARY),
- dict_(std::move(in_dict)) {}
+ : type_(Type::DICTIONARY), dict_(std::move(in_dict)) {}
-Value::Value(const ListStorage& in_list) : list_type_(Type::LIST), list_() {
+Value::Value(const ListStorage& in_list) : type_(Type::LIST), list_() {
list_.reserve(in_list.size());
for (const auto& val : in_list)
list_.emplace_back(val.Clone());
}
Value::Value(ListStorage&& in_list) noexcept
- : list_type_(Type::LIST),
- list_(std::move(in_list)) {}
+ : type_(Type::LIST), list_(std::move(in_list)) {}
Value& Value::operator=(Value&& that) noexcept {
InternalCleanup();
@@ -223,6 +213,10 @@ Value& Value::operator=(Value&& that) no
return *this;
}
+double Value::AsDoubleInternal() const {
+ return bit_cast<double>(double_value_);
+}
+
Value Value::Clone() const {
switch (type_) {
case Type::NONE:
@@ -232,7 +226,7 @@ Value Value::Clone() const {
case Type::INTEGER:
return Value(int_value_);
case Type::DOUBLE:
- return Value(double_value_);
+ return Value(AsDoubleInternal());
case Type::STRING:
return Value(string_value_);
case Type::BINARY:
@@ -277,7 +271,7 @@ int Value::GetInt() const {
double Value::GetDouble() const {
if (is_double())
- return double_value_;
+ return AsDoubleInternal();
if (is_int())
return int_value_;
CHECK(false);
@@ -342,9 +336,10 @@ base::Optional<double> Value::FindDouble
const Value* result = FindKey(key);
if (result) {
if (result->is_int())
- return base::make_optional(static_cast<double>(result->int_value_));
- if (result->is_double())
- return base::make_optional(result->double_value_);
+ return static_cast<double>(result->int_value_);
+ if (result->is_double()) {
+ return result->AsDoubleInternal();
+ }
}
return base::nullopt;
}
@@ -548,7 +543,7 @@ bool Value::GetAsInteger(int* out_value)
bool Value::GetAsDouble(double* out_value) const {
if (out_value && is_double()) {
- *out_value = double_value_;
+ *out_value = AsDoubleInternal();
return true;
}
if (out_value && is_int()) {
@@ -643,7 +638,7 @@ bool operator==(const Value& lhs, const
case Value::Type::INTEGER:
return lhs.int_value_ == rhs.int_value_;
case Value::Type::DOUBLE:
- return lhs.double_value_ == rhs.double_value_;
+ return lhs.AsDoubleInternal() == rhs.AsDoubleInternal();
case Value::Type::STRING:
return lhs.string_value_ == rhs.string_value_;
case Value::Type::BINARY:
@@ -688,7 +683,7 @@ bool operator<(const Value& lhs, const V
case Value::Type::INTEGER:
return lhs.int_value_ < rhs.int_value_;
case Value::Type::DOUBLE:
- return lhs.double_value_ < rhs.double_value_;
+ return lhs.AsDoubleInternal() < rhs.AsDoubleInternal();
case Value::Type::STRING:
return lhs.string_value_ < rhs.string_value_;
case Value::Type::BINARY:
diff -up chromium-74.0.3729.169/base/values.h.2f28731 chromium-74.0.3729.169/base/values.h
--- chromium-74.0.3729.169/base/values.h.2f28731 2019-05-31 15:13:48.418868163 -0400
+++ chromium-74.0.3729.169/base/values.h 2019-05-31 15:17:06.015112057 -0400
@@ -77,12 +77,13 @@ class Value;
// base::Value dict(base::Value::Type::DICTIONARY);
// dict.SetKey("mykey", base::Value(foo));
// return dict;
-// }
class BASE_EXPORT Value {
public:
using BlobStorage = std::vector<uint8_t>;
using DictStorage = flat_map<std::string, std::unique_ptr<Value>>;
using ListStorage = std::vector<Value>;
+ // See technical note below explaining why this is used.
+ using DoubleStorage = struct { alignas(4) char v[sizeof(double)]; };
enum class Type : unsigned char {
NONE = 0,
@@ -111,7 +112,10 @@ class BASE_EXPORT Value {
static std::unique_ptr<Value> ToUniquePtrValue(Value val);
Value(Value&& that) noexcept;
- Value() noexcept; // A null value.
+ Value() noexcept {} // A null value
+ // Fun fact: using '= default' above instead of '{}' does not work because
+ // the compiler complains that the default constructor was deleted since
+ // the inner union contains fields with non-default constructors.
// Value's copy constructor and copy assignment operator are deleted. Use this
// to obtain a deep copy explicitly.
@@ -379,82 +383,29 @@ class BASE_EXPORT Value {
size_t EstimateMemoryUsage() const;
protected:
- // Technical note:
- // The naive way to implement a tagged union leads to wasted bytes
- // in the object on CPUs like ARM ones, which impose an 8-byte alignment
- // for double values. I.e. if one does something like:
- //
- // struct TaggedValue {
- // int type_; // size = 1, align = 4
- // union {
- // bool bool_value_; // size = 1, align = 1
- // int int_value_; // size = 4, align = 4
- // double double_value_; // size = 8, align = 8
- // std::string string_value_; // size = 12, align = 4 (32-bit)
- // };
- // };
- //
- // The end result is that the union will have an alignment of 8, and a size
- // of 16, due to 4 extra padding bytes following |string_value_| to respect
- // the alignment requirement.
- //
- // As a consequence, the struct TaggedValue will have a size of 24 bytes,
- // due to the size of the union (16), the size of |type_| (4) and 4 bytes
- // of padding between |type_| and the union to respect its alignment.
- //
- // This means 8 bytes of unused memory per instance on 32-bit ARM!
- //
- // To reclaim these, a union of structs is used instead, in order to ensure
- // that |double_value_| below is always located at an offset that is a
- // multiple of 8, relative to the start of the overall data structure.
- //
- // Each struct must declare its own |type_| field, which must have a different
- // name, to appease the C++ compiler.
- //
- // Using this technique sizeof(base::Value) == 16 on 32-bit ARM instead
- // of 24, without losing any information. Results are unchanged for x86,
- // x86_64 and arm64 (16, 32 and 32 bytes respectively).
+ // Special case for doubles, which are aligned to 8 bytes on some
+ // 32-bit architectures. In this case, a simple declaration as a
+ // double member would make the whole union 8 byte-aligned, which
+ // would also force 4 bytes of wasted padding space before it in
+ // the Value layout.
+ //
+ // To override this, store the value as an array of 32-bit integers, and
+ // perform the appropriate bit casts when reading / writing to it.
+ Type type_ = Type::NONE;
+
union {
- struct {
- // TODO(crbug.com/646113): Make these private once DictionaryValue and
- // ListValue are properly inlined.
- Type type_ : 8;
- };
- struct {
- Type bool_type_ : 8;
- bool bool_value_;
- };
- struct {
- Type int_type_ : 8;
- int int_value_;
- };
- struct {
- Type double_type_ : 8;
- // Subtle: On architectures that require it, the compiler will ensure
- // that |double_value_|'s offset is a multiple of 8 (e.g. 32-bit ARM).
- // See technical note above to understand why it is important.
- double double_value_;
- };
- struct {
- Type string_type_ : 8;
- std::string string_value_;
- };
- struct {
- Type binary_type_ : 8;
- BlobStorage binary_value_;
- };
- struct {
- Type dict_type_ : 8;
- DictStorage dict_;
- };
- struct {
- Type list_type_ : 8;
- ListStorage list_;
- };
+ bool bool_value_;
+ int int_value_;
+ DoubleStorage double_value_;
+ std::string string_value_;
+ BlobStorage binary_value_;
+ DictStorage dict_;
+ ListStorage list_;
};
private:
friend class ValuesTest_SizeOfValue_Test;
+ double AsDoubleInternal() const;
void InternalMoveConstructFrom(Value&& that);
void InternalCleanup();