Import cobalt 25.master.0.1034729
diff --git a/base/json/OWNERS b/base/json/OWNERS
index e44d995..3e509a9 100644
--- a/base/json/OWNERS
+++ b/base/json/OWNERS
@@ -1 +1,3 @@
 file://base/SECURITY_OWNERS
+
+per-file values_util*=alancutter@chromium.org,jdoerrie@chromium.org
diff --git a/base/json/json_common.h b/base/json/json_common.h
new file mode 100644
index 0000000..3eb3a79
--- /dev/null
+++ b/base/json/json_common.h
@@ -0,0 +1,44 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_JSON_JSON_COMMON_H_
+#define BASE_JSON_JSON_COMMON_H_
+
+#include <stddef.h>
+
+#include "base/check_op.h"
+#include "base/memory/raw_ptr.h"
+
+namespace base {
+namespace internal {
+
+// Chosen to support 99.9% of documents found in the wild late 2016.
+// http://crbug.com/673263
+const size_t kAbsoluteMaxDepth = 200;
+
+// Simple class that checks for maximum recursion/stack overflow.
+class StackMarker {
+ public:
+  StackMarker(size_t max_depth, size_t* depth)
+      : max_depth_(max_depth), depth_(depth) {
+    ++(*depth_);
+    DCHECK_LE(*depth_, max_depth_);
+  }
+
+  StackMarker(const StackMarker&) = delete;
+  StackMarker& operator=(const StackMarker&) = delete;
+
+  ~StackMarker() { --(*depth_); }
+
+  bool IsTooDeep() const { return *depth_ >= max_depth_; }
+
+ private:
+  const size_t max_depth_;
+  const raw_ptr<size_t> depth_;
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_COMMON_H_
diff --git a/base/json/json_correctness_fuzzer.cc b/base/json/json_correctness_fuzzer.cc
index c7d6d6f..eb76ead 100644
--- a/base/json/json_correctness_fuzzer.cc
+++ b/base/json/json_correctness_fuzzer.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,6 +6,9 @@
 // The fuzzer input is passed through parsing twice,
 // so that presumably valid json is parsed/written again.
 
+#include <stddef.h>
+#include <stdint.h>
+
 #include <string>
 
 #include "base/json/json_reader.h"
@@ -13,8 +16,6 @@
 #include "base/json/string_escape.h"
 #include "base/logging.h"
 #include "base/values.h"
-#include "starboard/memory.h"
-#include "starboard/types.h"
 
 // Entry point for libFuzzer.
 // We will use the last byte of data as parsing options.
@@ -23,9 +24,6 @@
   if (size < 2)
     return 0;
 
-  int error_code, error_line, error_column;
-  std::string error_message;
-
   // Create a copy of input buffer, as otherwise we don't catch
   // overflow that touches the last byte (which is used in options).
   std::unique_ptr<char[]> input(new char[size - 1]);
@@ -34,23 +32,20 @@
   base::StringPiece input_string(input.get(), size - 1);
 
   const int options = data[size - 1];
-  auto parsed_value = base::JSONReader::ReadAndReturnError(
-      input_string, options, &error_code, &error_message, &error_line,
-      &error_column);
-  if (!parsed_value)
+  auto result =
+      base::JSONReader::ReadAndReturnValueWithError(input_string, options);
+  if (!result.has_value())
     return 0;
 
   std::string parsed_output;
-  bool b = base::JSONWriter::Write(*parsed_value, &parsed_output);
+  bool b = base::JSONWriter::Write(*result, &parsed_output);
   LOG_ASSERT(b);
 
-  auto double_parsed_value = base::JSONReader::ReadAndReturnError(
-      parsed_output, options, &error_code, &error_message, &error_line,
-      &error_column);
-  LOG_ASSERT(double_parsed_value);
+  auto double_result =
+      base::JSONReader::ReadAndReturnValueWithError(parsed_output, options);
+  LOG_ASSERT(double_result.has_value());
   std::string double_parsed_output;
-  bool b2 =
-      base::JSONWriter::Write(*double_parsed_value, &double_parsed_output);
+  bool b2 = base::JSONWriter::Write(*double_result, &double_parsed_output);
   LOG_ASSERT(b2);
 
   LOG_ASSERT(parsed_output == double_parsed_output)
diff --git a/base/json/json_file_value_serializer.cc b/base/json/json_file_value_serializer.cc
index 6ec275c..d7d72c0 100644
--- a/base/json/json_file_value_serializer.cc
+++ b/base/json/json_file_value_serializer.cc
@@ -1,12 +1,13 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/json_file_value_serializer.h"
 
+#include "base/check.h"
 #include "base/files/file_util.h"
 #include "base/json/json_string_value_serializer.h"
-#include "base/logging.h"
+#include "base/notreached.h"
 #include "build/build_config.h"
 
 using base::FilePath;
@@ -23,46 +24,42 @@
 
 JSONFileValueSerializer::~JSONFileValueSerializer() = default;
 
-bool JSONFileValueSerializer::Serialize(const base::Value& root) {
+bool JSONFileValueSerializer::Serialize(base::ValueView root) {
   return SerializeInternal(root, false);
 }
 
 bool JSONFileValueSerializer::SerializeAndOmitBinaryValues(
-    const base::Value& root) {
+    base::ValueView root) {
   return SerializeInternal(root, true);
 }
 
-bool JSONFileValueSerializer::SerializeInternal(const base::Value& root,
+bool JSONFileValueSerializer::SerializeInternal(base::ValueView root,
                                                 bool omit_binary_values) {
   std::string json_string;
   JSONStringValueSerializer serializer(&json_string);
   serializer.set_pretty_print(true);
-  bool result = omit_binary_values ?
-      serializer.SerializeAndOmitBinaryValues(root) :
-      serializer.Serialize(root);
+  bool result = omit_binary_values
+                    ? serializer.SerializeAndOmitBinaryValues(root)
+                    : serializer.Serialize(root);
   if (!result)
     return false;
 
-  int data_size = static_cast<int>(json_string.size());
-  if (base::WriteFile(json_file_path_, json_string.data(), data_size) !=
-      data_size)
-    return false;
-
-  return true;
+  return base::WriteFile(json_file_path_, json_string);
 }
 
 JSONFileValueDeserializer::JSONFileValueDeserializer(
     const base::FilePath& json_file_path,
     int options)
-    : json_file_path_(json_file_path), options_(options), last_read_size_(0U) {}
+    : json_file_path_(json_file_path), options_(options) {}
 
 JSONFileValueDeserializer::~JSONFileValueDeserializer() = default;
 
 int JSONFileValueDeserializer::ReadFileToString(std::string* json_string) {
   DCHECK(json_string);
+  last_read_size_ = 0u;
   if (!base::ReadFileToString(json_file_path_, json_string)) {
-#if defined(OS_WIN)
-    int error = ::GetLastError();
+#if BUILDFLAG(IS_WIN)
+    DWORD error = ::GetLastError();
     if (error == ERROR_SHARING_VIOLATION || error == ERROR_LOCK_VIOLATION) {
       return JSON_FILE_LOCKED;
     } else if (error == ERROR_ACCESS_DENIED) {
diff --git a/base/json/json_file_value_serializer.h b/base/json/json_file_value_serializer.h
index 6a726d6..16ceff5 100644
--- a/base/json/json_file_value_serializer.h
+++ b/base/json/json_file_value_serializer.h
@@ -1,72 +1,90 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
 #define BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
 
+#include <stddef.h>
+
+#include <memory>
 #include <string>
 
 #include "base/base_export.h"
 #include "base/files/file_path.h"
-#include "base/macros.h"
+#include "base/json/json_reader.h"
 #include "base/values.h"
-#include "starboard/types.h"
 
 class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
  public:
+  JSONFileValueSerializer() = delete;
+
   // |json_file_path_| is the path of a file that will be destination of the
   // serialization. The serializer will attempt to create the file at the
   // specified location.
   explicit JSONFileValueSerializer(const base::FilePath& json_file_path);
 
+  JSONFileValueSerializer(const JSONFileValueSerializer&) = delete;
+  JSONFileValueSerializer& operator=(const JSONFileValueSerializer&) = delete;
+
   ~JSONFileValueSerializer() override;
 
   // DO NOT USE except in unit tests to verify the file was written properly.
   // We should never serialize directly to a file since this will block the
   // thread. Instead, serialize to a string and write to the file you want on
-  // the file thread.
+  // the thread pool.
   //
   // Attempt to serialize the data structure represented by Value into
   // JSON.  If the return value is true, the result will have been written
   // into the file whose name was passed into the constructor.
-  bool Serialize(const base::Value& root) override;
+  bool Serialize(base::ValueView root) override;
 
   // Equivalent to Serialize(root) except binary values are omitted from the
   // output.
-  bool SerializeAndOmitBinaryValues(const base::Value& root);
+  bool SerializeAndOmitBinaryValues(base::ValueView root);
 
  private:
-  bool SerializeInternal(const base::Value& root, bool omit_binary_values);
+  bool SerializeInternal(base::ValueView root, bool omit_binary_values);
 
   const base::FilePath json_file_path_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer);
 };
 
 class BASE_EXPORT JSONFileValueDeserializer : public base::ValueDeserializer {
  public:
+  JSONFileValueDeserializer() = delete;
+
   // |json_file_path_| is the path of a file that will be source of the
   // deserialization. |options| is a bitmask of JSONParserOptions.
-  explicit JSONFileValueDeserializer(const base::FilePath& json_file_path,
-                                     int options = 0);
+  explicit JSONFileValueDeserializer(
+      const base::FilePath& json_file_path,
+      int options = base::JSON_PARSE_CHROMIUM_EXTENSIONS);
+
+  JSONFileValueDeserializer(const JSONFileValueDeserializer&) = delete;
+  JSONFileValueDeserializer& operator=(const JSONFileValueDeserializer&) =
+      delete;
 
   ~JSONFileValueDeserializer() override;
 
-  // Attempt to deserialize the data structure encoded in the file passed
-  // in to the constructor into a structure of Value objects.  If the return
-  // value is NULL, and if |error_code| is non-null, |error_code| will
-  // contain an integer error code (either JsonFileError or JsonParseError).
-  // If |error_message| is non-null, it will be filled in with a formatted
-  // error message including the location of the error if appropriate.
+  // Attempts to deserialize the data structure encoded in the file passed to
+  // the constructor into a structure of Value objects. If the return value is
+  // null, then
+  // (1) |error_code| will be filled with an integer error code (either a
+  //     JsonFileError or base::ValueDeserializer::kErrorCodeInvalidFormat) if a
+  //     non-null |error_code| was given.
+  // (2) |error_message| will be filled with a formatted error message,
+  //     including the location of the error (if appropriate), if a non-null
+  //     |error_message| was given.
   // The caller takes ownership of the returned value.
   std::unique_ptr<base::Value> Deserialize(int* error_code,
                                            std::string* error_message) override;
 
-  // This enum is designed to safely overlap with JSONReader::JsonParseError.
+  // This enum is designed to safely overlap with JSONParser::JsonParseError.
+  //
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
   enum JsonFileError {
     JSON_NO_ERROR = 0,
-    JSON_ACCESS_DENIED = 1000,
+    JSON_ACCESS_DENIED = kErrorCodeFirstMetadataError,
     JSON_CANNOT_READ_FILE,
     JSON_FILE_LOCKED,
     JSON_NO_SUCH_FILE
@@ -93,9 +111,7 @@
 
   const base::FilePath json_file_path_;
   const int options_;
-  size_t last_read_size_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueDeserializer);
+  size_t last_read_size_ = 0u;
 };
 
 #endif  // BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc
index 057f769..fbb226e 100644
--- a/base/json/json_parser.cc
+++ b/base/json/json_parser.cc
@@ -1,16 +1,20 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/json_parser.h"
 
 #include <cmath>
+#include <iterator>
 #include <utility>
 #include <vector>
 
-#include "base/logging.h"
-#include "base/macros.h"
+#include "base/check_op.h"
+#include "base/json/json_reader.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
@@ -18,101 +22,156 @@
 #include "base/strings/utf_string_conversion_utils.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/third_party/icu/icu_utf.h"
-#include "base/values.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 namespace internal {
 
 namespace {
 
+// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError.
+static_assert(JSONParser::JSON_PARSE_ERROR_COUNT < 1000,
+              "JSONParser error out of bounds");
+
+std::string ErrorCodeToString(JSONParser::JsonParseError error_code) {
+  switch (error_code) {
+    case JSONParser::JSON_NO_ERROR:
+      return std::string();
+    case JSONParser::JSON_SYNTAX_ERROR:
+      return JSONParser::kSyntaxError;
+    case JSONParser::JSON_INVALID_ESCAPE:
+      return JSONParser::kInvalidEscape;
+    case JSONParser::JSON_UNEXPECTED_TOKEN:
+      return JSONParser::kUnexpectedToken;
+    case JSONParser::JSON_TRAILING_COMMA:
+      return JSONParser::kTrailingComma;
+    case JSONParser::JSON_TOO_MUCH_NESTING:
+      return JSONParser::kTooMuchNesting;
+    case JSONParser::JSON_UNEXPECTED_DATA_AFTER_ROOT:
+      return JSONParser::kUnexpectedDataAfterRoot;
+    case JSONParser::JSON_UNSUPPORTED_ENCODING:
+      return JSONParser::kUnsupportedEncoding;
+    case JSONParser::JSON_UNQUOTED_DICTIONARY_KEY:
+      return JSONParser::kUnquotedDictionaryKey;
+    case JSONParser::JSON_UNREPRESENTABLE_NUMBER:
+      return JSONParser::kUnrepresentableNumber;
+    case JSONParser::JSON_PARSE_ERROR_COUNT:
+      break;
+  }
+  NOTREACHED();
+  return std::string();
+}
+
 const int32_t kExtendedASCIIStart = 0x80;
+constexpr base_icu::UChar32 kUnicodeReplacementPoint = 0xFFFD;
 
-// Simple class that checks for maximum recursion/"stack overflow."
-class StackMarker {
- public:
-  StackMarker(int max_depth, int* depth)
-      : max_depth_(max_depth), depth_(depth) {
-    ++(*depth_);
-    DCHECK_LE(*depth_, max_depth_);
+// UnprefixedHexStringToInt acts like |HexStringToInt|, but enforces that the
+// input consists purely of hex digits. I.e. no "0x" nor "OX" prefix is
+// permitted.
+bool UnprefixedHexStringToInt(StringPiece input, int* output) {
+  for (size_t i = 0; i < input.size(); i++) {
+    if (!IsHexDigit(input[i])) {
+      return false;
+    }
   }
-  ~StackMarker() {
-    --(*depth_);
-  }
+  return HexStringToInt(input, output);
+}
 
-  bool IsTooDeep() const { return *depth_ >= max_depth_; }
-
- private:
-  const int max_depth_;
-  int* const depth_;
-
-  DISALLOW_COPY_AND_ASSIGN(StackMarker);
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class ChromiumJsonExtension {
+  kCComment,
+  kCppComment,
+  kXEscape,
+  kVerticalTabEscape,
+  kControlCharacter,
+  kMaxValue = kControlCharacter,
 };
 
-constexpr uint32_t kUnicodeReplacementPoint = 0xFFFD;
+const char kExtensionHistogramName[] =
+    "Security.JSONParser.ChromiumExtensionUsage";
 
 }  // namespace
 
 // This is U+FFFD.
 const char kUnicodeReplacementString[] = "\xEF\xBF\xBD";
 
-JSONParser::JSONParser(int options, int max_depth)
+const char JSONParser::kSyntaxError[] = "Syntax error.";
+const char JSONParser::kInvalidEscape[] = "Invalid escape sequence.";
+const char JSONParser::kUnexpectedToken[] = "Unexpected token.";
+const char JSONParser::kTrailingComma[] = "Trailing comma not allowed.";
+const char JSONParser::kTooMuchNesting[] = "Too much nesting.";
+const char JSONParser::kUnexpectedDataAfterRoot[] =
+    "Unexpected data after root element.";
+const char JSONParser::kUnsupportedEncoding[] =
+    "Unsupported encoding. JSON must be UTF-8.";
+const char JSONParser::kUnquotedDictionaryKey[] =
+    "Dictionary keys must be quoted.";
+const char JSONParser::kUnrepresentableNumber[] =
+    "Number cannot be represented.";
+
+JSONParser::JSONParser(int options, size_t max_depth)
     : options_(options),
       max_depth_(max_depth),
       index_(0),
       stack_depth_(0),
       line_number_(0),
       index_last_line_(0),
-      error_code_(JSONReader::JSON_NO_ERROR),
+      error_code_(JSON_NO_ERROR),
       error_line_(0),
       error_column_(0) {
-  CHECK_LE(max_depth, JSONReader::kStackMaxDepth);
+  CHECK_LE(max_depth, kAbsoluteMaxDepth);
 }
 
 JSONParser::~JSONParser() = default;
 
-Optional<Value> JSONParser::Parse(StringPiece input) {
+absl::optional<Value> JSONParser::Parse(StringPiece input) {
   input_ = input;
   index_ = 0;
+  // Line and column counting is 1-based, but |index_| is 0-based. For example,
+  // if input is "Aaa\nB" then 'A' and 'B' are both in column 1 (at lines 1 and
+  // 2) and have indexes of 0 and 4. We track the line number explicitly (the
+  // |line_number_| field) and the column number implicitly (the difference
+  // between |index_| and |index_last_line_|). In calculating that difference,
+  // |index_last_line_| is the index of the '\r' or '\n', not the index of the
+  // first byte after the '\n'. For the 'B' in "Aaa\nB", its |index_| and
+  // |index_last_line_| would be 4 and 3: 'B' is in column (4 - 3) = 1. We
+  // initialize |index_last_line_| to -1, not 0, since -1 is the (out of range)
+  // index of the imaginary '\n' immediately before the start of the string:
+  // 'A' is in column (0 - -1) = 1.
   line_number_ = 1;
-  index_last_line_ = 0;
+  index_last_line_ = static_cast<size_t>(-1);
 
-  error_code_ = JSONReader::JSON_NO_ERROR;
+  error_code_ = JSON_NO_ERROR;
   error_line_ = 0;
   error_column_ = 0;
 
-  // ICU and ReadUnicodeCharacter() use int32_t for lengths, so ensure
-  // that the index_ will not overflow when parsing.
-  if (!base::IsValueInRangeForNumericType<int32_t>(input.length())) {
-    ReportError(JSONReader::JSON_TOO_LARGE, 0);
-    return nullopt;
-  }
-
   // When the input JSON string starts with a UTF-8 Byte-Order-Mark,
   // advance the start position to avoid the ParseNextToken function mis-
   // treating a Unicode BOM as an invalid character and returning NULL.
   ConsumeIfMatch("\xEF\xBB\xBF");
 
   // Parse the first and any nested tokens.
-  Optional<Value> root(ParseNextToken());
+  absl::optional<Value> root(ParseNextToken());
   if (!root)
-    return nullopt;
+    return absl::nullopt;
 
   // Make sure the input stream is at an end.
   if (GetNextToken() != T_END_OF_INPUT) {
-    ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 1);
-    return nullopt;
+    ReportError(JSON_UNEXPECTED_DATA_AFTER_ROOT, 0);
+    return absl::nullopt;
   }
 
   return root;
 }
 
-JSONReader::JsonParseError JSONParser::error_code() const {
+JSONParser::JsonParseError JSONParser::error_code() const {
   return error_code_;
 }
 
 std::string JSONParser::GetErrorMessage() const {
   return FormatErrorMessage(error_line_, error_column_,
-      JSONReader::ErrorCodeToString(error_code_));
+                            ErrorCodeToString(error_code_));
 }
 
 int JSONParser::error_line() const {
@@ -135,12 +194,16 @@
 JSONParser::StringBuilder& JSONParser::StringBuilder::operator=(
     StringBuilder&& other) = default;
 
-void JSONParser::StringBuilder::Append(uint32_t point) {
-  DCHECK(IsValidCharacter(point));
+void JSONParser::StringBuilder::Append(base_icu::UChar32 point) {
+  DCHECK(IsValidCodepoint(point));
 
-  if (point < kExtendedASCIIStart && !string_) {
-    DCHECK_EQ(static_cast<char>(point), pos_[length_]);
-    ++length_;
+  if (point < kExtendedASCIIStart) {
+    if (!string_) {
+      DCHECK_EQ(static_cast<char>(point), pos_[length_]);
+      ++length_;
+    } else {
+      string_->push_back(static_cast<char>(point));
+    }
   } else {
     Convert();
     if (UNLIKELY(point == kUnicodeReplacementPoint)) {
@@ -165,44 +228,44 @@
 
 // JSONParser private //////////////////////////////////////////////////////////
 
-Optional<StringPiece> JSONParser::PeekChars(int count) {
-  if (static_cast<size_t>(index_) + count > input_.length())
-    return nullopt;
+absl::optional<StringPiece> JSONParser::PeekChars(size_t count) {
+  if (index_ + count > input_.length())
+    return absl::nullopt;
   // Using StringPiece::substr() is significantly slower (according to
   // base_perftests) than constructing a substring manually.
   return StringPiece(input_.data() + index_, count);
 }
 
-Optional<char> JSONParser::PeekChar() {
-  Optional<StringPiece> chars = PeekChars(1);
+absl::optional<char> JSONParser::PeekChar() {
+  absl::optional<StringPiece> chars = PeekChars(1);
   if (chars)
     return (*chars)[0];
-  return nullopt;
+  return absl::nullopt;
 }
 
-Optional<StringPiece> JSONParser::ConsumeChars(int count) {
-  Optional<StringPiece> chars = PeekChars(count);
+absl::optional<StringPiece> JSONParser::ConsumeChars(size_t count) {
+  absl::optional<StringPiece> chars = PeekChars(count);
   if (chars)
     index_ += count;
   return chars;
 }
 
-Optional<char> JSONParser::ConsumeChar() {
-  Optional<StringPiece> chars = ConsumeChars(1);
+absl::optional<char> JSONParser::ConsumeChar() {
+  absl::optional<StringPiece> chars = ConsumeChars(1);
   if (chars)
     return (*chars)[0];
-  return nullopt;
+  return absl::nullopt;
 }
 
 const char* JSONParser::pos() {
-  CHECK_LE(static_cast<size_t>(index_), input_.length());
+  CHECK_LE(index_, input_.length());
   return input_.data() + index_;
 }
 
 JSONParser::Token JSONParser::GetNextToken() {
   EatWhitespaceAndComments();
 
-  Optional<char> c = PeekChar();
+  absl::optional<char> c = PeekChar();
   if (!c)
     return T_END_OF_INPUT;
 
@@ -245,7 +308,7 @@
 }
 
 void JSONParser::EatWhitespaceAndComments() {
-  while (Optional<char> c = PeekChar()) {
+  while (absl::optional<char> c = PeekChar()) {
     switch (*c) {
       case '\r':
       case '\n':
@@ -254,7 +317,7 @@
         if (!(c == '\n' && index_ > 0 && input_[index_ - 1] == '\r')) {
           ++line_number_;
         }
-        FALLTHROUGH;
+        [[fallthrough]];
       case ' ':
       case '\t':
         ConsumeChar();
@@ -270,21 +333,39 @@
 }
 
 bool JSONParser::EatComment() {
-  Optional<StringPiece> comment_start = ConsumeChars(2);
+  absl::optional<StringPiece> comment_start = PeekChars(2);
   if (!comment_start)
     return false;
 
+  const bool comments_allowed = options_ & JSON_ALLOW_COMMENTS;
+
   if (comment_start == "//") {
+    UmaHistogramEnumeration(kExtensionHistogramName,
+                            ChromiumJsonExtension::kCppComment);
+    if (!comments_allowed) {
+      ReportError(JSON_UNEXPECTED_TOKEN, 0);
+      return false;
+    }
+
+    ConsumeChars(2);
     // Single line comment, read to newline.
-    while (Optional<char> c = PeekChar()) {
+    while (absl::optional<char> c = PeekChar()) {
       if (c == '\n' || c == '\r')
         return true;
       ConsumeChar();
     }
   } else if (comment_start == "/*") {
+    UmaHistogramEnumeration(kExtensionHistogramName,
+                            ChromiumJsonExtension::kCComment);
+    if (!comments_allowed) {
+      ReportError(JSON_UNEXPECTED_TOKEN, 0);
+      return false;
+    }
+
+    ConsumeChars(2);
     char previous_char = '\0';
     // Block comment, read until end marker.
-    while (Optional<char> c = PeekChar()) {
+    while (absl::optional<char> c = PeekChar()) {
       if (previous_char == '*' && c == '/') {
         // EatWhitespaceAndComments will inspect pos(), which will still be on
         // the last / of the comment, so advance once more (which may also be
@@ -301,11 +382,11 @@
   return false;
 }
 
-Optional<Value> JSONParser::ParseNextToken() {
+absl::optional<Value> JSONParser::ParseNextToken() {
   return ParseToken(GetNextToken());
 }
 
-Optional<Value> JSONParser::ParseToken(Token token) {
+absl::optional<Value> JSONParser::ParseToken(Token token) {
   switch (token) {
     case T_OBJECT_BEGIN:
       return ConsumeDictionary();
@@ -320,129 +401,130 @@
     case T_NULL:
       return ConsumeLiteral();
     default:
-      ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
-      return nullopt;
+      ReportError(JSON_UNEXPECTED_TOKEN, 0);
+      return absl::nullopt;
   }
 }
 
-Optional<Value> JSONParser::ConsumeDictionary() {
+absl::optional<Value> JSONParser::ConsumeDictionary() {
   if (ConsumeChar() != '{') {
-    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
-    return nullopt;
+    ReportError(JSON_UNEXPECTED_TOKEN, 0);
+    return absl::nullopt;
   }
 
   StackMarker depth_check(max_depth_, &stack_depth_);
   if (depth_check.IsTooDeep()) {
-    ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 0);
-    return nullopt;
+    ReportError(JSON_TOO_MUCH_NESTING, -1);
+    return absl::nullopt;
   }
 
-  std::vector<Value::DictStorage::value_type> dict_storage;
+  std::vector<std::pair<std::string, Value>> values;
 
   Token token = GetNextToken();
   while (token != T_OBJECT_END) {
     if (token != T_STRING) {
-      ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 1);
-      return nullopt;
+      ReportError(JSON_UNQUOTED_DICTIONARY_KEY, 0);
+      return absl::nullopt;
     }
 
     // First consume the key.
     StringBuilder key;
     if (!ConsumeStringRaw(&key)) {
-      return nullopt;
+      return absl::nullopt;
     }
 
     // Read the separator.
     token = GetNextToken();
     if (token != T_OBJECT_PAIR_SEPARATOR) {
-      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
-      return nullopt;
+      ReportError(JSON_SYNTAX_ERROR, 0);
+      return absl::nullopt;
     }
 
     // The next token is the value. Ownership transfers to |dict|.
     ConsumeChar();
-    Optional<Value> value = ParseNextToken();
+    absl::optional<Value> value = ParseNextToken();
     if (!value) {
       // ReportError from deeper level.
-      return nullopt;
+      return absl::nullopt;
     }
 
-    dict_storage.emplace_back(key.DestructiveAsString(),
-                              std::make_unique<Value>(std::move(*value)));
+    values.emplace_back(key.DestructiveAsString(), std::move(*value));
 
     token = GetNextToken();
     if (token == T_LIST_SEPARATOR) {
       ConsumeChar();
       token = GetNextToken();
       if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) {
-        ReportError(JSONReader::JSON_TRAILING_COMMA, 1);
-        return nullopt;
+        ReportError(JSON_TRAILING_COMMA, 0);
+        return absl::nullopt;
       }
     } else if (token != T_OBJECT_END) {
-      ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
-      return nullopt;
+      ReportError(JSON_SYNTAX_ERROR, 0);
+      return absl::nullopt;
     }
   }
 
   ConsumeChar();  // Closing '}'.
-
-  return Value(Value::DictStorage(std::move(dict_storage), KEEP_LAST_OF_DUPES));
+  // Reverse |dict_storage| to keep the last of elements with the same key in
+  // the input.
+  ranges::reverse(values);
+  return Value(Value::Dict(std::make_move_iterator(values.begin()),
+                           std::make_move_iterator(values.end())));
 }
 
-Optional<Value> JSONParser::ConsumeList() {
+absl::optional<Value> JSONParser::ConsumeList() {
   if (ConsumeChar() != '[') {
-    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
-    return nullopt;
+    ReportError(JSON_UNEXPECTED_TOKEN, 0);
+    return absl::nullopt;
   }
 
   StackMarker depth_check(max_depth_, &stack_depth_);
   if (depth_check.IsTooDeep()) {
-    ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 0);
-    return nullopt;
+    ReportError(JSON_TOO_MUCH_NESTING, -1);
+    return absl::nullopt;
   }
 
-  Value::ListStorage list_storage;
+  Value::List list;
 
   Token token = GetNextToken();
   while (token != T_ARRAY_END) {
-    Optional<Value> item = ParseToken(token);
+    absl::optional<Value> item = ParseToken(token);
     if (!item) {
       // ReportError from deeper level.
-      return nullopt;
+      return absl::nullopt;
     }
 
-    list_storage.push_back(std::move(*item));
+    list.Append(std::move(*item));
 
     token = GetNextToken();
     if (token == T_LIST_SEPARATOR) {
       ConsumeChar();
       token = GetNextToken();
       if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) {
-        ReportError(JSONReader::JSON_TRAILING_COMMA, 1);
-        return nullopt;
+        ReportError(JSON_TRAILING_COMMA, 0);
+        return absl::nullopt;
       }
     } else if (token != T_ARRAY_END) {
-      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
-      return nullopt;
+      ReportError(JSON_SYNTAX_ERROR, 0);
+      return absl::nullopt;
     }
   }
 
   ConsumeChar();  // Closing ']'.
 
-  return Value(std::move(list_storage));
+  return Value(std::move(list));
 }
 
-Optional<Value> JSONParser::ConsumeString() {
+absl::optional<Value> JSONParser::ConsumeString() {
   StringBuilder string;
   if (!ConsumeStringRaw(&string))
-    return nullopt;
-
+    return absl::nullopt;
   return Value(string.DestructiveAsString());
 }
 
 bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
   if (ConsumeChar() != '"') {
-    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    ReportError(JSON_UNEXPECTED_TOKEN, 0);
     return false;
   }
 
@@ -451,15 +533,16 @@
   // std::string.
   StringBuilder string(pos());
 
-  while (PeekChar()) {
-    uint32_t next_char = 0;
-    if (!ReadUnicodeCharacter(input_.data(),
-                              static_cast<int32_t>(input_.length()),
-                              &index_,
-                              &next_char) ||
-        !IsValidCharacter(next_char)) {
+  while (absl::optional<char> c = PeekChar()) {
+    base_icu::UChar32 next_char = 0;
+    if (static_cast<unsigned char>(*c) < kExtendedASCIIStart) {
+      // Fast path for ASCII.
+      next_char = *c;
+    } else if (!ReadUnicodeCharacter(input_.data(), input_.length(), &index_,
+                                     &next_char) ||
+               !IsValidCodepoint(next_char)) {
       if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) {
-        ReportError(JSONReader::JSON_UNSUPPORTED_ENCODING, 1);
+        ReportError(JSON_UNSUPPORTED_ENCODING, 0);
         return false;
       }
       ConsumeChar();
@@ -473,7 +556,32 @@
       return true;
     }
     if (next_char != '\\') {
-      // If this character is not an escape sequence...
+      // Per Section 7, "All Unicode characters may be placed within the
+      // quotation marks, except for the characters that MUST be escaped:
+      // quotation mark, reverse solidus, and the control characters (U+0000
+      // through U+001F)".
+      if (next_char <= 0x1F) {
+        UmaHistogramEnumeration(kExtensionHistogramName,
+                                ChromiumJsonExtension::kControlCharacter);
+        if (!(options_ & JSON_ALLOW_CONTROL_CHARS)) {
+          ReportError(JSON_UNSUPPORTED_ENCODING, -1);
+          return false;
+        }
+      }
+
+      // If this character is not an escape sequence, track any line breaks and
+      // copy next_char to the StringBuilder. The JSON spec forbids unescaped
+      // ASCII control characters within a string, including '\r' and '\n', but
+      // this implementation is more lenient.
+      if ((next_char == '\r') || (next_char == '\n')) {
+        index_last_line_ = index_;
+        // Don't increment line_number_ twice for "\r\n". We are guaranteed
+        // that (index_ > 0) because we are consuming a string, so we must have
+        // seen an opening '"' quote character.
+        if ((next_char == '\r') || (input_[index_ - 1] != '\r')) {
+          ++line_number_;
+        }
+      }
       ConsumeChar();
       string.Append(next_char);
     } else {
@@ -484,9 +592,9 @@
       string.Convert();
 
       // Read past the escape '\' and ensure there's a character following.
-      Optional<StringPiece> escape_sequence = ConsumeChars(2);
+      absl::optional<StringPiece> escape_sequence = ConsumeChars(2);
       if (!escape_sequence) {
-        ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+        ReportError(JSON_INVALID_ESCAPE, -1);
         return false;
       }
 
@@ -495,16 +603,23 @@
         case 'x': {  // UTF-8 sequence.
           // UTF-8 \x escape sequences are not allowed in the spec, but they
           // are supported here for backwards-compatiblity with the old parser.
+          UmaHistogramEnumeration(kExtensionHistogramName,
+                                  ChromiumJsonExtension::kXEscape);
+          if (!(options_ & JSON_ALLOW_X_ESCAPES)) {
+            ReportError(JSON_INVALID_ESCAPE, -1);
+            return false;
+          }
+
           escape_sequence = ConsumeChars(2);
           if (!escape_sequence) {
-            ReportError(JSONReader::JSON_INVALID_ESCAPE, -2);
+            ReportError(JSON_INVALID_ESCAPE, -3);
             return false;
           }
 
           int hex_digit = 0;
-          if (!HexStringToInt(*escape_sequence, &hex_digit) ||
+          if (!UnprefixedHexStringToInt(*escape_sequence, &hex_digit) ||
               !IsValidCharacter(hex_digit)) {
-            ReportError(JSONReader::JSON_INVALID_ESCAPE, -2);
+            ReportError(JSON_INVALID_ESCAPE, -3);
             return false;
           }
 
@@ -513,9 +628,9 @@
         }
         case 'u': {  // UTF-16 sequence.
           // UTF units are of the form \uXXXX.
-          uint32_t code_point;
+          base_icu::UChar32 code_point;
           if (!DecodeUTF16(&code_point)) {
-            ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+            ReportError(JSON_INVALID_ESCAPE, -1);
             return false;
           }
           string.Append(code_point);
@@ -546,71 +661,79 @@
           string.Append('\t');
           break;
         case 'v':  // Not listed as valid escape sequence in the RFC.
+          UmaHistogramEnumeration(kExtensionHistogramName,
+                                  ChromiumJsonExtension::kVerticalTabEscape);
+          if (!(options_ & JSON_ALLOW_VERT_TAB)) {
+            ReportError(JSON_INVALID_ESCAPE, -1);
+            return false;
+          }
           string.Append('\v');
           break;
         // All other escape squences are illegal.
         default:
-          ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+          ReportError(JSON_INVALID_ESCAPE, -1);
           return false;
       }
     }
   }
 
-  ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+  ReportError(JSON_SYNTAX_ERROR, -1);
   return false;
 }
 
 // Entry is at the first X in \uXXXX.
-bool JSONParser::DecodeUTF16(uint32_t* out_code_point) {
-  Optional<StringPiece> escape_sequence = ConsumeChars(4);
+bool JSONParser::DecodeUTF16(base_icu::UChar32* out_code_point) {
+  absl::optional<StringPiece> escape_sequence = ConsumeChars(4);
   if (!escape_sequence)
     return false;
 
   // Consume the UTF-16 code unit, which may be a high surrogate.
   int code_unit16_high = 0;
-  if (!HexStringToInt(*escape_sequence, &code_unit16_high))
+  if (!UnprefixedHexStringToInt(*escape_sequence, &code_unit16_high))
     return false;
 
   // If this is a high surrogate, consume the next code unit to get the
   // low surrogate.
   if (CBU16_IS_SURROGATE(code_unit16_high)) {
-    // Make sure this is the high surrogate. If not, it's an encoding
-    // error.
-    if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high))
-      return false;
+    // Make sure this is the high surrogate.
+    if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high)) {
+      if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0)
+        return false;
+      *out_code_point = kUnicodeReplacementPoint;
+      return true;
+    }
 
     // Make sure that the token has more characters to consume the
     // lower surrogate.
-    if (!ConsumeIfMatch("\\u"))
-      return false;
+    if (!ConsumeIfMatch("\\u")) {
+      if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0)
+        return false;
+      *out_code_point = kUnicodeReplacementPoint;
+      return true;
+    }
 
     escape_sequence = ConsumeChars(4);
     if (!escape_sequence)
       return false;
 
     int code_unit16_low = 0;
-    if (!HexStringToInt(*escape_sequence, &code_unit16_low))
+    if (!UnprefixedHexStringToInt(*escape_sequence, &code_unit16_low))
       return false;
 
-    if (!CBU16_IS_TRAIL(code_unit16_low))
-      return false;
+    if (!CBU16_IS_TRAIL(code_unit16_low)) {
+      if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0)
+        return false;
+      *out_code_point = kUnicodeReplacementPoint;
+      return true;
+    }
 
-    uint32_t code_point =
+    base_icu::UChar32 code_point =
         CBU16_GET_SUPPLEMENTARY(code_unit16_high, code_unit16_low);
-    if (!IsValidCharacter(code_point))
-      return false;
 
     *out_code_point = code_point;
   } else {
     // Not a surrogate.
     DCHECK(CBU16_IS_SINGLE(code_unit16_high));
-    if (!IsValidCharacter(code_unit16_high)) {
-      if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) {
-        return false;
-      }
-      *out_code_point = kUnicodeReplacementPoint;
-      return true;
-    }
 
     *out_code_point = code_unit16_high;
   }
@@ -618,17 +741,17 @@
   return true;
 }
 
-Optional<Value> JSONParser::ConsumeNumber() {
+absl::optional<Value> JSONParser::ConsumeNumber() {
   const char* num_start = pos();
-  const int start_index = index_;
-  int end_index = start_index;
+  const size_t start_index = index_;
+  size_t end_index = start_index;
 
   if (PeekChar() == '-')
     ConsumeChar();
 
   if (!ReadInt(false)) {
-    ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
-    return nullopt;
+    ReportError(JSON_SYNTAX_ERROR, 0);
+    return absl::nullopt;
   }
   end_index = index_;
 
@@ -636,22 +759,22 @@
   if (PeekChar() == '.') {
     ConsumeChar();
     if (!ReadInt(true)) {
-      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
-      return nullopt;
+      ReportError(JSON_SYNTAX_ERROR, 0);
+      return absl::nullopt;
     }
     end_index = index_;
   }
 
   // Optional exponent part.
-  Optional<char> c = PeekChar();
+  absl::optional<char> c = PeekChar();
   if (c == 'e' || c == 'E') {
     ConsumeChar();
     if (PeekChar() == '-' || PeekChar() == '+') {
       ConsumeChar();
     }
     if (!ReadInt(true)) {
-      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
-      return nullopt;
+      ReportError(JSON_SYNTAX_ERROR, 0);
+      return absl::nullopt;
     }
     end_index = index_;
   }
@@ -660,7 +783,7 @@
   // so save off where the parser should be on exit (see Consume invariant at
   // the top of the header), then make sure the next token is one which is
   // valid.
-  int exit_index = index_;
+  size_t exit_index = index_;
 
   switch (GetNextToken()) {
     case T_OBJECT_END:
@@ -669,8 +792,8 @@
     case T_END_OF_INPUT:
       break;
     default:
-      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
-      return nullopt;
+      ReportError(JSON_SYNTAX_ERROR, 0);
+      return absl::nullopt;
   }
 
   index_ = exit_index;
@@ -682,19 +805,19 @@
     return Value(num_int);
 
   double num_double;
-  if (StringToDouble(num_string.as_string(), &num_double) &&
-      std::isfinite(num_double)) {
+  if (StringToDouble(num_string, &num_double) && std::isfinite(num_double)) {
     return Value(num_double);
   }
 
-  return nullopt;
+  ReportError(JSON_UNREPRESENTABLE_NUMBER, 0);
+  return absl::nullopt;
 }
 
 bool JSONParser::ReadInt(bool allow_leading_zeros) {
   size_t len = 0;
   char first = 0;
 
-  while (Optional<char> c = PeekChar()) {
+  while (absl::optional<char> c = PeekChar()) {
     if (!IsAsciiDigit(c))
       break;
 
@@ -714,15 +837,15 @@
   return true;
 }
 
-Optional<Value> JSONParser::ConsumeLiteral() {
+absl::optional<Value> JSONParser::ConsumeLiteral() {
   if (ConsumeIfMatch("true"))
     return Value(true);
   if (ConsumeIfMatch("false"))
     return Value(false);
   if (ConsumeIfMatch("null"))
     return Value(Value::Type::NONE);
-  ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
-  return nullopt;
+  ReportError(JSON_SYNTAX_ERROR, 0);
+  return absl::nullopt;
 }
 
 bool JSONParser::ConsumeIfMatch(StringPiece match) {
@@ -733,11 +856,16 @@
   return false;
 }
 
-void JSONParser::ReportError(JSONReader::JsonParseError code,
-                             int column_adjust) {
+void JSONParser::ReportError(JsonParseError code, int column_adjust) {
   error_code_ = code;
   error_line_ = line_number_;
-  error_column_ = index_ - index_last_line_ + column_adjust;
+  error_column_ = static_cast<int>(index_ - index_last_line_) + column_adjust;
+
+  // For a final blank line ('\n' and then EOF), a negative column_adjust may
+  // put us below 1, which doesn't really make sense for 1-based columns.
+  if (error_column_ < 1) {
+    error_column_ = 1;
+  }
 }
 
 // static
diff --git a/base/json/json_parser.h b/base/json/json_parser.h
index 9e6be55..0eb4fac 100644
--- a/base/json/json_parser.h
+++ b/base/json/json_parser.h
@@ -1,21 +1,24 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_JSON_JSON_PARSER_H_
 #define BASE_JSON_JSON_PARSER_H_
 
+#include <stddef.h>
+#include <stdint.h>
+
 #include <memory>
 #include <string>
 
 #include "base/base_export.h"
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
-#include "base/json/json_reader.h"
-#include "base/macros.h"
-#include "base/optional.h"
+#include "base/json/json_common.h"
 #include "base/strings/string_piece.h"
-#include "starboard/types.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "base/values.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 
@@ -41,17 +44,47 @@
 // of the next token.
 class BASE_EXPORT JSONParser {
  public:
-  JSONParser(int options, int max_depth = JSONReader::kStackMaxDepth);
+  // Error codes during parsing.
+  enum JsonParseError {
+    JSON_NO_ERROR = base::ValueDeserializer::kErrorCodeNoError,
+    JSON_SYNTAX_ERROR = base::ValueDeserializer::kErrorCodeInvalidFormat,
+    JSON_INVALID_ESCAPE,
+    JSON_UNEXPECTED_TOKEN,
+    JSON_TRAILING_COMMA,
+    JSON_TOO_MUCH_NESTING,
+    JSON_UNEXPECTED_DATA_AFTER_ROOT,
+    JSON_UNSUPPORTED_ENCODING,
+    JSON_UNQUOTED_DICTIONARY_KEY,
+    JSON_UNREPRESENTABLE_NUMBER,
+    JSON_PARSE_ERROR_COUNT
+  };
+
+  // String versions of parse error codes.
+  static const char kSyntaxError[];
+  static const char kInvalidEscape[];
+  static const char kUnexpectedToken[];
+  static const char kTrailingComma[];
+  static const char kTooMuchNesting[];
+  static const char kUnexpectedDataAfterRoot[];
+  static const char kUnsupportedEncoding[];
+  static const char kUnquotedDictionaryKey[];
+  static const char kUnrepresentableNumber[];
+
+  explicit JSONParser(int options, size_t max_depth = kAbsoluteMaxDepth);
+
+  JSONParser(const JSONParser&) = delete;
+  JSONParser& operator=(const JSONParser&) = delete;
+
   ~JSONParser();
 
   // Parses the input string according to the set options and returns the
   // result as a Value.
   // Wrap this in base::FooValue::From() to check the Value is of type Foo and
   // convert to a FooValue at the same time.
-  Optional<Value> Parse(StringPiece input);
+  absl::optional<Value> Parse(StringPiece input);
 
   // Returns the error code.
-  JSONReader::JsonParseError error_code() const;
+  JsonParseError error_code() const;
 
   // Returns the human-friendly error message.
   std::string GetErrorMessage() const;
@@ -101,7 +134,7 @@
     // Appends the Unicode code point |point| to the string, either by
     // increasing the |length_| of the string if the string has not been
     // converted, or by appending the UTF8 bytes for the code point.
-    void Append(uint32_t point);
+    void Append(base_icu::UChar32 point);
 
     // Converts the builder from its default StringPiece to a full std::string,
     // performing a copy. Once a builder is converted, it cannot be made a
@@ -122,22 +155,22 @@
 
     // The copied string representation. Will be unset until Convert() is
     // called.
-    base::Optional<std::string> string_;
+    absl::optional<std::string> string_;
   };
 
   // Returns the next |count| bytes of the input stream, or nullopt if fewer
   // than |count| bytes remain.
-  Optional<StringPiece> PeekChars(int count);
+  absl::optional<StringPiece> PeekChars(size_t count);
 
   // Calls PeekChars() with a |count| of 1.
-  Optional<char> PeekChar();
+  absl::optional<char> PeekChar();
 
   // Returns the next |count| bytes of the input stream, or nullopt if fewer
   // than |count| bytes remain, and advances the parser position by |count|.
-  Optional<StringPiece> ConsumeChars(int count);
+  absl::optional<StringPiece> ConsumeChars(size_t count);
 
   // Calls ConsumeChars() with a |count| of 1.
-  Optional<char> ConsumeChar();
+  absl::optional<char> ConsumeChar();
 
   // Returns a pointer to the current character position.
   const char* pos();
@@ -154,22 +187,22 @@
   bool EatComment();
 
   // Calls GetNextToken() and then ParseToken().
-  Optional<Value> ParseNextToken();
+  absl::optional<Value> ParseNextToken();
 
   // Takes a token that represents the start of a Value ("a structural token"
   // in RFC terms) and consumes it, returning the result as a Value.
-  Optional<Value> ParseToken(Token token);
+  absl::optional<Value> ParseToken(Token token);
 
   // Assuming that the parser is currently wound to '{', this parses a JSON
   // object into a Value.
-  Optional<Value> ConsumeDictionary();
+  absl::optional<Value> ConsumeDictionary();
 
   // Assuming that the parser is wound to '[', this parses a JSON list into a
   // Value.
-  Optional<Value> ConsumeList();
+  absl::optional<Value> ConsumeList();
 
   // Calls through ConsumeStringRaw and wraps it in a value.
-  Optional<Value> ConsumeString();
+  absl::optional<Value> ConsumeString();
 
   // Assuming that the parser is wound to a double quote, this parses a string,
   // decoding any escape sequences and converts UTF-16 to UTF-8. Returns true on
@@ -180,18 +213,18 @@
   // bytes (parser is wound to the first character of a HEX sequence, with the
   // potential for consuming another \uXXXX for a surrogate). Returns true on
   // success and places the code point |out_code_point|, and false on failure.
-  bool DecodeUTF16(uint32_t* out_code_point);
+  bool DecodeUTF16(base_icu::UChar32* out_code_point);
 
   // Assuming that the parser is wound to the start of a valid JSON number,
   // this parses and converts it to either an int or double value.
-  Optional<Value> ConsumeNumber();
+  absl::optional<Value> ConsumeNumber();
   // Helper that reads characters that are ints. Returns true if a number was
   // read and false on error.
   bool ReadInt(bool allow_leading_zeros);
 
   // Consumes the literal values of |true|, |false|, and |null|, assuming the
   // parser is wound to the first character of any of those.
-  Optional<Value> ConsumeLiteral();
+  absl::optional<Value> ConsumeLiteral();
 
   // Helper function that returns true if the byte squence |match| can be
   // consumed at the current parser position. Returns false if there are fewer
@@ -202,7 +235,7 @@
   // Sets the error information to |code| at the current column, based on
   // |index_| and |index_last_line_|, with an optional positive/negative
   // adjustment by |column_adjust|.
-  void ReportError(JSONReader::JsonParseError code, int column_adjust);
+  void ReportError(JsonParseError code, int column_adjust);
 
   // Given the line and column number of an error, formats one of the error
   // message contants from json_reader.h for human display.
@@ -213,25 +246,25 @@
   const int options_;
 
   // Maximum depth to parse.
-  const int max_depth_;
+  const size_t max_depth_;
 
   // The input stream being parsed. Note: Not guaranteed to NUL-terminated.
   StringPiece input_;
 
   // The index in the input stream to which the parser is wound.
-  int index_;
+  size_t index_;
 
   // The number of times the parser has recursed (current stack depth).
-  int stack_depth_;
+  size_t stack_depth_;
 
   // The line number that the parser is at currently.
   int line_number_;
 
   // The last value of |index_| on the previous line.
-  int index_last_line_;
+  size_t index_last_line_;
 
   // Error information.
-  JSONReader::JsonParseError error_code_;
+  JsonParseError error_code_;
   int error_line_;
   int error_column_;
 
@@ -243,10 +276,6 @@
   FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeLiterals);
   FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeNumbers);
   FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ErrorMessages);
-  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ReplaceInvalidCharacters);
-  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ReplaceInvalidUTF16EscapeSequence);
-
-  DISALLOW_COPY_AND_ASSIGN(JSONParser);
 };
 
 // Used when decoding and an invalid utf-8 sequence is encountered.
diff --git a/base/json/json_parser_unittest.cc b/base/json/json_parser_unittest.cc
index 0e5e10c..e8de7d5 100644
--- a/base/json/json_parser_unittest.cc
+++ b/base/json/json_parser_unittest.cc
@@ -1,20 +1,18 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/json_parser.h"
 
+#include <stddef.h>
+
 #include <memory>
 
 #include "base/json/json_reader.h"
 #include "base/memory/ptr_util.h"
-#include "base/optional.h"
-#include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "starboard/common/string.h"
-#include "starboard/memory.h"
-#include "starboard/types.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 namespace internal {
@@ -29,17 +27,6 @@
     return parser;
   }
 
-  // MSan will do a better job detecting over-read errors if the input is
-  // not nul-terminated on the heap. This will copy |input| to a new buffer
-  // owned by |owner|, returning a StringPiece to |owner|.
-  StringPiece MakeNotNullTerminatedInput(const char* input,
-                                         std::unique_ptr<char[]>* owner) {
-    size_t str_len = strlen(input);
-    owner->reset(new char[str_len]);
-    memcpy(owner->get(), input, str_len);
-    return StringPiece(owner->get(), str_len);
-  }
-
   void TestLastThree(JSONParser* parser) {
     EXPECT_EQ(',', *parser->PeekChar());
     parser->ConsumeChar();
@@ -67,60 +54,58 @@
 TEST_F(JSONParserTest, ConsumeString) {
   std::string input("\"test\",|");
   std::unique_ptr<JSONParser> parser(NewTestParser(input));
-  Optional<Value> value(parser->ConsumeString());
+  absl::optional<Value> value(parser->ConsumeString());
   EXPECT_EQ(',', *parser->pos());
 
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  std::string str;
-  EXPECT_TRUE(value->GetAsString(&str));
-  EXPECT_EQ("test", str);
+  ASSERT_TRUE(value->is_string());
+  EXPECT_EQ("test", value->GetString());
 }
 
 TEST_F(JSONParserTest, ConsumeList) {
   std::string input("[true, false],|");
   std::unique_ptr<JSONParser> parser(NewTestParser(input));
-  Optional<Value> value(parser->ConsumeList());
+  absl::optional<Value> value(parser->ConsumeList());
   EXPECT_EQ(',', *parser->pos());
 
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  base::ListValue* list;
-  EXPECT_TRUE(value->GetAsList(&list));
-  EXPECT_EQ(2u, list->GetSize());
+  Value::List* list = value->GetIfList();
+  ASSERT_TRUE(list);
+  EXPECT_EQ(2u, list->size());
 }
 
 TEST_F(JSONParserTest, ConsumeDictionary) {
   std::string input("{\"abc\":\"def\"},|");
   std::unique_ptr<JSONParser> parser(NewTestParser(input));
-  Optional<Value> value(parser->ConsumeDictionary());
+  absl::optional<Value> value(parser->ConsumeDictionary());
   EXPECT_EQ(',', *parser->pos());
 
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  base::DictionaryValue* dict;
-  EXPECT_TRUE(value->GetAsDictionary(&dict));
-  std::string str;
-  EXPECT_TRUE(dict->GetString("abc", &str));
-  EXPECT_EQ("def", str);
+  const Value::Dict* value_dict = value->GetIfDict();
+  ASSERT_TRUE(value_dict);
+  const std::string* str = value_dict->FindString("abc");
+  ASSERT_TRUE(str);
+  EXPECT_EQ("def", *str);
 }
 
 TEST_F(JSONParserTest, ConsumeLiterals) {
   // Literal |true|.
   std::string input("true,|");
   std::unique_ptr<JSONParser> parser(NewTestParser(input));
-  Optional<Value> value(parser->ConsumeLiteral());
+  absl::optional<Value> value(parser->ConsumeLiteral());
   EXPECT_EQ(',', *parser->pos());
 
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  bool bool_value = false;
-  EXPECT_TRUE(value->GetAsBoolean(&bool_value));
-  EXPECT_TRUE(bool_value);
+  ASSERT_TRUE(value->is_bool());
+  EXPECT_TRUE(value->GetBool());
 
   // Literal |false|.
   input = "false,|";
@@ -131,8 +116,8 @@
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  EXPECT_TRUE(value->GetAsBoolean(&bool_value));
-  EXPECT_FALSE(bool_value);
+  ASSERT_TRUE(value->is_bool());
+  EXPECT_FALSE(value->GetBool());
 
   // Literal |null|.
   input = "null,|";
@@ -150,15 +135,14 @@
   // Integer.
   std::string input("1234,|");
   std::unique_ptr<JSONParser> parser(NewTestParser(input));
-  Optional<Value> value(parser->ConsumeNumber());
+  absl::optional<Value> value(parser->ConsumeNumber());
   EXPECT_EQ(',', *parser->pos());
 
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  int number_i;
-  EXPECT_TRUE(value->GetAsInteger(&number_i));
-  EXPECT_EQ(1234, number_i);
+  ASSERT_TRUE(value->is_int());
+  EXPECT_EQ(1234, value->GetInt());
 
   // Negative integer.
   input = "-1234,|";
@@ -169,8 +153,8 @@
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  EXPECT_TRUE(value->GetAsInteger(&number_i));
-  EXPECT_EQ(-1234, number_i);
+  ASSERT_TRUE(value->is_int());
+  EXPECT_EQ(-1234, value->GetInt());
 
   // Double.
   input = "12.34,|";
@@ -181,9 +165,8 @@
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  double number_d;
-  EXPECT_TRUE(value->GetAsDouble(&number_d));
-  EXPECT_EQ(12.34, number_d);
+  ASSERT_TRUE(value->is_double());
+  EXPECT_EQ(12.34, value->GetDouble());
 
   // Scientific.
   input = "42e3,|";
@@ -194,8 +177,8 @@
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  EXPECT_TRUE(value->GetAsDouble(&number_d));
-  EXPECT_EQ(42000, number_d);
+  ASSERT_TRUE(value->is_double());
+  EXPECT_EQ(42000, value->GetDouble());
 
   // Negative scientific.
   input = "314159e-5,|";
@@ -206,8 +189,8 @@
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  EXPECT_TRUE(value->GetAsDouble(&number_d));
-  EXPECT_EQ(3.14159, number_d);
+  ASSERT_TRUE(value->is_double());
+  EXPECT_EQ(3.14159, value->GetDouble());
 
   // Positive scientific.
   input = "0.42e+3,|";
@@ -218,244 +201,107 @@
   TestLastThree(parser.get());
 
   ASSERT_TRUE(value);
-  EXPECT_TRUE(value->GetAsDouble(&number_d));
-  EXPECT_EQ(420, number_d);
+  ASSERT_TRUE(value->is_double());
+  EXPECT_EQ(420, value->GetDouble());
 }
 
 TEST_F(JSONParserTest, ErrorMessages) {
-  // Error strings should not be modified in case of success.
-  std::string error_message;
-  int error_code = 0;
-  std::unique_ptr<Value> root = JSONReader::ReadAndReturnError(
-      "[42]", JSON_PARSE_RFC, &error_code, &error_message);
-  EXPECT_TRUE(error_message.empty());
-  EXPECT_EQ(0, error_code);
-
-  // Test line and column counting
-  const char big_json[] = "[\n0,\n1,\n2,\n3,4,5,6 7,\n8,\n9\n]";
-  // error here ----------------------------------^
-  root = JSONReader::ReadAndReturnError(big_json, JSON_PARSE_RFC, &error_code,
-                                        &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
-            error_message);
-  EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
-
-  error_code = 0;
-  error_message = "";
-  // Test line and column counting with "\r\n" line ending
-  const char big_json_crlf[] =
-      "[\r\n0,\r\n1,\r\n2,\r\n3,4,5,6 7,\r\n8,\r\n9\r\n]";
-  // error here ----------------------^
-  root = JSONReader::ReadAndReturnError(big_json_crlf, JSON_PARSE_RFC,
-                                        &error_code, &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
-            error_message);
-  EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
+  {
+    JSONParser parser(JSON_PARSE_RFC);
+    absl::optional<Value> value = parser.Parse("[42]");
+    EXPECT_TRUE(value);
+    EXPECT_TRUE(parser.GetErrorMessage().empty());
+    EXPECT_EQ(0, parser.error_code());
+  }
 
   // Test each of the error conditions
-  root = JSONReader::ReadAndReturnError("{},{}", JSON_PARSE_RFC, &error_code,
-                                        &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 3,
-      JSONReader::kUnexpectedDataAfterRoot), error_message);
-  EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, error_code);
-
-  std::string nested_json;
-  for (int i = 0; i < 201; ++i) {
-    nested_json.insert(nested_json.begin(), '[');
-    nested_json.append(1, ']');
+  {
+    JSONParser parser(JSON_PARSE_RFC);
+    absl::optional<Value> value = parser.Parse("{},{}");
+    EXPECT_FALSE(value);
+    EXPECT_EQ(JSONParser::FormatErrorMessage(
+                  1, 3, JSONParser::kUnexpectedDataAfterRoot),
+              parser.GetErrorMessage());
+    EXPECT_EQ(JSONParser::JSON_UNEXPECTED_DATA_AFTER_ROOT, parser.error_code());
   }
-  root = JSONReader::ReadAndReturnError(nested_json, JSON_PARSE_RFC,
-                                        &error_code, &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 200, JSONReader::kTooMuchNesting),
-            error_message);
-  EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, error_code);
 
-  root = JSONReader::ReadAndReturnError("[1,]", JSON_PARSE_RFC, &error_code,
-                                        &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma),
-            error_message);
-  EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
-
-  root = JSONReader::ReadAndReturnError("{foo:\"bar\"}", JSON_PARSE_RFC,
-                                        &error_code, &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2,
-      JSONReader::kUnquotedDictionaryKey), error_message);
-  EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, error_code);
-
-  root = JSONReader::ReadAndReturnError("{\"foo\":\"bar\",}", JSON_PARSE_RFC,
-                                        &error_code, &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma),
-            error_message);
-
-  root = JSONReader::ReadAndReturnError("[nu]", JSON_PARSE_RFC, &error_code,
-                                        &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError),
-            error_message);
-  EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
-
-  root = JSONReader::ReadAndReturnError("[\"xxx\\xq\"]", JSON_PARSE_RFC,
-                                        &error_code, &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
-            error_message);
-  EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
-
-  root = JSONReader::ReadAndReturnError("[\"xxx\\uq\"]", JSON_PARSE_RFC,
-                                        &error_code, &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
-            error_message);
-  EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
-
-  root = JSONReader::ReadAndReturnError("[\"xxx\\q\"]", JSON_PARSE_RFC,
-                                        &error_code, &error_message);
-  EXPECT_FALSE(root.get());
-  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
-            error_message);
-  EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
-
-  root = JSONReader::ReadAndReturnError(("[\"\\ufffe\"]"), JSON_PARSE_RFC,
-                                        &error_code, &error_message);
-  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 8, JSONReader::kInvalidEscape),
-            error_message);
-  EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
-}
-
-TEST_F(JSONParserTest, Decode4ByteUtf8Char) {
-  // This test strings contains a 4 byte unicode character (a smiley!) that the
-  // reader should be able to handle (the character is \xf0\x9f\x98\x87).
-  const char kUtf8Data[] =
-      "[\"😇\",[],[],[],{\"google:suggesttype\":[]}]";
-  std::string error_message;
-  int error_code = 0;
-  std::unique_ptr<Value> root = JSONReader::ReadAndReturnError(
-      kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message);
-  EXPECT_TRUE(root.get()) << error_message;
-}
-
-TEST_F(JSONParserTest, DecodeUnicodeNonCharacter) {
-  // Tests Unicode code points (encoded as escaped UTF-16) that are not valid
-  // characters.
-  EXPECT_FALSE(JSONReader::Read("[\"\\ufdd0\"]"));
-  EXPECT_FALSE(JSONReader::Read("[\"\\ufffe\"]"));
-  EXPECT_FALSE(JSONReader::Read("[\"\\ud83f\\udffe\"]"));
-
-  EXPECT_TRUE(
-      JSONReader::Read("[\"\\ufdd0\"]", JSON_REPLACE_INVALID_CHARACTERS));
-  EXPECT_TRUE(
-      JSONReader::Read("[\"\\ufffe\"]", JSON_REPLACE_INVALID_CHARACTERS));
-}
-
-TEST_F(JSONParserTest, DecodeNegativeEscapeSequence) {
-  EXPECT_FALSE(JSONReader::Read("[\"\\x-A\"]"));
-  EXPECT_FALSE(JSONReader::Read("[\"\\u-00A\"]"));
-}
-
-// Verifies invalid utf-8 characters are replaced.
-TEST_F(JSONParserTest, ReplaceInvalidCharacters) {
-  const std::string bogus_char = "ó¿¿¿";
-  const std::string quoted_bogus_char = "\"" + bogus_char + "\"";
-  std::unique_ptr<JSONParser> parser(
-      NewTestParser(quoted_bogus_char, JSON_REPLACE_INVALID_CHARACTERS));
-  Optional<Value> value(parser->ConsumeString());
-  ASSERT_TRUE(value);
-  std::string str;
-  EXPECT_TRUE(value->GetAsString(&str));
-  EXPECT_EQ(kUnicodeReplacementString, str);
-}
-
-TEST_F(JSONParserTest, ReplaceInvalidUTF16EscapeSequence) {
-  const std::string invalid = "\"\\ufffe\"";
-  std::unique_ptr<JSONParser> parser(
-      NewTestParser(invalid, JSON_REPLACE_INVALID_CHARACTERS));
-  Optional<Value> value(parser->ConsumeString());
-  ASSERT_TRUE(value);
-  std::string str;
-  EXPECT_TRUE(value->GetAsString(&str));
-  EXPECT_EQ(kUnicodeReplacementString, str);
-}
-
-TEST_F(JSONParserTest, ParseNumberErrors) {
-  const struct {
-    const char* input;
-    bool parse_success;
-    double value;
-  } kCases[] = {
-      // clang-format off
-      {"1", true, 1},
-      {"2.", false, 0},
-      {"42", true, 42},
-      {"6e", false, 0},
-      {"43e2", true, 4300},
-      {"43e-", false, 0},
-      {"9e-3", true, 0.009},
-      {"2e+", false, 0},
-      {"2e+2", true, 200},
-      // clang-format on
-  };
-
-  for (unsigned int i = 0; i < arraysize(kCases); ++i) {
-    auto test_case = kCases[i];
-    SCOPED_TRACE(StringPrintf("case %u: \"%s\"", i, test_case.input));
-
-    std::unique_ptr<char[]> input_owner;
-    StringPiece input =
-        MakeNotNullTerminatedInput(test_case.input, &input_owner);
-
-    std::unique_ptr<Value> result = JSONReader::Read(input);
-    if (test_case.parse_success) {
-      EXPECT_TRUE(result);
-    } else {
-      EXPECT_FALSE(result);
+  {
+    std::string nested_json;
+    for (int i = 0; i < 201; ++i) {
+      nested_json.insert(nested_json.begin(), '[');
+      nested_json.append(1, ']');
     }
-
-    if (!result)
-      continue;
-
-    double double_value = 0;
-    EXPECT_TRUE(result->GetAsDouble(&double_value));
-    EXPECT_EQ(test_case.value, double_value);
+    JSONParser parser(JSON_PARSE_RFC);
+    absl::optional<Value> value = parser.Parse(nested_json);
+    EXPECT_FALSE(value);
+    EXPECT_EQ(
+        JSONParser::FormatErrorMessage(1, 200, JSONParser::kTooMuchNesting),
+        parser.GetErrorMessage());
+    EXPECT_EQ(JSONParser::JSON_TOO_MUCH_NESTING, parser.error_code());
   }
-}
 
-TEST_F(JSONParserTest, UnterminatedInputs) {
-  const char* kCases[] = {
-      // clang-format off
-      "/",
-      "//",
-      "/*",
-      "\"xxxxxx",
-      "\"",
-      "{   ",
-      "[\t",
-      "tru",
-      "fals",
-      "nul",
-      "\"\\x",
-      "\"\\x2",
-      "\"\\u123",
-      "\"\\uD803\\u",
-      "\"\\",
-      "\"\\/",
-      // clang-format on
-  };
+  {
+    JSONParser parser(JSON_PARSE_RFC);
+    absl::optional<Value> value = parser.Parse("[1,]");
+    EXPECT_FALSE(value);
+    EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONParser::kTrailingComma),
+              parser.GetErrorMessage());
+    EXPECT_EQ(JSONParser::JSON_TRAILING_COMMA, parser.error_code());
+  }
 
-  for (unsigned int i = 0; i < arraysize(kCases); ++i) {
-    auto* test_case = kCases[i];
-    SCOPED_TRACE(StringPrintf("case %u: \"%s\"", i, test_case));
+  {
+    JSONParser parser(JSON_PARSE_RFC);
+    absl::optional<Value> value = parser.Parse("{foo:\"bar\"}");
+    EXPECT_FALSE(value);
+    EXPECT_EQ(JSONParser::FormatErrorMessage(
+                  1, 2, JSONParser::kUnquotedDictionaryKey),
+              parser.GetErrorMessage());
+    EXPECT_EQ(JSONParser::JSON_UNQUOTED_DICTIONARY_KEY, parser.error_code());
+  }
 
-    std::unique_ptr<char[]> input_owner;
-    StringPiece input = MakeNotNullTerminatedInput(test_case, &input_owner);
+  {
+    JSONParser parser(JSON_PARSE_RFC);
+    absl::optional<Value> value = parser.Parse("{\"foo\":\"bar\",}");
+    EXPECT_FALSE(value);
+    EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONParser::kTrailingComma),
+              parser.GetErrorMessage());
+    EXPECT_EQ(JSONParser::JSON_TRAILING_COMMA, parser.error_code());
+  }
 
-    EXPECT_FALSE(JSONReader::Read(input));
+  {
+    JSONParser parser(JSON_PARSE_RFC);
+    absl::optional<Value> value = parser.Parse("[nu]");
+    EXPECT_FALSE(value);
+    EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONParser::kSyntaxError),
+              parser.GetErrorMessage());
+    EXPECT_EQ(JSONParser::JSON_SYNTAX_ERROR, parser.error_code());
+  }
+
+  {
+    JSONParser parser(JSON_PARSE_RFC | JSON_ALLOW_X_ESCAPES);
+    absl::optional<Value> value = parser.Parse("[\"xxx\\xq\"]");
+    EXPECT_FALSE(value);
+    EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape),
+              parser.GetErrorMessage());
+    EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code());
+  }
+
+  {
+    JSONParser parser(JSON_PARSE_RFC);
+    absl::optional<Value> value = parser.Parse("[\"xxx\\uq\"]");
+    EXPECT_FALSE(value);
+    EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape),
+              parser.GetErrorMessage());
+    EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code());
+  }
+
+  {
+    JSONParser parser(JSON_PARSE_RFC);
+    absl::optional<Value> value = parser.Parse("[\"xxx\\q\"]");
+    EXPECT_FALSE(value);
+    EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape),
+              parser.GetErrorMessage());
+    EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code());
   }
 }
 
diff --git a/base/json/json_perftest.cc b/base/json/json_perftest.cc
index fc05bdc..11f5290 100644
--- a/base/json/json_perftest.cc
+++ b/base/json/json_perftest.cc
@@ -1,47 +1,61 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
+#include "testing/perf/perf_result_reporter.h"
 
 namespace base {
 
 namespace {
+
+constexpr char kMetricPrefixJSON[] = "JSON.";
+constexpr char kMetricReadTime[] = "read_time";
+constexpr char kMetricWriteTime[] = "write_time";
+
+perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
+  perf_test::PerfResultReporter reporter(kMetricPrefixJSON, story_name);
+  reporter.RegisterImportantMetric(kMetricReadTime, "ms");
+  reporter.RegisterImportantMetric(kMetricWriteTime, "ms");
+  return reporter;
+}
+
 // Generates a simple dictionary value with simple data types, a string and a
 // list.
-std::unique_ptr<DictionaryValue> GenerateDict() {
-  auto root = std::make_unique<DictionaryValue>();
-  root->SetDouble("Double", 3.141);
-  root->SetBoolean("Bool", true);
-  root->SetInteger("Int", 42);
-  root->SetString("String", "Foo");
+Value::Dict GenerateDict() {
+  Value::Dict root;
+  root.Set("Double", 3.141);
+  root.Set("Bool", true);
+  root.Set("Int", 42);
+  root.Set("String", "Foo");
 
-  auto list = std::make_unique<ListValue>();
-  list->Set(0, std::make_unique<Value>(2.718));
-  list->Set(1, std::make_unique<Value>(false));
-  list->Set(2, std::make_unique<Value>(123));
-  list->Set(3, std::make_unique<Value>("Bar"));
-  root->Set("List", std::move(list));
+  Value::List list;
+  list.Append(2.718);
+  list.Append(false);
+  list.Append(123);
+  list.Append("Bar");
+  root.Set("List", std::move(list));
 
   return root;
 }
 
 // Generates a tree-like dictionary value with a size of O(breadth ** depth).
-std::unique_ptr<DictionaryValue> GenerateLayeredDict(int breadth, int depth) {
+Value::Dict GenerateLayeredDict(int breadth, int depth) {
   if (depth == 1)
     return GenerateDict();
 
-  auto root = GenerateDict();
-  auto next = GenerateLayeredDict(breadth, depth - 1);
+  Value::Dict root = GenerateDict();
+  Value::Dict next = GenerateLayeredDict(breadth, depth - 1);
 
   for (int i = 0; i < breadth; ++i) {
-    root->Set("Dict" + std::to_string(i), next->CreateDeepCopy());
+    root.Set("Dict" + base::NumberToString(i), next.Clone());
   }
 
   return root;
@@ -52,30 +66,32 @@
 class JSONPerfTest : public testing::Test {
  public:
   void TestWriteAndRead(int breadth, int depth) {
-    std::string description = "Breadth: " + std::to_string(breadth) +
-                              ", Depth: " + std::to_string(depth);
-    auto dict = GenerateLayeredDict(breadth, depth);
+    std::string description = "Breadth: " + base::NumberToString(breadth) +
+                              ", Depth: " + base::NumberToString(depth);
+    Value::Dict dict = GenerateLayeredDict(breadth, depth);
     std::string json;
 
     TimeTicks start_write = TimeTicks::Now();
-    JSONWriter::Write(*dict, &json);
+    JSONWriter::Write(dict, &json);
     TimeTicks end_write = TimeTicks::Now();
-    perf_test::PrintResult("Write", "", description,
-                           (end_write - start_write).InMillisecondsF(), "ms",
-                           true);
+    auto reporter = SetUpReporter("breadth_" + base::NumberToString(breadth) +
+                                  "_depth_" + base::NumberToString(depth));
+    reporter.AddResult(kMetricWriteTime, end_write - start_write);
 
     TimeTicks start_read = TimeTicks::Now();
     JSONReader::Read(json);
     TimeTicks end_read = TimeTicks::Now();
-    perf_test::PrintResult("Read", "", description,
-                           (end_read - start_read).InMillisecondsF(), "ms",
-                           true);
+    reporter.AddResult(kMetricReadTime, end_read - start_read);
   }
 };
 
 TEST_F(JSONPerfTest, StressTest) {
+  // These loop ranges are chosen such that this test will complete in a
+  // reasonable amount of time and will work on a 32-bit build without hitting
+  // an out-of-memory failure. Having j go to 10 uses over 2 GiB of memory and
+  // might hit Android timeouts so be wary of going that high.
   for (int i = 0; i < 4; ++i) {
-    for (int j = 0; j < 12; ++j) {
+    for (int j = 0; j < 10; ++j) {
       TestWriteAndRead(i + 1, j + 1);
     }
   }
diff --git a/base/json/json_perftest_decodebench.cc b/base/json/json_perftest_decodebench.cc
new file mode 100644
index 0000000..9972de8
--- /dev/null
+++ b/base/json/json_perftest_decodebench.cc
@@ -0,0 +1,100 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This program measures the time taken to decode the given JSON files (the
+// command line arguments). It is for manual benchmarking.
+//
+// Usage:
+// $ ninja -C out/foobar json_perftest_decodebench
+// $ out/foobar/json_perftest_decodebench -a -n=10 the/path/to/your/*.json
+//
+// The -n=10 switch controls the number of iterations. It defaults to 1.
+//
+// The -a switch means to print 1 non-comment line per input file (the average
+// iteration time). Without this switch (the default), it prints n non-comment
+// lines per input file (individual iteration times). For a single input file,
+// building and running this program before and after a particular commit can
+// work well with the 'ministat' tool: https://github.com/thorduri/ministat
+
+#include <inttypes.h>
+#include <iomanip>
+#include <iostream>
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+
+int main(int argc, char* argv[]) {
+  if (!base::ThreadTicks::IsSupported()) {
+    std::cout << "# base::ThreadTicks is not supported\n";
+    return EXIT_FAILURE;
+  }
+  base::ThreadTicks::WaitUntilInitialized();
+
+  base::CommandLine::Init(argc, argv);
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  bool average = command_line->HasSwitch("a");
+  int iterations = 1;
+  std::string iterations_str = command_line->GetSwitchValueASCII("n");
+  if (!iterations_str.empty()) {
+    iterations = atoi(iterations_str.c_str());
+    if (iterations < 1) {
+      std::cout << "# invalid -n command line switch\n";
+      return EXIT_FAILURE;
+    }
+  }
+
+  if (average) {
+    std::cout << "# Microseconds (μs), n=" << iterations << ", averaged"
+              << std::endl;
+  } else {
+    std::cout << "# Microseconds (μs), n=" << iterations << std::endl;
+  }
+  for (const auto& filename : command_line->GetArgs()) {
+    std::string src;
+    if (!base::ReadFileToString(base::FilePath(filename), &src)) {
+      std::cout << "# could not read " << filename << std::endl;
+      return EXIT_FAILURE;
+    }
+
+    int64_t total_time = 0;
+    std::string error_message;
+    for (int i = 0; i < iterations; ++i) {
+      auto start = base::ThreadTicks::Now();
+      auto v = base::JSONReader::ReadAndReturnValueWithError(src);
+      auto end = base::ThreadTicks::Now();
+      int64_t iteration_time = (end - start).InMicroseconds();
+      total_time += iteration_time;
+
+      if (i == 0) {
+        if (average) {
+          error_message =
+              !v.has_value() ? std::move(v.error().message) : std::string();
+        } else {
+          std::cout << "# " << filename;
+          if (!v.has_value() && !v.error().message.empty()) {
+            std::cout << ": " << v.error().message;
+          }
+          std::cout << std::endl;
+        }
+      }
+
+      if (!average) {
+        std::cout << iteration_time << std::endl;
+      }
+    }
+
+    if (average) {
+      int64_t average_time = total_time / iterations;
+      std::cout << std::setw(12) << average_time << "\t# " << filename;
+      if (!error_message.empty()) {
+        std::cout << ": " << error_message;
+      }
+      std::cout << std::endl;
+    }
+  }
+  return EXIT_SUCCESS;
+}
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index bf2a18a..8faa713 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.cc
@@ -1,126 +1,170 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/json_reader.h"
 
 #include <utility>
-#include <vector>
 
-#include "base/json/json_parser.h"
 #include "base/logging.h"
-#include "base/optional.h"
-#include "base/values.h"
+#include "base/rust_buildflags.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+#if BUILDFLAG(BUILD_RUST_JSON_READER)
+#include "base/strings/string_piece_rust.h"
+#include "third_party/rust/serde_json_lenient/v0_1/wrapper/functions.h"
+#include "third_party/rust/serde_json_lenient/v0_1/wrapper/lib.rs.h"
+#else
+#include "base/json/json_parser.h"
+#endif
 
 namespace base {
 
-// Chosen to support 99.9% of documents found in the wild late 2016.
-// http://crbug.com/673263
-const int JSONReader::kStackMaxDepth = 200;
+#if BUILDFLAG(BUILD_RUST_JSON_READER)
 
-// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError.
-static_assert(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
-              "JSONReader error out of bounds");
+namespace {
+using serde_json_lenient::ContextPointer;
 
-const char JSONReader::kInvalidEscape[] =
-    "Invalid escape sequence.";
-const char JSONReader::kSyntaxError[] =
-    "Syntax error.";
-const char JSONReader::kUnexpectedToken[] =
-    "Unexpected token.";
-const char JSONReader::kTrailingComma[] =
-    "Trailing comma not allowed.";
-const char JSONReader::kTooMuchNesting[] =
-    "Too much nesting.";
-const char JSONReader::kUnexpectedDataAfterRoot[] =
-    "Unexpected data after root element.";
-const char JSONReader::kUnsupportedEncoding[] =
-    "Unsupported encoding. JSON must be UTF-8.";
-const char JSONReader::kUnquotedDictionaryKey[] =
-    "Dictionary keys must be quoted.";
-const char JSONReader::kInputTooLarge[] =
-    "Input string is too large (>2GB).";
+ContextPointer& ListAppendList(ContextPointer& ctx, size_t reserve) {
+  auto& value = reinterpret_cast<base::Value&>(ctx);
+  value.GetList().reserve(reserve);
+  value.GetList().Append(base::Value::List());
+  return reinterpret_cast<ContextPointer&>(value.GetList().back());
+}
 
-JSONReader::JSONReader(int options, int max_depth)
-    : parser_(new internal::JSONParser(options, max_depth)) {}
+ContextPointer& ListAppendDict(ContextPointer& ctx) {
+  auto& value = reinterpret_cast<base::Value&>(ctx);
+  value.GetList().Append(base::Value::Dict());
+  return reinterpret_cast<ContextPointer&>(value.GetList().back());
+}
 
-JSONReader::~JSONReader() = default;
+void ListAppendNone(ContextPointer& ctx) {
+  auto& value = reinterpret_cast<base::Value&>(ctx);
+  value.GetList().Append(base::Value());
+}
+
+template <class T, class As = T>
+void ListAppendValue(ContextPointer& ctx, T v) {
+  auto& value = reinterpret_cast<base::Value&>(ctx);
+  value.GetList().Append(As{v});
+}
+
+ContextPointer& DictSetList(ContextPointer& ctx,
+                            rust::Str key,
+                            size_t reserve) {
+  auto& value = reinterpret_cast<base::Value&>(ctx);
+  base::Value::List list;
+  list.reserve(reserve);
+  value.SetKey(base::RustStrToStringPiece(key), base::Value(std::move(list)));
+  return reinterpret_cast<ContextPointer&>(
+      *value.GetDict().Find(base::RustStrToStringPiece(key)));
+}
+
+ContextPointer& DictSetDict(ContextPointer& ctx, rust::Str key) {
+  auto& value = reinterpret_cast<base::Value&>(ctx);
+  value.SetKey(base::RustStrToStringPiece(key),
+               base::Value(base::Value::Dict()));
+  return reinterpret_cast<ContextPointer&>(
+      *value.GetDict().Find(base::RustStrToStringPiece(key)));
+}
+
+void DictSetNone(ContextPointer& ctx, rust::Str key) {
+  auto& value = reinterpret_cast<base::Value&>(ctx);
+  value.SetKey(base::RustStrToStringPiece(key), base::Value());
+}
+
+template <class T, class As = T>
+void DictSetValue(ContextPointer& ctx, rust::Str key, T v) {
+  auto& value = reinterpret_cast<base::Value&>(ctx);
+  value.SetKey(base::RustStrToStringPiece(key), base::Value(As{v}));
+}
+
+JSONReader::Result DecodeJSONInRust(const base::StringPiece& json,
+                                    int options,
+                                    size_t max_depth) {
+  const serde_json_lenient::JsonOptions rust_options = {
+      .allow_trailing_commas =
+          (options & base::JSON_ALLOW_TRAILING_COMMAS) != 0,
+      .replace_invalid_characters =
+          (options & base::JSON_REPLACE_INVALID_CHARACTERS) != 0,
+      .allow_comments = (options & base::JSON_ALLOW_COMMENTS) != 0,
+      .allow_control_chars = (options & base::JSON_ALLOW_CONTROL_CHARS) != 0,
+      .allow_vert_tab = (options & base::JSON_ALLOW_VERT_TAB) != 0,
+      .allow_x_escapes = (options & base::JSON_ALLOW_X_ESCAPES) != 0,
+      .max_depth = max_depth,
+  };
+  const serde_json_lenient::Functions functions = {
+      .list_append_none_fn = ListAppendNone,
+      .list_append_bool_fn = ListAppendValue<bool>,
+      .list_append_i32_fn = ListAppendValue<int32_t>,
+      .list_append_f64_fn = ListAppendValue<double>,
+      .list_append_str_fn = ListAppendValue<rust::Str, std::string>,
+      .list_append_list_fn = ListAppendList,
+      .list_append_dict_fn = ListAppendDict,
+      .dict_set_none_fn = DictSetNone,
+      .dict_set_bool_fn = DictSetValue<bool>,
+      .dict_set_i32_fn = DictSetValue<int32_t>,
+      .dict_set_f64_fn = DictSetValue<double>,
+      .dict_set_str_fn = DictSetValue<rust::Str, std::string>,
+      .dict_set_list_fn = DictSetList,
+      .dict_set_dict_fn = DictSetDict,
+  };
+
+  base::Value value(base::Value::Type::LIST);
+  auto& ctx = reinterpret_cast<ContextPointer&>(value);
+  serde_json_lenient::DecodeError error;
+  bool ok = serde_json_lenient::decode_json(
+      base::StringPieceToRustSlice(json), rust_options, functions, ctx, error);
+
+  if (!ok) {
+    return base::unexpected(base::JSONReader::Error{
+        .message = std::string(error.message),
+        .line = error.line,
+        .column = error.column,
+    });
+  }
+
+  return std::move(std::move(value.GetList()).back());
+}
+
+}  // anonymous namespace
+
+#endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
 
 // static
-std::unique_ptr<Value> JSONReader::Read(StringPiece json,
-                                        int options,
-                                        int max_depth) {
+absl::optional<Value> JSONReader::Read(StringPiece json,
+                                       int options,
+                                       size_t max_depth) {
+#if BUILDFLAG(BUILD_RUST_JSON_READER)
+  JSONReader::Result result = DecodeJSONInRust(json, options, max_depth);
+  if (!result.has_value()) {
+    return absl::nullopt;
+  }
+  return std::move(*result);
+#else   // BUILDFLAG(BUILD_RUST_JSON_READER)
   internal::JSONParser parser(options, max_depth);
-  Optional<Value> root = parser.Parse(json);
-  return root ? std::make_unique<Value>(std::move(*root)) : nullptr;
+  return parser.Parse(json);
+#endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
 }
 
-
 // static
-std::unique_ptr<Value> JSONReader::ReadAndReturnError(
-    StringPiece json,
-    int options,
-    int* error_code_out,
-    std::string* error_msg_out,
-    int* error_line_out,
-    int* error_column_out) {
+JSONReader::Result JSONReader::ReadAndReturnValueWithError(StringPiece json,
+                                                           int options) {
+#if BUILDFLAG(BUILD_RUST_JSON_READER)
+  return DecodeJSONInRust(json, options, internal::kAbsoluteMaxDepth);
+#else   // BUILDFLAG(BUILD_RUST_JSON_READER)
   internal::JSONParser parser(options);
-  Optional<Value> root = parser.Parse(json);
-  if (!root) {
-    if (error_code_out)
-      *error_code_out = parser.error_code();
-    if (error_msg_out)
-      *error_msg_out = parser.GetErrorMessage();
-    if (error_line_out)
-      *error_line_out = parser.error_line();
-    if (error_column_out)
-      *error_column_out = parser.error_column();
+  auto value = parser.Parse(json);
+  if (!value) {
+    Error error;
+    error.message = parser.GetErrorMessage();
+    error.line = parser.error_line();
+    error.column = parser.error_column();
+    return base::unexpected(std::move(error));
   }
 
-  return root ? std::make_unique<Value>(std::move(*root)) : nullptr;
-}
-
-// static
-std::string JSONReader::ErrorCodeToString(JsonParseError error_code) {
-  switch (error_code) {
-    case JSON_NO_ERROR:
-      return std::string();
-    case JSON_INVALID_ESCAPE:
-      return kInvalidEscape;
-    case JSON_SYNTAX_ERROR:
-      return kSyntaxError;
-    case JSON_UNEXPECTED_TOKEN:
-      return kUnexpectedToken;
-    case JSON_TRAILING_COMMA:
-      return kTrailingComma;
-    case JSON_TOO_MUCH_NESTING:
-      return kTooMuchNesting;
-    case JSON_UNEXPECTED_DATA_AFTER_ROOT:
-      return kUnexpectedDataAfterRoot;
-    case JSON_UNSUPPORTED_ENCODING:
-      return kUnsupportedEncoding;
-    case JSON_UNQUOTED_DICTIONARY_KEY:
-      return kUnquotedDictionaryKey;
-    case JSON_TOO_LARGE:
-      return kInputTooLarge;
-    case JSON_PARSE_ERROR_COUNT:
-      break;
-  }
-  NOTREACHED();
-  return std::string();
-}
-
-std::unique_ptr<Value> JSONReader::ReadToValue(StringPiece json) {
-  Optional<Value> value = parser_->Parse(json);
-  return value ? std::make_unique<Value>(std::move(*value)) : nullptr;
-}
-
-JSONReader::JsonParseError JSONReader::error_code() const {
-  return parser_->error_code();
-}
-
-std::string JSONReader::GetErrorMessage() const {
-  return parser_->GetErrorMessage();
+  return std::move(*value);
+#endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
 }
 
 }  // namespace base
diff --git a/base/json/json_reader.h b/base/json/json_reader.h
index 2c6bd3e..00d23cf 100644
--- a/base/json/json_reader.h
+++ b/base/json/json_reader.h
@@ -1,133 +1,118 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
+// A JSON parser, converting from a base::StringPiece to a base::Value.
 //
-// A JSON parser.  Converts strings of JSON into a Value object (see
-// base/values.h).
-// http://www.ietf.org/rfc/rfc4627.txt?number=4627
+// The JSON spec is:
+// https://tools.ietf.org/rfc/rfc8259.txt
+// which obsoletes the earlier RFCs 4627, 7158 and 7159.
 //
-// Known limitations/deviations from the RFC:
-// - Only knows how to parse ints within the range of a signed 32 bit int and
-//   decimal numbers within a double.
-// - Assumes input is encoded as UTF8.  The spec says we should allow UTF-16
-//   (BE or LE) and UTF-32 (BE or LE) as well.
-// - We limit nesting to 100 levels to prevent stack overflow (this is allowed
-//   by the RFC).
-// - A Unicode FAQ ("http://unicode.org/faq/utf_bom.html") writes a data
-//   stream may start with a Unicode Byte-Order-Mark (U+FEFF), i.e. the input
-//   UTF-8 string for the JSONReader::JsonToValue() function may start with a
-//   UTF-8 BOM (0xEF, 0xBB, 0xBF).
-//   To avoid the function from mis-treating a UTF-8 BOM as an invalid
-//   character, the function skips a Unicode BOM at the beginning of the
-//   Unicode string (converted from the input UTF-8 string) before parsing it.
+// This RFC should be equivalent to the informal spec:
+// https://www.json.org/json-en.html
 //
-// TODO(tc): Add a parsing option to to relax object keys being wrapped in
-//   double quotes
-// TODO(tc): Add an option to disable comment stripping
+// Implementation choices permitted by the RFC:
+// - Nesting is limited (to a configurable depth, 200 by default).
+// - Numbers are limited to those representable by a finite double. The
+//   conversion from a JSON number (in the base::StringPiece input) to a
+//   double-flavored base::Value may also be lossy.
+// - The input (which must be UTF-8) may begin with a BOM (Byte Order Mark).
+// - Duplicate object keys (strings) are silently allowed. Last key-value pair
+//   wins. Previous pairs are discarded.
+//
+// Configurable (see the JSONParserOptions type) deviations from the RFC:
+// - Allow trailing commas: "[1,2,]".
+// - Replace invalid Unicode with U+FFFD REPLACEMENT CHARACTER.
+// - Allow "// etc\n" and "/* etc */" C-style comments.
+// - Allow ASCII control characters, including literal (not escaped) NUL bytes
+//   and new lines, within a JSON string.
+// - Allow "\\v" escapes within a JSON string, producing a vertical tab.
+// - Allow "\\x23" escapes within a JSON string. Subtly, the 2-digit hex value
+//   is a Unicode code point, not a UTF-8 byte. For example, "\\xFF" in the
+//   JSON source decodes to a base::Value whose string contains "\xC3\xBF", the
+//   UTF-8 encoding of U+00FF LATIN SMALL LETTER Y WITH DIAERESIS. Converting
+//   from UTF-8 to UTF-16, e.g. via UTF8ToWide, will recover a 16-bit 0x00FF.
 
 #ifndef BASE_JSON_JSON_READER_H_
 #define BASE_JSON_JSON_READER_H_
 
-#include <memory>
 #include <string>
 
 #include "base/base_export.h"
+#include "base/json/json_common.h"
 #include "base/strings/string_piece.h"
+#include "base/types/expected.h"
+#include "base/values.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 
-class Value;
-
-namespace internal {
-class JSONParser;
-}
-
 enum JSONParserOptions {
-  // Parses the input strictly according to RFC 4627, except for where noted
-  // above.
+  // Parses the input strictly according to RFC 8259.
   JSON_PARSE_RFC = 0,
 
   // Allows commas to exist after the last element in structures.
   JSON_ALLOW_TRAILING_COMMAS = 1 << 0,
 
-  // If set the parser replaces invalid characters with the Unicode replacement
-  // character (U+FFFD). If not set, invalid characters trigger a hard error and
-  // parsing fails.
+  // If set the parser replaces invalid code points (i.e. lone
+  // surrogates) with the Unicode replacement character (U+FFFD). If
+  // not set, invalid code points trigger a hard error and parsing
+  // fails.
   JSON_REPLACE_INVALID_CHARACTERS = 1 << 1,
+
+  // Allows both C (/* */) and C++ (//) style comments.
+  JSON_ALLOW_COMMENTS = 1 << 2,
+
+  // Permits unescaped ASCII control characters (such as unescaped \r and \n)
+  // in the range [0x00,0x1F].
+  JSON_ALLOW_CONTROL_CHARS = 1 << 3,
+
+  // Permits \\v vertical tab escapes.
+  JSON_ALLOW_VERT_TAB = 1 << 4,
+
+  // Permits \\xNN escapes as described above.
+  JSON_ALLOW_X_ESCAPES = 1 << 5,
+
+  // This parser historically accepted, without configuration flags,
+  // non-standard JSON extensions. This flag enables that traditional parsing
+  // behavior.
+  //
+  // This set of options is mirrored in Rust
+  // base::JsonOptions::with_chromium_extensions().
+  JSON_PARSE_CHROMIUM_EXTENSIONS = JSON_ALLOW_COMMENTS |
+                                   JSON_ALLOW_CONTROL_CHARS |
+                                   JSON_ALLOW_VERT_TAB | JSON_ALLOW_X_ESCAPES,
 };
 
 class BASE_EXPORT JSONReader {
  public:
-  static const int kStackMaxDepth;
-
-  // Error codes during parsing.
-  enum JsonParseError {
-    JSON_NO_ERROR = 0,
-    JSON_INVALID_ESCAPE,
-    JSON_SYNTAX_ERROR,
-    JSON_UNEXPECTED_TOKEN,
-    JSON_TRAILING_COMMA,
-    JSON_TOO_MUCH_NESTING,
-    JSON_UNEXPECTED_DATA_AFTER_ROOT,
-    JSON_UNSUPPORTED_ENCODING,
-    JSON_UNQUOTED_DICTIONARY_KEY,
-    JSON_TOO_LARGE,
-    JSON_PARSE_ERROR_COUNT
+  struct BASE_EXPORT Error {
+    std::string message;
+    int line = 0;
+    int column = 0;
   };
 
-  // String versions of parse error codes.
-  static const char kInvalidEscape[];
-  static const char kSyntaxError[];
-  static const char kUnexpectedToken[];
-  static const char kTrailingComma[];
-  static const char kTooMuchNesting[];
-  static const char kUnexpectedDataAfterRoot[];
-  static const char kUnsupportedEncoding[];
-  static const char kUnquotedDictionaryKey[];
-  static const char kInputTooLarge[];
+  using Result = base::expected<Value, Error>;
 
-  // Constructs a reader.
-  JSONReader(int options = JSON_PARSE_RFC, int max_depth = kStackMaxDepth);
-
-  ~JSONReader();
+  // This class contains only static methods.
+  JSONReader() = delete;
+  JSONReader(const JSONReader&) = delete;
+  JSONReader& operator=(const JSONReader&) = delete;
 
   // Reads and parses |json|, returning a Value.
-  // If |json| is not a properly formed JSON string, returns nullptr.
-  // Wrap this in base::FooValue::From() to check the Value is of type Foo and
-  // convert to a FooValue at the same time.
-  static std::unique_ptr<Value> Read(StringPiece json,
-                                     int options = JSON_PARSE_RFC,
-                                     int max_depth = kStackMaxDepth);
-
-  // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
-  // are optional. If specified and nullptr is returned, they will be populated
-  // an error code and a formatted error message (including error location if
-  // appropriate). Otherwise, they will be unmodified.
-  static std::unique_ptr<Value> ReadAndReturnError(
+  // If |json| is not a properly formed JSON string, returns absl::nullopt.
+  static absl::optional<Value> Read(
       StringPiece json,
-      int options,  // JSONParserOptions
-      int* error_code_out,
-      std::string* error_msg_out,
-      int* error_line_out = nullptr,
-      int* error_column_out = nullptr);
+      int options = JSON_PARSE_CHROMIUM_EXTENSIONS,
+      size_t max_depth = internal::kAbsoluteMaxDepth);
 
-  // Converts a JSON parse error code into a human readable message.
-  // Returns an empty string if error_code is JSON_NO_ERROR.
-  static std::string ErrorCodeToString(JsonParseError error_code);
-
-  // Non-static version of Read() above.
-  std::unique_ptr<Value> ReadToValue(StringPiece json);
-
-  // Returns the error code if the last call to ReadToValue() failed.
-  // Returns JSON_NO_ERROR otherwise.
-  JsonParseError error_code() const;
-
-  // Converts error_code_ to a human-readable string, including line and column
-  // numbers if appropriate.
-  std::string GetErrorMessage() const;
-
- private:
-  std::unique_ptr<internal::JSONParser> parser_;
+  // Reads and parses |json| like Read(). On success returns a Value as the
+  // expected value. Otherwise, it returns an Error instance, populated with a
+  // formatted error message, an error code, and the error location if
+  // appropriate as the error value of the expected type.
+  static Result ReadAndReturnValueWithError(
+      StringPiece json,
+      int options = JSON_PARSE_CHROMIUM_EXTENSIONS);
 };
 
 }  // namespace base
diff --git a/base/json/json_reader_fuzzer.cc b/base/json/json_reader_fuzzer.cc
index 2642646..fb82787 100644
--- a/base/json/json_reader_fuzzer.cc
+++ b/base/json/json_reader_fuzzer.cc
@@ -1,10 +1,13 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
 #include "base/values.h"
-#include "starboard/memory.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace base {
 
 // Entry point for LibFuzzer.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
@@ -16,15 +19,26 @@
   std::unique_ptr<char[]> input(new char[size - 1]);
   memcpy(input.get(), data, size - 1);
 
-  base::StringPiece input_string(input.get(), size - 1);
+  StringPiece input_string(input.get(), size - 1);
 
   const int options = data[size - 1];
 
-  int error_code, error_line, error_column;
-  std::string error_message;
-  base::JSONReader::ReadAndReturnError(input_string, options, &error_code,
-                                       &error_message, &error_line,
-                                       &error_column);
+  auto json_val =
+      JSONReader::ReadAndReturnValueWithError(input_string, options);
+  if (json_val.has_value()) {
+    // Check that the value can be serialized and deserialized back to an
+    // equivalent |Value|.
+    const Value& value = *json_val;
+    std::string serialized;
+    CHECK(JSONWriter::Write(value, &serialized));
+
+    absl::optional<Value> deserialized =
+        JSONReader::Read(StringPiece(serialized));
+    CHECK(deserialized);
+    CHECK_EQ(value, deserialized.value());
+  }
 
   return 0;
 }
+
+}  // namespace base
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
index 762092c..9d71caa 100644
--- a/base/json/json_reader_unittest.cc
+++ b/base/json/json_reader_unittest.cc
@@ -1,280 +1,341 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/json_reader.h"
 
-#include <memory>
+#include <stddef.h>
+
+#include <utility>
 
 #include "base/base_paths.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
-#include "base/macros.h"
 #include "base/path_service.h"
 #include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "starboard/types.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace {
+
+// MSan will do a better job detecting over-read errors if the input is not
+// nul-terminated on the heap. This will copy |input| to a new buffer owned by
+// |owner|, returning a base::StringPiece to |owner|.
+base::StringPiece MakeNotNullTerminatedInput(const char* input,
+                                             std::unique_ptr<char[]>* owner) {
+  size_t str_len = strlen(input);
+  owner->reset(new char[str_len]);
+  memcpy(owner->get(), input, str_len);
+  return base::StringPiece(owner->get(), str_len);
+}
+
+}  // namespace
 
 namespace base {
 
 TEST(JSONReaderTest, Whitespace) {
-  std::unique_ptr<Value> root = JSONReader().ReadToValue("   null   ");
+  absl::optional<Value> root = JSONReader::Read("   null   ");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_none());
 }
 
 TEST(JSONReaderTest, InvalidString) {
-  EXPECT_FALSE(JSONReader().ReadToValue("nu"));
+  // These are invalid because they do not represent a JSON value,
+  // see https://tools.ietf.org/rfc/rfc8259.txt
+  EXPECT_FALSE(JSONReader::Read(""));
+  EXPECT_FALSE(JSONReader::Read("nu"));
 }
 
 TEST(JSONReaderTest, SimpleBool) {
-  std::unique_ptr<Value> root = JSONReader().ReadToValue("true  ");
+  absl::optional<Value> root = JSONReader::Read("true  ");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_bool());
 }
 
 TEST(JSONReaderTest, EmbeddedComments) {
-  std::unique_ptr<Value> root = JSONReader().ReadToValue("/* comment */null");
+  absl::optional<Value> root = JSONReader::Read("/* comment */null");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_none());
-  root = JSONReader().ReadToValue("40 /* comment */");
+  root = JSONReader::Read("40 /* comment */");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_int());
-  root = JSONReader().ReadToValue("true // comment");
+  root = JSONReader::Read("true // comment");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_bool());
-  root = JSONReader().ReadToValue("/* comment */\"sample string\"");
+  // Comments in different contexts.
+  root = JSONReader::Read("{   \"cheese\": 3\n\n   // Here's a comment\n}");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_string());
-  std::string value;
-  EXPECT_TRUE(root->GetAsString(&value));
-  EXPECT_EQ("sample string", value);
-  std::unique_ptr<ListValue> list =
-      ListValue::From(JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]"));
-  ASSERT_TRUE(list);
-  EXPECT_EQ(2u, list->GetSize());
-  int int_val = 0;
-  EXPECT_TRUE(list->GetInteger(0, &int_val));
-  EXPECT_EQ(1, int_val);
-  EXPECT_TRUE(list->GetInteger(1, &int_val));
-  EXPECT_EQ(3, int_val);
-  list = ListValue::From(JSONReader().ReadToValue("[1, /*a*/2, 3]"));
-  ASSERT_TRUE(list);
-  EXPECT_EQ(3u, list->GetSize());
-  root = JSONReader().ReadToValue("/* comment **/42");
+  EXPECT_TRUE(root->is_dict());
+  root = JSONReader::Read("{   \"cheese\": 3// Here's a comment\n}");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_int());
-  EXPECT_TRUE(root->GetAsInteger(&int_val));
-  EXPECT_EQ(42, int_val);
-  root = JSONReader().ReadToValue(
+  EXPECT_TRUE(root->is_dict());
+  // Multiple comment markers.
+  root = JSONReader::Read(
+      "{   \"cheese\": 3// Here's a comment // and another\n}");
+  ASSERT_TRUE(root);
+  EXPECT_TRUE(root->is_dict());
+  root = JSONReader::Read("/* comment */\"sample string\"");
+  ASSERT_TRUE(root);
+  ASSERT_TRUE(root->is_string());
+  EXPECT_EQ("sample string", root->GetString());
+  root = JSONReader::Read("[1, /* comment, 2 ] */ \n 3]");
+  ASSERT_TRUE(root);
+  Value::List* list = root->GetIfList();
+  ASSERT_TRUE(list);
+  ASSERT_EQ(2u, list->size());
+  ASSERT_TRUE((*list)[0].is_int());
+  EXPECT_EQ(1, (*list)[0].GetInt());
+  ASSERT_TRUE((*list)[1].is_int());
+  EXPECT_EQ(3, (*list)[1].GetInt());
+  root = JSONReader::Read("[1, /*a*/2, 3]");
+  ASSERT_TRUE(root);
+  list = root->GetIfList();
+  ASSERT_TRUE(list);
+  EXPECT_EQ(3u, (*list).size());
+  root = JSONReader::Read("/* comment **/42");
+  ASSERT_TRUE(root);
+  ASSERT_TRUE(root->is_int());
+  EXPECT_EQ(42, root->GetInt());
+  root = JSONReader::Read(
       "/* comment **/\n"
       "// */ 43\n"
       "44");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_int());
-  EXPECT_TRUE(root->GetAsInteger(&int_val));
-  EXPECT_EQ(44, int_val);
+  EXPECT_EQ(44, root->GetInt());
+
+  // At one point, this parsed successfully as the value three.
+  EXPECT_FALSE(JSONReader::Read("/33"));
 }
 
 TEST(JSONReaderTest, Ints) {
-  std::unique_ptr<Value> root = JSONReader().ReadToValue("43");
+  absl::optional<Value> root = JSONReader::Read("43");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_int());
-  int int_val = 0;
-  EXPECT_TRUE(root->GetAsInteger(&int_val));
-  EXPECT_EQ(43, int_val);
+  ASSERT_TRUE(root->is_int());
+  EXPECT_EQ(43, root->GetInt());
 }
 
 TEST(JSONReaderTest, NonDecimalNumbers) {
-  // According to RFC4627, oct, hex, and leading zeros are invalid JSON.
-  EXPECT_FALSE(JSONReader().ReadToValue("043"));
-  EXPECT_FALSE(JSONReader().ReadToValue("0x43"));
-  EXPECT_FALSE(JSONReader().ReadToValue("00"));
+  // According to RFC 8259, oct, hex, and leading zeros are invalid JSON.
+  EXPECT_FALSE(JSONReader::Read("043"));
+  EXPECT_FALSE(JSONReader::Read("0x43"));
+  EXPECT_FALSE(JSONReader::Read("00"));
 }
 
 TEST(JSONReaderTest, NumberZero) {
   // Test 0 (which needs to be special cased because of the leading zero
   // clause).
-  std::unique_ptr<Value> root = JSONReader().ReadToValue("0");
+  absl::optional<Value> root = JSONReader::Read("0");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_int());
-  int int_val = 1;
-  EXPECT_TRUE(root->GetAsInteger(&int_val));
-  EXPECT_EQ(0, int_val);
+  ASSERT_TRUE(root->is_int());
+  EXPECT_EQ(0, root->GetInt());
 }
 
 TEST(JSONReaderTest, LargeIntPromotion) {
   // Numbers that overflow ints should succeed, being internally promoted to
   // storage as doubles
-  std::unique_ptr<Value> root = JSONReader().ReadToValue("2147483648");
-  ASSERT_TRUE(root);
-  double double_val;
-  EXPECT_TRUE(root->is_double());
-  double_val = 0.0;
-  EXPECT_TRUE(root->GetAsDouble(&double_val));
-  EXPECT_DOUBLE_EQ(2147483648.0, double_val);
-  root = JSONReader().ReadToValue("-2147483649");
+  absl::optional<Value> root = JSONReader::Read("2147483648");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_double());
-  double_val = 0.0;
-  EXPECT_TRUE(root->GetAsDouble(&double_val));
-  EXPECT_DOUBLE_EQ(-2147483649.0, double_val);
+  EXPECT_DOUBLE_EQ(2147483648.0, root->GetDouble());
+  root = JSONReader::Read("-2147483649");
+  ASSERT_TRUE(root);
+  EXPECT_TRUE(root->is_double());
+  EXPECT_DOUBLE_EQ(-2147483649.0, root->GetDouble());
+}
+
+TEST(JSONReaderTest, LargerIntIsLossy) {
+  // Parse LONG_MAX as a JSON number (not a JSON string). The result of the
+  // parse is a base::Value, either a (32-bit) int or a (64-bit) double.
+  // LONG_MAX would overflow an int and can only be approximated by a double.
+  // In this case, parsing is lossy.
+  const char* etc807 = "9223372036854775807";
+  const char* etc808 = "9223372036854775808.000000";
+  absl::optional<Value> root = JSONReader::Read(etc807);
+  ASSERT_TRUE(root);
+  ASSERT_FALSE(root->is_int());
+  ASSERT_TRUE(root->is_double());
+  // We use StringPrintf instead of NumberToString, because the NumberToString
+  // function does not let you specify the precision, and its default output,
+  // "9.223372036854776e+18", isn't precise enough to see the lossiness.
+  EXPECT_EQ(std::string(etc808), StringPrintf("%f", root->GetDouble()));
 }
 
 TEST(JSONReaderTest, Doubles) {
-  std::unique_ptr<Value> root = JSONReader().ReadToValue("43.1");
+  absl::optional<Value> root = JSONReader::Read("43.1");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_double());
-  double double_val = 0.0;
-  EXPECT_TRUE(root->GetAsDouble(&double_val));
-  EXPECT_DOUBLE_EQ(43.1, double_val);
+  EXPECT_DOUBLE_EQ(43.1, root->GetDouble());
 
-  root = JSONReader().ReadToValue("4.3e-1");
+  root = JSONReader::Read("4.3e-1");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_double());
-  double_val = 0.0;
-  EXPECT_TRUE(root->GetAsDouble(&double_val));
-  EXPECT_DOUBLE_EQ(.43, double_val);
+  EXPECT_DOUBLE_EQ(.43, root->GetDouble());
 
-  root = JSONReader().ReadToValue("2.1e0");
+  root = JSONReader::Read("2.1e0");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_double());
-  double_val = 0.0;
-  EXPECT_TRUE(root->GetAsDouble(&double_val));
-  EXPECT_DOUBLE_EQ(2.1, double_val);
+  EXPECT_DOUBLE_EQ(2.1, root->GetDouble());
 
-  root = JSONReader().ReadToValue("2.1e+0001");
+  root = JSONReader::Read("2.1e+0001");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_double());
-  double_val = 0.0;
-  EXPECT_TRUE(root->GetAsDouble(&double_val));
-  EXPECT_DOUBLE_EQ(21.0, double_val);
+  EXPECT_DOUBLE_EQ(21.0, root->GetDouble());
 
-  root = JSONReader().ReadToValue("0.01");
+  root = JSONReader::Read("0.01");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_double());
-  double_val = 0.0;
-  EXPECT_TRUE(root->GetAsDouble(&double_val));
-  EXPECT_DOUBLE_EQ(0.01, double_val);
+  EXPECT_DOUBLE_EQ(0.01, root->GetDouble());
 
-  root = JSONReader().ReadToValue("1.00");
+  root = JSONReader::Read("1.00");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_double());
-  double_val = 0.0;
-  EXPECT_TRUE(root->GetAsDouble(&double_val));
-  EXPECT_DOUBLE_EQ(1.0, double_val);
+  EXPECT_DOUBLE_EQ(1.0, root->GetDouble());
+
+  // Some "parse to float64" implementations find this one tricky.
+  // https://github.com/serde-rs/json/issues/707
+  root = JSONReader::Read("122.416294033786585");
+  ASSERT_TRUE(root);
+  EXPECT_TRUE(root->is_double());
+  EXPECT_DOUBLE_EQ(122.416294033786585, root->GetDouble());
+
+  // This is syntaxtically valid, but out of range of a double.
+  auto value =
+      JSONReader::ReadAndReturnValueWithError("1e1000", JSON_PARSE_RFC);
+  ASSERT_FALSE(value.has_value());
 }
 
 TEST(JSONReaderTest, FractionalNumbers) {
   // Fractional parts must have a digit before and after the decimal point.
-  EXPECT_FALSE(JSONReader().ReadToValue("1."));
-  EXPECT_FALSE(JSONReader().ReadToValue(".1"));
-  EXPECT_FALSE(JSONReader().ReadToValue("1.e10"));
+  EXPECT_FALSE(JSONReader::Read("1."));
+  EXPECT_FALSE(JSONReader::Read(".1"));
+  EXPECT_FALSE(JSONReader::Read("1.e10"));
 }
 
 TEST(JSONReaderTest, ExponentialNumbers) {
   // Exponent must have a digit following the 'e'.
-  EXPECT_FALSE(JSONReader().ReadToValue("1e"));
-  EXPECT_FALSE(JSONReader().ReadToValue("1E"));
-  EXPECT_FALSE(JSONReader().ReadToValue("1e1."));
-  EXPECT_FALSE(JSONReader().ReadToValue("1e1.0"));
+  EXPECT_FALSE(JSONReader::Read("1e"));
+  EXPECT_FALSE(JSONReader::Read("1E"));
+  EXPECT_FALSE(JSONReader::Read("1e1."));
+  EXPECT_FALSE(JSONReader::Read("1e1.0"));
 }
 
-TEST(JSONReaderTest, InvalidNAN) {
-  EXPECT_FALSE(JSONReader().ReadToValue("1e1000"));
-  EXPECT_FALSE(JSONReader().ReadToValue("-1e1000"));
-  EXPECT_FALSE(JSONReader().ReadToValue("NaN"));
-  EXPECT_FALSE(JSONReader().ReadToValue("nan"));
-  EXPECT_FALSE(JSONReader().ReadToValue("inf"));
+TEST(JSONReaderTest, InvalidInfNAN) {
+  // The largest finite double is roughly 1.8e308.
+  EXPECT_FALSE(JSONReader::Read("1e1000"));
+  EXPECT_FALSE(JSONReader::Read("-1e1000"));
+  EXPECT_FALSE(JSONReader::Read("NaN"));
+  EXPECT_FALSE(JSONReader::Read("nan"));
+  EXPECT_FALSE(JSONReader::Read("inf"));
 }
 
 TEST(JSONReaderTest, InvalidNumbers) {
-  EXPECT_FALSE(JSONReader().ReadToValue("4.3.1"));
-  EXPECT_FALSE(JSONReader().ReadToValue("4e3.1"));
-  EXPECT_FALSE(JSONReader().ReadToValue("4.a"));
+  EXPECT_TRUE(JSONReader::Read("4.3"));
+  EXPECT_FALSE(JSONReader::Read("4."));
+  EXPECT_FALSE(JSONReader::Read("4.3.1"));
+  EXPECT_FALSE(JSONReader::Read("4e3.1"));
+  EXPECT_FALSE(JSONReader::Read("4.a"));
+  EXPECT_FALSE(JSONReader::Read("42a"));
 }
 
-TEST(JSONReader, SimpleString) {
-  std::unique_ptr<Value> root = JSONReader().ReadToValue("\"hello world\"");
+TEST(JSONReaderTest, SimpleString) {
+  absl::optional<Value> root = JSONReader::Read("\"hello world\"");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_string());
-  std::string str_val;
-  EXPECT_TRUE(root->GetAsString(&str_val));
-  EXPECT_EQ("hello world", str_val);
+  ASSERT_TRUE(root->is_string());
+  EXPECT_EQ("hello world", root->GetString());
 }
 
 TEST(JSONReaderTest, EmptyString) {
-  std::unique_ptr<Value> root = JSONReader().ReadToValue("\"\"");
+  absl::optional<Value> root = JSONReader::Read("\"\"");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_string());
-  std::string str_val;
-  EXPECT_TRUE(root->GetAsString(&str_val));
-  EXPECT_EQ("", str_val);
+  ASSERT_TRUE(root->is_string());
+  EXPECT_EQ("", root->GetString());
 }
 
 TEST(JSONReaderTest, BasicStringEscapes) {
-  std::unique_ptr<Value> root =
-      JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\"");
+  absl::optional<Value> root =
+      JSONReader::Read("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\"");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_string());
-  std::string str_val;
-  EXPECT_TRUE(root->GetAsString(&str_val));
-  EXPECT_EQ(" \"\\/\b\f\n\r\t\v", str_val);
+  ASSERT_TRUE(root->is_string());
+  EXPECT_EQ(" \"\\/\b\f\n\r\t\v", root->GetString());
 }
 
 TEST(JSONReaderTest, UnicodeEscapes) {
   // Test hex and unicode escapes including the null character.
-  std::unique_ptr<Value> root =
-      JSONReader().ReadToValue("\"\\x41\\x00\\u1234\\u0000\"");
+  absl::optional<Value> root =
+      JSONReader::Read("\"\\x41\\xFF\\x00\\u1234\\u0000\"");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_string());
-  std::string str_val;
-  EXPECT_TRUE(root->GetAsString(&str_val));
-  EXPECT_EQ(std::wstring(L"A\0\x1234\0", 4), UTF8ToWide(str_val));
+  ASSERT_TRUE(root->is_string());
+  const std::string& str_val = root->GetString();
+  EXPECT_EQ(std::wstring(L"A\x00FF\0\x1234\0", 5), UTF8ToWide(str_val));
+
+  // The contents of a Unicode escape may only be four hex chars. Previously the
+  // parser accepted things like "0x01" and "0X01".
+  EXPECT_FALSE(JSONReader::Read("\"\\u0x12\""));
+
+  // Surrogate pairs are allowed in JSON.
+  EXPECT_TRUE(JSONReader::Read("\"\\uD834\\uDD1E\""));  // U+1D11E
 }
 
 TEST(JSONReaderTest, InvalidStrings) {
-  EXPECT_FALSE(JSONReader().ReadToValue("\"no closing quote"));
-  EXPECT_FALSE(JSONReader().ReadToValue("\"\\z invalid escape char\""));
-  EXPECT_FALSE(JSONReader().ReadToValue("\"\\xAQ invalid hex code\""));
-  EXPECT_FALSE(JSONReader().ReadToValue("not enough hex chars\\x1\""));
-  EXPECT_FALSE(JSONReader().ReadToValue("\"not enough escape chars\\u123\""));
-  EXPECT_FALSE(
-      JSONReader().ReadToValue("\"extra backslash at end of input\\\""));
+  EXPECT_FALSE(JSONReader::Read("\"no closing quote"));
+  EXPECT_FALSE(JSONReader::Read("\"\\z invalid escape char\""));
+  EXPECT_FALSE(JSONReader::Read("\"\\xAQ invalid hex code\""));
+  EXPECT_FALSE(JSONReader::Read("not enough hex chars\\x1\""));
+  EXPECT_FALSE(JSONReader::Read("\"not enough escape chars\\u123\""));
+  EXPECT_FALSE(JSONReader::Read("\"extra backslash at end of input\\\""));
 }
 
 TEST(JSONReaderTest, BasicArray) {
-  std::unique_ptr<ListValue> list =
-      ListValue::From(JSONReader::Read("[true, false, null]"));
+  absl::optional<Value> root = JSONReader::Read("[true, false, null]");
+  ASSERT_TRUE(root);
+  Value::List* list = root->GetIfList();
   ASSERT_TRUE(list);
-  EXPECT_EQ(3U, list->GetSize());
+  EXPECT_EQ(3U, list->size());
 
   // Test with trailing comma.  Should be parsed the same as above.
-  std::unique_ptr<Value> root2 =
+  absl::optional<Value> root2 =
       JSONReader::Read("[true, false, null, ]", JSON_ALLOW_TRAILING_COMMAS);
-  EXPECT_TRUE(list->Equals(root2.get()));
+  ASSERT_TRUE(root2);
+  EXPECT_EQ(*list, *root2);
 }
 
 TEST(JSONReaderTest, EmptyArray) {
-  std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read("[]"));
+  absl::optional<Value> value = JSONReader::Read("[]");
+  ASSERT_TRUE(value);
+  Value::List* list = value->GetIfList();
   ASSERT_TRUE(list);
-  EXPECT_EQ(0U, list->GetSize());
+  EXPECT_TRUE(list->empty());
+}
+
+TEST(JSONReaderTest, CompleteArray) {
+  absl::optional<Value> value = JSONReader::Read("[\"a\", 3, 4.56, null]");
+  ASSERT_TRUE(value);
+  Value::List* list = value->GetIfList();
+  ASSERT_TRUE(list);
+  EXPECT_EQ(4U, list->size());
 }
 
 TEST(JSONReaderTest, NestedArrays) {
-  std::unique_ptr<ListValue> list = ListValue::From(
-      JSONReader::Read("[[true], [], [false, [], [null]], null]"));
+  absl::optional<Value> value = JSONReader::Read(
+      "[[true], [], {\"smell\": \"nice\",\"taste\": \"yummy\" }, [false, [], "
+      "[null]], null]");
+  ASSERT_TRUE(value);
+  Value::List* list = value->GetIfList();
   ASSERT_TRUE(list);
-  EXPECT_EQ(4U, list->GetSize());
+  EXPECT_EQ(5U, list->size());
 
   // Lots of trailing commas.
-  std::unique_ptr<Value> root2 =
-      JSONReader::Read("[[true], [], [false, [], [null, ]  , ], null,]",
-                       JSON_ALLOW_TRAILING_COMMAS);
-  EXPECT_TRUE(list->Equals(root2.get()));
+  absl::optional<Value> root2 = JSONReader::Read(
+      "[[true], [], {\"smell\": \"nice\",\"taste\": \"yummy\" }, [false, [], "
+      "[null, ]  , ], null,]",
+      JSON_ALLOW_TRAILING_COMMAS);
+  ASSERT_TRUE(root2);
+  EXPECT_EQ(*list, *root2);
 }
 
 TEST(JSONReaderTest, InvalidArrays) {
@@ -294,16 +355,15 @@
 
 TEST(JSONReaderTest, ArrayTrailingComma) {
   // Valid if we set |allow_trailing_comma| to true.
-  std::unique_ptr<ListValue> list =
-      ListValue::From(JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS));
+  absl::optional<Value> value =
+      JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS);
+  ASSERT_TRUE(value);
+  Value::List* list = value->GetIfList();
   ASSERT_TRUE(list);
-  EXPECT_EQ(1U, list->GetSize());
-  Value* tmp_value = nullptr;
-  ASSERT_TRUE(list->Get(0, &tmp_value));
-  EXPECT_TRUE(tmp_value->is_bool());
-  bool bool_value = false;
-  EXPECT_TRUE(tmp_value->GetAsBoolean(&bool_value));
-  EXPECT_TRUE(bool_value);
+  ASSERT_EQ(1U, list->size());
+  const Value& value1 = (*list)[0];
+  ASSERT_TRUE(value1.is_bool());
+  EXPECT_TRUE(value1.GetBool());
 }
 
 TEST(JSONReaderTest, ArrayTrailingCommaNoEmptyElements) {
@@ -316,30 +376,39 @@
 }
 
 TEST(JSONReaderTest, EmptyDictionary) {
-  std::unique_ptr<DictionaryValue> dict_val =
-      DictionaryValue::From(JSONReader::Read("{}"));
+  absl::optional<Value> dict_val = JSONReader::Read("{}");
   ASSERT_TRUE(dict_val);
+  ASSERT_TRUE(dict_val->is_dict());
 }
 
 TEST(JSONReaderTest, CompleteDictionary) {
-  auto dict_val = DictionaryValue::From(JSONReader::Read(
-      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }"));
-  ASSERT_TRUE(dict_val);
-  double double_val = 0.0;
-  EXPECT_TRUE(dict_val->GetDouble("number", &double_val));
-  EXPECT_DOUBLE_EQ(9.87654321, double_val);
-  Value* null_val = nullptr;
-  ASSERT_TRUE(dict_val->Get("null", &null_val));
+  absl::optional<Value> root1 = JSONReader::Read(
+      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", \"bool\": "
+      "false, \"more\": {} }");
+  ASSERT_TRUE(root1);
+  const Value::Dict* root1_dict = root1->GetIfDict();
+  ASSERT_TRUE(root1_dict);
+  auto double_val = root1_dict->FindDouble("number");
+  ASSERT_TRUE(double_val);
+  EXPECT_DOUBLE_EQ(9.87654321, *double_val);
+  const Value* null_val = root1_dict->Find("null");
+  ASSERT_TRUE(null_val);
   EXPECT_TRUE(null_val->is_none());
-  std::string str_val;
-  EXPECT_TRUE(dict_val->GetString("S", &str_val));
-  EXPECT_EQ("str", str_val);
+  const std::string* str_val = root1_dict->FindString("S");
+  ASSERT_TRUE(str_val);
+  EXPECT_EQ("str", *str_val);
+  auto bool_val = root1_dict->FindBool("bool");
+  ASSERT_TRUE(bool_val);
+  ASSERT_FALSE(*bool_val);
 
-  std::unique_ptr<Value> root2 = JSONReader::Read(
-      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }",
-      JSON_ALLOW_TRAILING_COMMAS);
+  absl::optional<Value> root2 = JSONReader::Read(
+      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", \"bool\": "
+      "false, \"more\": {},}",
+      JSON_PARSE_CHROMIUM_EXTENSIONS | JSON_ALLOW_TRAILING_COMMAS);
   ASSERT_TRUE(root2);
-  EXPECT_TRUE(dict_val->Equals(root2.get()));
+  Value::Dict* root2_dict = root2->GetIfDict();
+  ASSERT_TRUE(root2_dict);
+  EXPECT_EQ(*root1_dict, *root2_dict);
 
   // Test newline equivalence.
   root2 = JSONReader::Read(
@@ -347,68 +416,96 @@
       "  \"number\":9.87654321,\n"
       "  \"null\":null,\n"
       "  \"\\x53\":\"str\",\n"
+      "  \"bool\": false,\n"
+      "  \"more\": {},\n"
       "}\n",
-      JSON_ALLOW_TRAILING_COMMAS);
+      JSON_PARSE_CHROMIUM_EXTENSIONS | JSON_ALLOW_TRAILING_COMMAS);
   ASSERT_TRUE(root2);
-  EXPECT_TRUE(dict_val->Equals(root2.get()));
+  root2_dict = root2->GetIfDict();
+  ASSERT_TRUE(root2);
+  EXPECT_EQ(*root1_dict, *root2_dict);
 
   root2 = JSONReader::Read(
       "{\r\n"
       "  \"number\":9.87654321,\r\n"
       "  \"null\":null,\r\n"
       "  \"\\x53\":\"str\",\r\n"
+      "  \"bool\": false,\r\n"
+      "  \"more\": {},\r\n"
       "}\r\n",
-      JSON_ALLOW_TRAILING_COMMAS);
+      JSON_PARSE_CHROMIUM_EXTENSIONS | JSON_ALLOW_TRAILING_COMMAS);
   ASSERT_TRUE(root2);
-  EXPECT_TRUE(dict_val->Equals(root2.get()));
+  root2_dict = root2->GetIfDict();
+  ASSERT_TRUE(root2_dict);
+  EXPECT_EQ(*root1_dict, *root2_dict);
 }
 
 TEST(JSONReaderTest, NestedDictionaries) {
-  std::unique_ptr<DictionaryValue> dict_val =
-      DictionaryValue::From(JSONReader::Read(
-          "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}"));
-  ASSERT_TRUE(dict_val);
-  DictionaryValue* inner_dict = nullptr;
-  ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict));
-  ListValue* inner_array = nullptr;
-  ASSERT_TRUE(inner_dict->GetList("array", &inner_array));
-  EXPECT_EQ(1U, inner_array->GetSize());
-  bool bool_value = true;
-  EXPECT_TRUE(dict_val->GetBoolean("false", &bool_value));
-  EXPECT_FALSE(bool_value);
-  inner_dict = nullptr;
-  EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict));
+  absl::optional<Value> root1 = JSONReader::Read(
+      "{\"inner\":{\"array\":[true, 3, 4.56, null]},\"false\":false,\"d\":{}}");
+  ASSERT_TRUE(root1);
+  const base::Value::Dict* root1_dict = root1->GetIfDict();
+  ASSERT_TRUE(root1_dict);
+  const Value::Dict* inner_dict = root1_dict->FindDict("inner");
+  ASSERT_TRUE(inner_dict);
+  const Value::List* inner_array = inner_dict->FindList("array");
+  ASSERT_TRUE(inner_array);
+  EXPECT_EQ(4U, inner_array->size());
+  auto bool_value = root1_dict->FindBool("false");
+  ASSERT_TRUE(bool_value);
+  EXPECT_FALSE(*bool_value);
+  inner_dict = root1_dict->FindDict("d");
+  EXPECT_TRUE(inner_dict);
 
-  std::unique_ptr<Value> root2 = JSONReader::Read(
-      "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}",
+  absl::optional<Value> root2 = JSONReader::Read(
+      "{\"inner\": {\"array\":[true, 3, 4.56, null] , "
+      "},\"false\":false,\"d\":{},}",
       JSON_ALLOW_TRAILING_COMMAS);
-  EXPECT_TRUE(dict_val->Equals(root2.get()));
+  ASSERT_TRUE(root2);
+  EXPECT_EQ(*root1_dict, *root2);
 }
 
 TEST(JSONReaderTest, DictionaryKeysWithPeriods) {
-  std::unique_ptr<DictionaryValue> dict_val = DictionaryValue::From(
-      JSONReader::Read("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}"));
-  ASSERT_TRUE(dict_val);
-  int integer_value = 0;
-  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value));
-  EXPECT_EQ(3, integer_value);
-  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("c", &integer_value));
-  EXPECT_EQ(2, integer_value);
-  DictionaryValue* inner_dict = nullptr;
-  ASSERT_TRUE(
-      dict_val->GetDictionaryWithoutPathExpansion("d.e.f", &inner_dict));
-  EXPECT_EQ(1U, inner_dict->size());
-  EXPECT_TRUE(
-      inner_dict->GetIntegerWithoutPathExpansion("g.h.i.j", &integer_value));
-  EXPECT_EQ(1, integer_value);
+  absl::optional<Value> root =
+      JSONReader::Read("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}");
+  ASSERT_TRUE(root);
+  Value::Dict* root_dict = root->GetIfDict();
+  ASSERT_TRUE(root_dict);
 
-  dict_val =
-      DictionaryValue::From(JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}"));
-  ASSERT_TRUE(dict_val);
-  EXPECT_TRUE(dict_val->GetInteger("a.b", &integer_value));
-  EXPECT_EQ(2, integer_value);
-  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value));
-  EXPECT_EQ(1, integer_value);
+  auto integer_value = root_dict->FindInt("a.b");
+  ASSERT_TRUE(integer_value);
+  EXPECT_EQ(3, *integer_value);
+  integer_value = root_dict->FindInt("c");
+  ASSERT_TRUE(integer_value);
+  EXPECT_EQ(2, *integer_value);
+  const Value::Dict* inner_dict = root_dict->FindDict("d.e.f");
+  ASSERT_TRUE(inner_dict);
+  EXPECT_EQ(1U, inner_dict->size());
+  integer_value = inner_dict->FindInt("g.h.i.j");
+  ASSERT_TRUE(integer_value);
+  EXPECT_EQ(1, *integer_value);
+
+  root = JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}");
+  ASSERT_TRUE(root);
+  root_dict = root->GetIfDict();
+  ASSERT_TRUE(root_dict);
+  const Value* integer_path_value = root_dict->FindByDottedPath("a.b");
+  ASSERT_TRUE(integer_path_value);
+  EXPECT_EQ(2, integer_path_value->GetInt());
+  integer_value = root_dict->FindInt("a.b");
+  ASSERT_TRUE(integer_value);
+  EXPECT_EQ(1, *integer_value);
+}
+
+TEST(JSONReaderTest, DuplicateKeys) {
+  absl::optional<Value> root = JSONReader::Read("{\"x\":1,\"x\":2,\"y\":3}");
+  ASSERT_TRUE(root);
+  const Value::Dict* root_dict = root->GetIfDict();
+  ASSERT_TRUE(root_dict);
+
+  auto integer_value = root_dict->FindInt("x");
+  ASSERT_TRUE(integer_value);
+  EXPECT_EQ(2, *integer_value);
 }
 
 TEST(JSONReaderTest, InvalidDictionaries) {
@@ -419,6 +516,7 @@
   EXPECT_FALSE(JSONReader::Read("{foo:true}"));
   EXPECT_FALSE(JSONReader::Read("{1234: false}"));
   EXPECT_FALSE(JSONReader::Read("{:false}"));
+  EXPECT_FALSE(JSONReader::Read("{ , }"));
 
   // Trailing comma.
   EXPECT_FALSE(JSONReader::Read("{\"a\":true,}"));
@@ -451,51 +549,96 @@
   for (int i = 0; i < 5000; ++i)
     not_evil.append("[],");
   not_evil.append("[]]");
-  std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read(not_evil));
+  absl::optional<Value> value = JSONReader::Read(not_evil);
+  ASSERT_TRUE(value);
+  Value::List* list = value->GetIfList();
   ASSERT_TRUE(list);
-  EXPECT_EQ(5001U, list->GetSize());
+  EXPECT_EQ(5001U, list->size());
 }
 
 TEST(JSONReaderTest, UTF8Input) {
-  std::unique_ptr<Value> root =
-      JSONReader().ReadToValue("\"\xe7\xbd\x91\xe9\xa1\xb5\"");
+  absl::optional<Value> root = JSONReader::Read("\"\xe7\xbd\x91\xe9\xa1\xb5\"");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_string());
-  std::string str_val;
-  EXPECT_TRUE(root->GetAsString(&str_val));
+  ASSERT_TRUE(root->is_string());
+  const std::string& str_val = root->GetString();
   EXPECT_EQ(L"\x7f51\x9875", UTF8ToWide(str_val));
 
-  std::unique_ptr<DictionaryValue> dict_val =
-      DictionaryValue::From(JSONReader().ReadToValue(
-          "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}"));
-  ASSERT_TRUE(dict_val);
-  EXPECT_TRUE(dict_val->GetString("path", &str_val));
-  EXPECT_EQ("/tmp/\xC3\xA0\xC3\xA8\xC3\xB2.png", str_val);
+  root = JSONReader::Read("{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}");
+  ASSERT_TRUE(root);
+  const Value::Dict* root_dict = root->GetIfDict();
+  ASSERT_TRUE(root_dict);
+  const std::string* maybe_string = root_dict->FindString("path");
+  ASSERT_TRUE(maybe_string);
+  EXPECT_EQ("/tmp/\xC3\xA0\xC3\xA8\xC3\xB2.png", *maybe_string);
+
+  // JSON can encode non-characters.
+  const char* const noncharacters[] = {
+      "\"\xEF\xB7\x90\"",      // U+FDD0
+      "\"\xEF\xB7\x9F\"",      // U+FDDF
+      "\"\xEF\xB7\xAF\"",      // U+FDEF
+      "\"\xEF\xBF\xBE\"",      // U+FFFE
+      "\"\xEF\xBF\xBF\"",      // U+FFFF
+      "\"\xF0\x9F\xBF\xBE\"",  // U+01FFFE
+      "\"\xF0\x9F\xBF\xBF\"",  // U+01FFFF
+      "\"\xF0\xAF\xBF\xBE\"",  // U+02FFFE
+      "\"\xF0\xAF\xBF\xBF\"",  // U+02FFFF
+      "\"\xF0\xBF\xBF\xBE\"",  // U+03FFFE
+      "\"\xF0\xBF\xBF\xBF\"",  // U+03FFFF
+      "\"\xF1\x8F\xBF\xBE\"",  // U+04FFFE
+      "\"\xF1\x8F\xBF\xBF\"",  // U+04FFFF
+      "\"\xF1\x9F\xBF\xBE\"",  // U+05FFFE
+      "\"\xF1\x9F\xBF\xBF\"",  // U+05FFFF
+      "\"\xF1\xAF\xBF\xBE\"",  // U+06FFFE
+      "\"\xF1\xAF\xBF\xBF\"",  // U+06FFFF
+      "\"\xF1\xBF\xBF\xBE\"",  // U+07FFFE
+      "\"\xF1\xBF\xBF\xBF\"",  // U+07FFFF
+      "\"\xF2\x8F\xBF\xBE\"",  // U+08FFFE
+      "\"\xF2\x8F\xBF\xBF\"",  // U+08FFFF
+      "\"\xF2\x9F\xBF\xBE\"",  // U+09FFFE
+      "\"\xF2\x9F\xBF\xBF\"",  // U+09FFFF
+      "\"\xF2\xAF\xBF\xBE\"",  // U+0AFFFE
+      "\"\xF2\xAF\xBF\xBF\"",  // U+0AFFFF
+      "\"\xF2\xBF\xBF\xBE\"",  // U+0BFFFE
+      "\"\xF2\xBF\xBF\xBF\"",  // U+0BFFFF
+      "\"\xF3\x8F\xBF\xBE\"",  // U+0CFFFE
+      "\"\xF3\x8F\xBF\xBF\"",  // U+0CFFFF
+      "\"\xF3\x9F\xBF\xBE\"",  // U+0DFFFE
+      "\"\xF3\x9F\xBF\xBF\"",  // U+0DFFFF
+      "\"\xF3\xAF\xBF\xBE\"",  // U+0EFFFE
+      "\"\xF3\xAF\xBF\xBF\"",  // U+0EFFFF
+      "\"\xF3\xBF\xBF\xBE\"",  // U+0FFFFE
+      "\"\xF3\xBF\xBF\xBF\"",  // U+0FFFFF
+      "\"\xF4\x8F\xBF\xBE\"",  // U+10FFFE
+      "\"\xF4\x8F\xBF\xBF\"",  // U+10FFFF
+  };
+  for (auto* noncharacter : noncharacters) {
+    root = JSONReader::Read(noncharacter);
+    ASSERT_TRUE(root);
+    ASSERT_TRUE(root->is_string());
+    EXPECT_EQ(std::string(noncharacter + 1, strlen(noncharacter) - 2),
+              root->GetString());
+  }
 }
 
 TEST(JSONReaderTest, InvalidUTF8Input) {
-  EXPECT_FALSE(JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\""));
-  EXPECT_FALSE(JSONReader().ReadToValue("\"123\xc0\x81\""));
-  EXPECT_FALSE(JSONReader().ReadToValue("\"abc\xc0\xae\""));
+  EXPECT_FALSE(JSONReader::Read("\"345\xb0\xa1\xb0\xa2\""));
+  EXPECT_FALSE(JSONReader::Read("\"123\xc0\x81\""));
+  EXPECT_FALSE(JSONReader::Read("\"abc\xc0\xae\""));
 }
 
 TEST(JSONReaderTest, UTF16Escapes) {
-  std::unique_ptr<Value> root = JSONReader().ReadToValue("\"\\u20ac3,14\"");
+  absl::optional<Value> root = JSONReader::Read("\"\\u20ac3,14\"");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_string());
-  std::string str_val;
-  EXPECT_TRUE(root->GetAsString(&str_val));
+  ASSERT_TRUE(root->is_string());
   EXPECT_EQ(
       "\xe2\x82\xac"
       "3,14",
-      str_val);
+      root->GetString());
 
-  root = JSONReader().ReadToValue("\"\\ud83d\\udca9\\ud83d\\udc6c\"");
+  root = JSONReader::Read("\"\\ud83d\\udca9\\ud83d\\udc6c\"");
   ASSERT_TRUE(root);
-  EXPECT_TRUE(root->is_string());
-  str_val.clear();
-  EXPECT_TRUE(root->GetAsString(&str_val));
-  EXPECT_EQ("\xf0\x9f\x92\xa9\xf0\x9f\x91\xac", str_val);
+  ASSERT_TRUE(root->is_string());
+  EXPECT_EQ("\xf0\x9f\x92\xa9\xf0\x9f\x91\xac", root->GetString());
 }
 
 TEST(JSONReaderTest, InvalidUTF16Escapes) {
@@ -506,42 +649,39 @@
       "\"\\uzz89\"",         // Invalid scalar.
       "\"\\ud83d\\udca\"",   // Invalid lower surrogate.
       "\"\\ud83d\\ud83d\"",  // Invalid lower surrogate.
-      "\"\\ud83d\\uaaaZ\""   // Invalid lower surrogate.
+      "\"\\ud83d\\uaaaZ\"",  // Invalid lower surrogate.
       "\"\\ud83foo\"",       // No lower surrogate.
-      "\"\\ud83d\\foo\""     // No lower surrogate.
-      "\"\\ud83\\foo\""      // Invalid upper surrogate.
-      "\"\\ud83d\\u1\""      // No lower surrogate.
-      "\"\\ud83\\u1\""       // Invalid upper surrogate.
+      "\"\\ud83d\\foo\"",    // No lower surrogate.
+      "\"\\ud83\\foo\"",     // Invalid upper surrogate.
+      "\"\\ud83d\\u1\"",     // No lower surrogate.
+      "\"\\ud83\\u1\"",      // Invalid upper surrogate.
   };
-  std::unique_ptr<Value> root;
-  for (size_t i = 0; i < arraysize(cases); ++i) {
-    root = JSONReader().ReadToValue(cases[i]);
-    EXPECT_FALSE(root) << cases[i];
+  absl::optional<Value> root;
+  for (auto* i : cases) {
+    root = JSONReader::Read(i);
+    EXPECT_FALSE(root) << i;
   }
 }
 
 TEST(JSONReaderTest, LiteralRoots) {
-  std::unique_ptr<Value> root = JSONReader::Read("null");
+  absl::optional<Value> root = JSONReader::Read("null");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_none());
 
   root = JSONReader::Read("true");
   ASSERT_TRUE(root);
-  bool bool_value;
-  EXPECT_TRUE(root->GetAsBoolean(&bool_value));
-  EXPECT_TRUE(bool_value);
+  ASSERT_TRUE(root->is_bool());
+  EXPECT_TRUE(root->GetBool());
 
   root = JSONReader::Read("10");
   ASSERT_TRUE(root);
-  int integer_value;
-  EXPECT_TRUE(root->GetAsInteger(&integer_value));
-  EXPECT_EQ(10, integer_value);
+  ASSERT_TRUE(root->is_int());
+  EXPECT_EQ(10, root->GetInt());
 
   root = JSONReader::Read("\"root\"");
   ASSERT_TRUE(root);
-  std::string str_val;
-  EXPECT_TRUE(root->GetAsString(&str_val));
-  EXPECT_EQ("root", str_val);
+  ASSERT_TRUE(root->is_string());
+  EXPECT_EQ("root", root->GetString());
 }
 
 TEST(JSONReaderTest, ReadFromFile) {
@@ -558,24 +698,23 @@
   std::string input;
   ASSERT_TRUE(ReadFileToString(path.AppendASCII("bom_feff.json"), &input));
 
-  JSONReader reader;
-  std::unique_ptr<Value> root(reader.ReadToValue(input));
-  ASSERT_TRUE(root) << reader.GetErrorMessage();
+  auto root = JSONReader::ReadAndReturnValueWithError(input);
+  ASSERT_TRUE(root.has_value()) << root.error().message;
   EXPECT_TRUE(root->is_dict());
 }
 
 // Tests that the root of a JSON object can be deleted safely while its
 // children outlive it.
 TEST(JSONReaderTest, StringOptimizations) {
-  std::unique_ptr<Value> dict_literal_0;
-  std::unique_ptr<Value> dict_literal_1;
-  std::unique_ptr<Value> dict_string_0;
-  std::unique_ptr<Value> dict_string_1;
-  std::unique_ptr<Value> list_value_0;
-  std::unique_ptr<Value> list_value_1;
+  Value dict_literal_0;
+  Value dict_literal_1;
+  Value dict_string_0;
+  Value dict_string_1;
+  Value list_value_0;
+  Value list_value_1;
 
   {
-    std::unique_ptr<Value> root = JSONReader::Read(
+    absl::optional<Value> root = JSONReader::Read(
         "{"
         "  \"test\": {"
         "    \"foo\": true,"
@@ -590,46 +729,53 @@
         "}",
         JSON_PARSE_RFC);
     ASSERT_TRUE(root);
+    Value::Dict* root_dict = root->GetIfDict();
+    ASSERT_TRUE(root_dict);
 
-    DictionaryValue* root_dict = nullptr;
-    ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+    Value::Dict* dict = root_dict->FindDict("test");
+    ASSERT_TRUE(dict);
+    Value::List* list = root_dict->FindList("list");
+    ASSERT_TRUE(list);
 
-    DictionaryValue* dict = nullptr;
-    ListValue* list = nullptr;
+    Value* to_move = dict->Find("foo");
+    ASSERT_TRUE(to_move);
+    dict_literal_0 = std::move(*to_move);
+    to_move = dict->Find("bar");
+    ASSERT_TRUE(to_move);
+    dict_literal_1 = std::move(*to_move);
+    to_move = dict->Find("baz");
+    ASSERT_TRUE(to_move);
+    dict_string_0 = std::move(*to_move);
+    to_move = dict->Find("moo");
+    ASSERT_TRUE(to_move);
+    dict_string_1 = std::move(*to_move);
+    ASSERT_TRUE(dict->Remove("foo"));
+    ASSERT_TRUE(dict->Remove("bar"));
+    ASSERT_TRUE(dict->Remove("baz"));
+    ASSERT_TRUE(dict->Remove("moo"));
 
-    ASSERT_TRUE(root_dict->GetDictionary("test", &dict));
-    ASSERT_TRUE(root_dict->GetList("list", &list));
-
-    ASSERT_TRUE(dict->Remove("foo", &dict_literal_0));
-    ASSERT_TRUE(dict->Remove("bar", &dict_literal_1));
-    ASSERT_TRUE(dict->Remove("baz", &dict_string_0));
-    ASSERT_TRUE(dict->Remove("moo", &dict_string_1));
-
-    ASSERT_EQ(2u, list->GetSize());
-    ASSERT_TRUE(list->Remove(0, &list_value_0));
-    ASSERT_TRUE(list->Remove(0, &list_value_1));
+    ASSERT_EQ(2u, list->size());
+    list_value_0 = std::move((*list)[0]);
+    list_value_1 = std::move((*list)[1]);
+    list->clear();
   }
 
-  bool b = false;
-  double d = 0;
-  std::string s;
+  ASSERT_TRUE(dict_literal_0.is_bool());
+  EXPECT_TRUE(dict_literal_0.GetBool());
 
-  EXPECT_TRUE(dict_literal_0->GetAsBoolean(&b));
-  EXPECT_TRUE(b);
+  ASSERT_TRUE(dict_literal_1.is_double());
+  EXPECT_EQ(3.14, dict_literal_1.GetDouble());
 
-  EXPECT_TRUE(dict_literal_1->GetAsDouble(&d));
-  EXPECT_EQ(3.14, d);
+  ASSERT_TRUE(dict_string_0.is_string());
+  EXPECT_EQ("bat", dict_string_0.GetString());
 
-  EXPECT_TRUE(dict_string_0->GetAsString(&s));
-  EXPECT_EQ("bat", s);
+  ASSERT_TRUE(dict_string_1.is_string());
+  EXPECT_EQ("cow", dict_string_1.GetString());
 
-  EXPECT_TRUE(dict_string_1->GetAsString(&s));
-  EXPECT_EQ("cow", s);
-
-  EXPECT_TRUE(list_value_0->GetAsString(&s));
-  EXPECT_EQ("a", s);
-  EXPECT_TRUE(list_value_1->GetAsString(&s));
-  EXPECT_EQ("b", s);
+  ASSERT_TRUE(list_value_0.is_string());
+  EXPECT_EQ("a", list_value_0.GetString());
+  ASSERT_TRUE(list_value_1.is_string());
+  EXPECT_EQ("b", list_value_1.GetString());
 }
 
 // A smattering of invalid JSON designed to test specific portions of the
@@ -640,30 +786,325 @@
       "/* test *", "{\"foo\"", "{\"foo\":", "  [", "\"\\u123g\"", "{\n\"eh:\n}",
   };
 
-  for (size_t i = 0; i < arraysize(kInvalidJson); ++i) {
-    JSONReader reader;
+  for (size_t i = 0; i < std::size(kInvalidJson); ++i) {
     LOG(INFO) << "Sanity test " << i << ": <" << kInvalidJson[i] << ">";
-    EXPECT_FALSE(reader.ReadToValue(kInvalidJson[i]));
-    EXPECT_NE(JSONReader::JSON_NO_ERROR, reader.error_code());
-    EXPECT_NE("", reader.GetErrorMessage());
+    auto root = JSONReader::ReadAndReturnValueWithError(kInvalidJson[i]);
+    EXPECT_FALSE(root.has_value());
+    EXPECT_NE("", root.error().message);
   }
 }
 
 TEST(JSONReaderTest, IllegalTrailingNull) {
-  const char json[] = { '"', 'n', 'u', 'l', 'l', '"', '\0' };
+  const char json[] = {'"', 'n', 'u', 'l', 'l', '"', '\0'};
   std::string json_string(json, sizeof(json));
-  JSONReader reader;
-  EXPECT_FALSE(reader.ReadToValue(json_string));
-  EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, reader.error_code());
+  auto root = JSONReader::ReadAndReturnValueWithError(json_string);
+  EXPECT_FALSE(root.has_value());
+  EXPECT_NE("", root.error().message);
+}
+
+TEST(JSONReaderTest, ASCIIControlCodes) {
+  // A literal NUL byte or a literal new line, in a JSON string, should be
+  // rejected. RFC 8259 section 7 says "the characters that MUST be escaped
+  // [include]... the control characters (U+0000 through U+001F)".
+  //
+  // Nonetheless, we accept them, for backwards compatibility.
+  const char json[] = {'"', 'a', '\0', 'b', '\n', 'c', '"'};
+  absl::optional<Value> root =
+      JSONReader::Read(std::string(json, sizeof(json)));
+  ASSERT_TRUE(root);
+  ASSERT_TRUE(root->is_string());
+  EXPECT_EQ(5u, root->GetString().length());
 }
 
 TEST(JSONReaderTest, MaxNesting) {
   std::string json(R"({"outer": { "inner": {"foo": true}}})");
-  std::unique_ptr<Value> root;
-  root = JSONReader::Read(json, JSON_PARSE_RFC, 3);
-  ASSERT_FALSE(root);
-  root = JSONReader::Read(json, JSON_PARSE_RFC, 4);
+  EXPECT_FALSE(JSONReader::Read(json, JSON_PARSE_RFC, 3));
+  EXPECT_TRUE(JSONReader::Read(json, JSON_PARSE_RFC, 4));
+}
+
+TEST(JSONReaderTest, Decode4ByteUtf8Char) {
+  // kUtf8Data contains a 4 byte unicode character (a smiley!) that JSONReader
+  // should be able to handle. The UTF-8 encoding of U+1F607 SMILING FACE WITH
+  // HALO is "\xF0\x9F\x98\x87".
+  const char kUtf8Data[] = "[\"😇\",[],[],[],{\"google:suggesttype\":[]}]";
+  absl::optional<Value> root = JSONReader::Read(kUtf8Data, JSON_PARSE_RFC);
   ASSERT_TRUE(root);
+  Value::List* list = root->GetIfList();
+  ASSERT_TRUE(list);
+  ASSERT_EQ(5u, list->size());
+  ASSERT_TRUE((*list)[0].is_string());
+  EXPECT_EQ("\xF0\x9F\x98\x87", (*list)[0].GetString());
+}
+
+TEST(JSONReaderTest, DecodeUnicodeNonCharacter) {
+  // Tests Unicode code points (encoded as escaped UTF-16) that are not valid
+  // characters.
+  EXPECT_TRUE(JSONReader::Read("[\"\\uFDD0\"]"));         // U+FDD0
+  EXPECT_TRUE(JSONReader::Read("[\"\\uFDDF\"]"));         // U+FDDF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uFDEF\"]"));         // U+FDEF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uFFFE\"]"));         // U+FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uFFFF\"]"));         // U+FFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD83F\\uDFFE\"]"));  // U+01FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD83F\\uDFFF\"]"));  // U+01FFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD87F\\uDFFE\"]"));  // U+02FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD87F\\uDFFF\"]"));  // U+02FFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD8BF\\uDFFE\"]"));  // U+03FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD8BF\\uDFFF\"]"));  // U+03FFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD8FF\\uDFFE\"]"));  // U+04FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD8FF\\uDFFF\"]"));  // U+04FFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD93F\\uDFFE\"]"));  // U+05FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD93F\\uDFFF\"]"));  // U+05FFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD97F\\uDFFE\"]"));  // U+06FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD97F\\uDFFF\"]"));  // U+06FFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD9BF\\uDFFE\"]"));  // U+07FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD9BF\\uDFFF\"]"));  // U+07FFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD9FF\\uDFFE\"]"));  // U+08FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uD9FF\\uDFFF\"]"));  // U+08FFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDA3F\\uDFFE\"]"));  // U+09FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDA3F\\uDFFF\"]"));  // U+09FFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDA7F\\uDFFE\"]"));  // U+0AFFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDA7F\\uDFFF\"]"));  // U+0AFFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDABF\\uDFFE\"]"));  // U+0BFFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDABF\\uDFFF\"]"));  // U+0BFFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDAFF\\uDFFE\"]"));  // U+0CFFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDAFF\\uDFFF\"]"));  // U+0CFFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDB3F\\uDFFE\"]"));  // U+0DFFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDB3F\\uDFFF\"]"));  // U+0DFFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDB7F\\uDFFE\"]"));  // U+0EFFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDB7F\\uDFFF\"]"));  // U+0EFFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDBBF\\uDFFE\"]"));  // U+0FFFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDBBF\\uDFFF\"]"));  // U+0FFFFF
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDBFF\\uDFFE\"]"));  // U+10FFFE
+  EXPECT_TRUE(JSONReader::Read("[\"\\uDBFF\\uDFFF\"]"));  // U+10FFFF
+}
+
+TEST(JSONReaderTest, DecodeNegativeEscapeSequence) {
+  EXPECT_FALSE(JSONReader::Read("[\"\\x-A\"]"));
+  EXPECT_FALSE(JSONReader::Read("[\"\\u-00A\"]"));
+}
+
+// Verifies invalid code points are replaced.
+TEST(JSONReaderTest, ReplaceInvalidCharacters) {
+  // U+D800 is a lone high surrogate.
+  const std::string invalid_high = "\"\xED\xA0\x80\"";
+  absl::optional<Value> value =
+      JSONReader::Read(invalid_high, JSON_REPLACE_INVALID_CHARACTERS);
+  ASSERT_TRUE(value);
+  ASSERT_TRUE(value->is_string());
+  // Expect three U+FFFD (one for each UTF-8 byte in the invalid code point).
+  EXPECT_EQ("\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD", value->GetString());
+
+  // U+DFFF is a lone low surrogate.
+  const std::string invalid_low = "\"\xED\xBF\xBF\"";
+  value = JSONReader::Read(invalid_low, JSON_REPLACE_INVALID_CHARACTERS);
+  ASSERT_TRUE(value);
+  ASSERT_TRUE(value->is_string());
+  // Expect three U+FFFD (one for each UTF-8 byte in the invalid code point).
+  EXPECT_EQ("\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD", value->GetString());
+}
+
+TEST(JSONReaderTest, ReplaceInvalidUTF16EscapeSequence) {
+  // U+D800 is a lone high surrogate.
+  const std::string invalid_high = "\"_\\uD800_\"";
+  absl::optional<Value> value =
+      JSONReader::Read(invalid_high, JSON_REPLACE_INVALID_CHARACTERS);
+  ASSERT_TRUE(value);
+  ASSERT_TRUE(value->is_string());
+  EXPECT_EQ("_\xEF\xBF\xBD_", value->GetString());
+
+  // U+DFFF is a lone low surrogate.
+  const std::string invalid_low = "\"_\\uDFFF_\"";
+  value = JSONReader::Read(invalid_low, JSON_REPLACE_INVALID_CHARACTERS);
+  ASSERT_TRUE(value);
+  ASSERT_TRUE(value->is_string());
+  EXPECT_EQ("_\xEF\xBF\xBD_", value->GetString());
+}
+
+TEST(JSONReaderTest, ParseNumberErrors) {
+  const struct {
+    const char* input;
+    bool parse_success;
+    double value;
+  } kCases[] = {
+      // clang-format off
+      {"1", true, 1},
+      {"2.", false, 0},
+      {"42", true, 42},
+      {"6e", false, 0},
+      {"43e2", true, 4300},
+      {"43e-", false, 0},
+      {"9e-3", true, 0.009},
+      {"2e+", false, 0},
+      {"2e+2", true, 200},
+      // clang-format on
+  };
+
+  for (unsigned int i = 0; i < std::size(kCases); ++i) {
+    auto test_case = kCases[i];
+    SCOPED_TRACE(StringPrintf("case %u: \"%s\"", i, test_case.input));
+
+    std::unique_ptr<char[]> input_owner;
+    StringPiece input =
+        MakeNotNullTerminatedInput(test_case.input, &input_owner);
+
+    absl::optional<Value> result = JSONReader::Read(input);
+    EXPECT_EQ(test_case.parse_success, result.has_value());
+
+    if (!result)
+      continue;
+
+    ASSERT_TRUE(result->is_double() || result->is_int());
+    EXPECT_EQ(test_case.value, result->GetDouble());
+  }
+}
+
+TEST(JSONReaderTest, UnterminatedInputs) {
+  const char* const kCases[] = {
+      // clang-format off
+      "/",
+      "//",
+      "/*",
+      "\"xxxxxx",
+      "\"",
+      "{   ",
+      "[\t",
+      "tru",
+      "fals",
+      "nul",
+      "\"\\x",
+      "\"\\x2",
+      "\"\\u123",
+      "\"\\uD803\\u",
+      "\"\\",
+      "\"\\/",
+      // clang-format on
+  };
+
+  for (unsigned int i = 0; i < std::size(kCases); ++i) {
+    auto* test_case = kCases[i];
+    SCOPED_TRACE(StringPrintf("case %u: \"%s\"", i, test_case));
+
+    std::unique_ptr<char[]> input_owner;
+    StringPiece input = MakeNotNullTerminatedInput(test_case, &input_owner);
+
+    EXPECT_FALSE(JSONReader::Read(input));
+  }
+}
+
+TEST(JSONReaderTest, LineColumnCounting) {
+  const struct {
+    const char* input;
+    int error_line;
+    int error_column;
+  } kCases[] = {
+      // For all but the "q_is_not_etc" case, the error (indicated by ^ in the
+      // comments) is seeing a digit when expecting ',' or ']'.
+      {
+          // Line and column counts are 1-based, not 0-based.
+          "q_is_not_the_start_of_any_valid_JSON_token",
+          1,
+          1,
+      },
+      {
+          "[2,4,6 8",
+          // -----^
+          1,
+          8,
+      },
+      {
+          "[2,4,6\t8",
+          // ------^
+          1,
+          8,
+      },
+      {
+          "[2,4,6\n8",
+          // ------^
+          2,
+          1,
+      },
+      {
+          "[\n0,\n1,\n2,\n3,4,5,6 7,\n8,\n9\n]",
+          // ---------------------^
+          5,
+          9,
+      },
+      {
+          // Same as the previous example, but with "\r\n"s instead of "\n"s.
+          "[\r\n0,\r\n1,\r\n2,\r\n3,4,5,6 7,\r\n8,\r\n9\r\n]",
+          // -----------------------------^
+          5,
+          9,
+      },
+      // The JSON spec forbids unescaped ASCII control characters (including
+      // line breaks) within a string, but our implementation is more lenient.
+      {
+          "[\"3\n1\" 4",
+          // --------^
+          2,
+          4,
+      },
+      {
+          "[\"3\r\n1\" 4",
+          // ----------^
+          2,
+          4,
+      },
+  };
+
+  for (unsigned int i = 0; i < std::size(kCases); ++i) {
+    auto test_case = kCases[i];
+    SCOPED_TRACE(StringPrintf("case %u: \"%s\"", i, test_case.input));
+
+    auto root = JSONReader::ReadAndReturnValueWithError(
+        test_case.input, JSON_PARSE_RFC | JSON_ALLOW_CONTROL_CHARS);
+    EXPECT_FALSE(root.has_value());
+    EXPECT_EQ(test_case.error_line, root.error().line);
+    EXPECT_EQ(test_case.error_column, root.error().column);
+  }
+}
+
+TEST(JSONReaderTest, ChromiumExtensions) {
+  // All of these cases should parse with JSON_PARSE_CHROMIUM_EXTENSIONS but
+  // fail with JSON_PARSE_RFC.
+  const struct {
+    // The JSON input.
+    const char* input;
+    // What JSON_* option permits this extension.
+    int option;
+  } kCases[] = {
+      {"{ /* comment */ \"foo\": 3 }", JSON_ALLOW_COMMENTS},
+      {"{ // comment\n \"foo\": 3 }", JSON_ALLOW_COMMENTS},
+      {"[\"\\xAB\"]", JSON_ALLOW_X_ESCAPES},
+      {"[\"\b\"]", JSON_ALLOW_CONTROL_CHARS},
+      {"[\"\f\"]", JSON_ALLOW_CONTROL_CHARS},
+      {"[\"\n\"]", JSON_ALLOW_CONTROL_CHARS},
+      {"[\"\r\"]", JSON_ALLOW_CONTROL_CHARS},
+      {"[\"\t\"]", JSON_ALLOW_CONTROL_CHARS},
+      {"[\"\v\"]", JSON_ALLOW_CONTROL_CHARS},
+      {"[\"\\v\"]", JSON_ALLOW_VERT_TAB},
+  };
+
+  for (size_t i = 0; i < std::size(kCases); ++i) {
+    SCOPED_TRACE(testing::Message() << "case " << i);
+    const auto& test_case = kCases[i];
+
+    auto result = JSONReader::ReadAndReturnValueWithError(test_case.input,
+                                                          JSON_PARSE_RFC);
+    EXPECT_FALSE(result.has_value());
+
+    result = JSONReader::ReadAndReturnValueWithError(
+        test_case.input, JSON_PARSE_RFC | test_case.option);
+    EXPECT_TRUE(result.has_value());
+
+    result = JSONReader::ReadAndReturnValueWithError(
+        test_case.input, JSON_PARSE_CHROMIUM_EXTENSIONS);
+    EXPECT_TRUE(result.has_value());
+
+    result = JSONReader::ReadAndReturnValueWithError(
+        test_case.input, JSON_PARSE_CHROMIUM_EXTENSIONS & ~test_case.option);
+    EXPECT_FALSE(result.has_value());
+  }
 }
 
 }  // namespace base
diff --git a/base/json/json_string_value_serializer.cc b/base/json/json_string_value_serializer.cc
index f9c45a4..561bfa0 100644
--- a/base/json/json_string_value_serializer.cc
+++ b/base/json/json_string_value_serializer.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,7 +6,6 @@
 
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
-#include "base/logging.h"
 
 using base::Value;
 
@@ -17,16 +16,16 @@
 
 JSONStringValueSerializer::~JSONStringValueSerializer() = default;
 
-bool JSONStringValueSerializer::Serialize(const Value& root) {
+bool JSONStringValueSerializer::Serialize(base::ValueView root) {
   return SerializeInternal(root, false);
 }
 
 bool JSONStringValueSerializer::SerializeAndOmitBinaryValues(
-    const Value& root) {
+    base::ValueView root) {
   return SerializeInternal(root, true);
 }
 
-bool JSONStringValueSerializer::SerializeInternal(const Value& root,
+bool JSONStringValueSerializer::SerializeInternal(base::ValueView root,
                                                   bool omit_binary_values) {
   if (!json_string_)
     return false;
@@ -50,6 +49,14 @@
 std::unique_ptr<Value> JSONStringValueDeserializer::Deserialize(
     int* error_code,
     std::string* error_str) {
-  return base::JSONReader::ReadAndReturnError(json_string_, options_,
-                                              error_code, error_str);
+  auto ret =
+      base::JSONReader::ReadAndReturnValueWithError(json_string_, options_);
+  if (ret.has_value())
+    return base::Value::ToUniquePtrValue(std::move(*ret));
+
+  if (error_code)
+    *error_code = base::ValueDeserializer::kErrorCodeInvalidFormat;
+  if (error_str)
+    *error_str = std::move(ret.error().message);
+  return nullptr;
 }
diff --git a/base/json/json_string_value_serializer.h b/base/json/json_string_value_serializer.h
index 55a53e2..5386546 100644
--- a/base/json/json_string_value_serializer.h
+++ b/base/json/json_string_value_serializer.h
@@ -1,15 +1,16 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_
 #define BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_
 
+#include <memory>
 #include <string>
 
 #include "base/base_export.h"
-#include "base/files/file_path.h"
-#include "base/macros.h"
+#include "base/json/json_reader.h"
+#include "base/memory/raw_ptr.h"
 #include "base/strings/string_piece.h"
 #include "base/values.h"
 
@@ -20,28 +21,30 @@
   // string. |json_string| must not be null.
   explicit JSONStringValueSerializer(std::string* json_string);
 
+  JSONStringValueSerializer(const JSONStringValueSerializer&) = delete;
+  JSONStringValueSerializer& operator=(const JSONStringValueSerializer&) =
+      delete;
+
   ~JSONStringValueSerializer() override;
 
   // Attempt to serialize the data structure represented by Value into
   // JSON.  If the return value is true, the result will have been written
   // into the string passed into the constructor.
-  bool Serialize(const base::Value& root) override;
+  bool Serialize(base::ValueView root) override;
 
   // Equivalent to Serialize(root) except binary values are omitted from the
   // output.
-  bool SerializeAndOmitBinaryValues(const base::Value& root);
+  bool SerializeAndOmitBinaryValues(base::ValueView root);
 
   void set_pretty_print(bool new_value) { pretty_print_ = new_value; }
   bool pretty_print() { return pretty_print_; }
 
  private:
-  bool SerializeInternal(const base::Value& root, bool omit_binary_values);
+  bool SerializeInternal(base::ValueView root, bool omit_binary_values);
 
   // Owned by the caller of the constructor.
-  std::string* json_string_;
+  raw_ptr<std::string> json_string_;
   bool pretty_print_;  // If true, serialization will span multiple lines.
-
-  DISALLOW_COPY_AND_ASSIGN(JSONStringValueSerializer);
 };
 
 class BASE_EXPORT JSONStringValueDeserializer : public base::ValueDeserializer {
@@ -49,17 +52,24 @@
   // This retains a reference to the contents of |json_string|, so the data
   // must outlive the JSONStringValueDeserializer. |options| is a bitmask of
   // JSONParserOptions.
-  explicit JSONStringValueDeserializer(const base::StringPiece& json_string,
-                                       int options = 0);
+  explicit JSONStringValueDeserializer(
+      const base::StringPiece& json_string,
+      int options = base::JSON_PARSE_CHROMIUM_EXTENSIONS);
+
+  JSONStringValueDeserializer(const JSONStringValueDeserializer&) = delete;
+  JSONStringValueDeserializer& operator=(const JSONStringValueDeserializer&) =
+      delete;
 
   ~JSONStringValueDeserializer() override;
 
-  // Attempt to deserialize the data structure encoded in the string passed
-  // in to the constructor into a structure of Value objects.  If the return
-  // value is null, and if |error_code| is non-null, |error_code| will
-  // contain an integer error code (a JsonParseError in this case).
-  // If |error_message| is non-null, it will be filled in with a formatted
-  // error message including the location of the error if appropriate.
+  // Attempts to deserialize |json_string_| into a structure of Value objects.
+  // If the return value is null, then
+  // (1) |error_code| will be filled with an integer error code
+  //     (base::ValueDeserializer::kErrorCodeInvalidFormat) if a non-null
+  //     |error_code| was given.
+  // (2) |error_message| will be filled with a formatted error message,
+  //     including the location of the error (if appropriate), if a non-null
+  //     |error_message| was given.
   // The caller takes ownership of the returned value.
   std::unique_ptr<base::Value> Deserialize(int* error_code,
                                            std::string* error_message) override;
@@ -68,8 +78,6 @@
   // Data is owned by the caller of the constructor.
   base::StringPiece json_string_;
   const int options_;
-
-  DISALLOW_COPY_AND_ASSIGN(JSONStringValueDeserializer);
 };
 
 #endif  // BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_
diff --git a/base/json/json_value_converter.cc b/base/json/json_value_converter.cc
index 6f772f3..50a3976 100644
--- a/base/json/json_value_converter.cc
+++ b/base/json/json_value_converter.cc
@@ -1,35 +1,57 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/json_value_converter.h"
 
+#include "base/strings/utf_string_conversions.h"
+
 namespace base {
 namespace internal {
 
 bool BasicValueConverter<int>::Convert(
     const base::Value& value, int* field) const {
-  return value.GetAsInteger(field);
+  if (!value.is_int())
+    return false;
+  if (field)
+    *field = value.GetInt();
+  return true;
 }
 
 bool BasicValueConverter<std::string>::Convert(
     const base::Value& value, std::string* field) const {
-  return value.GetAsString(field);
+  if (!value.is_string())
+    return false;
+  if (field)
+    *field = value.GetString();
+  return true;
 }
 
-bool BasicValueConverter<string16>::Convert(
-    const base::Value& value, string16* field) const {
-  return value.GetAsString(field);
+bool BasicValueConverter<std::u16string>::Convert(const base::Value& value,
+                                                  std::u16string* field) const {
+  if (!value.is_string())
+    return false;
+  if (field)
+    *field = base::UTF8ToUTF16(value.GetString());
+  return true;
 }
 
 bool BasicValueConverter<double>::Convert(
     const base::Value& value, double* field) const {
-  return value.GetAsDouble(field);
+  if (!value.is_double() && !value.is_int())
+    return false;
+  if (field)
+    *field = value.GetDouble();
+  return true;
 }
 
 bool BasicValueConverter<bool>::Convert(
     const base::Value& value, bool* field) const {
-  return value.GetAsBoolean(field);
+  if (!value.is_bool())
+    return false;
+  if (field)
+    *field = value.GetBool();
+  return true;
 }
 
 }  // namespace internal
diff --git a/base/json/json_value_converter.h b/base/json/json_value_converter.h
index 9a7b999..0d00cf3 100644
--- a/base/json/json_value_converter.h
+++ b/base/json/json_value_converter.h
@@ -1,22 +1,22 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_JSON_JSON_VALUE_CONVERTER_H_
 #define BASE_JSON_JSON_VALUE_CONVERTER_H_
 
+#include <stddef.h>
+
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/base_export.h"
 #include "base/logging.h"
-#include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/strings/string16.h"
 #include "base/strings/string_piece.h"
 #include "base/values.h"
-#include "starboard/types.h"
 
 // JSONValueConverter converts a JSON value into a C++ struct in a
 // lightweight way.
@@ -91,18 +91,21 @@
 
 namespace internal {
 
-template<typename StructType>
+template <typename StructType>
 class FieldConverterBase {
  public:
   explicit FieldConverterBase(const std::string& path) : field_path_(path) {}
+
+  FieldConverterBase(const FieldConverterBase&) = delete;
+  FieldConverterBase& operator=(const FieldConverterBase&) = delete;
+
   virtual ~FieldConverterBase() = default;
-  virtual bool ConvertField(const base::Value& value, StructType* obj)
-      const = 0;
+  virtual bool ConvertField(const base::Value& value,
+                            StructType* obj) const = 0;
   const std::string& field_path() const { return field_path_; }
 
  private:
   std::string field_path_;
-  DISALLOW_COPY_AND_ASSIGN(FieldConverterBase);
 };
 
 template <typename FieldType>
@@ -116,21 +119,22 @@
 class FieldConverter : public FieldConverterBase<StructType> {
  public:
   explicit FieldConverter(const std::string& path,
-                          FieldType StructType::* field,
+                          FieldType StructType::*field,
                           ValueConverter<FieldType>* converter)
       : FieldConverterBase<StructType>(path),
         field_pointer_(field),
-        value_converter_(converter) {
-  }
+        value_converter_(converter) {}
+
+  FieldConverter(const FieldConverter&) = delete;
+  FieldConverter& operator=(const FieldConverter&) = delete;
 
   bool ConvertField(const base::Value& value, StructType* dst) const override {
     return value_converter_->Convert(value, &(dst->*field_pointer_));
   }
 
  private:
-  FieldType StructType::* field_pointer_;
+  FieldType StructType::*field_pointer_;
   std::unique_ptr<ValueConverter<FieldType>> value_converter_;
-  DISALLOW_COPY_AND_ASSIGN(FieldConverter);
 };
 
 template <typename FieldType>
@@ -141,10 +145,10 @@
  public:
   BasicValueConverter() = default;
 
-  bool Convert(const base::Value& value, int* field) const override;
+  BasicValueConverter(const BasicValueConverter&) = delete;
+  BasicValueConverter& operator=(const BasicValueConverter&) = delete;
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+  bool Convert(const base::Value& value, int* field) const override;
 };
 
 template <>
@@ -153,22 +157,22 @@
  public:
   BasicValueConverter() = default;
 
-  bool Convert(const base::Value& value, std::string* field) const override;
+  BasicValueConverter(const BasicValueConverter&) = delete;
+  BasicValueConverter& operator=(const BasicValueConverter&) = delete;
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+  bool Convert(const base::Value& value, std::string* field) const override;
 };
 
 template <>
-class BASE_EXPORT BasicValueConverter<string16>
-    : public ValueConverter<string16> {
+class BASE_EXPORT BasicValueConverter<std::u16string>
+    : public ValueConverter<std::u16string> {
  public:
   BasicValueConverter() = default;
 
-  bool Convert(const base::Value& value, string16* field) const override;
+  BasicValueConverter(const BasicValueConverter&) = delete;
+  BasicValueConverter& operator=(const BasicValueConverter&) = delete;
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+  bool Convert(const base::Value& value, std::u16string* field) const override;
 };
 
 template <>
@@ -176,10 +180,10 @@
  public:
   BasicValueConverter() = default;
 
-  bool Convert(const base::Value& value, double* field) const override;
+  BasicValueConverter(const BasicValueConverter&) = delete;
+  BasicValueConverter& operator=(const BasicValueConverter&) = delete;
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+  bool Convert(const base::Value& value, double* field) const override;
 };
 
 template <>
@@ -187,28 +191,29 @@
  public:
   BasicValueConverter() = default;
 
-  bool Convert(const base::Value& value, bool* field) const override;
+  BasicValueConverter(const BasicValueConverter&) = delete;
+  BasicValueConverter& operator=(const BasicValueConverter&) = delete;
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+  bool Convert(const base::Value& value, bool* field) const override;
 };
 
 template <typename FieldType>
 class ValueFieldConverter : public ValueConverter<FieldType> {
  public:
-  typedef bool(*ConvertFunc)(const base::Value* value, FieldType* field);
+  typedef bool (*ConvertFunc)(const base::Value* value, FieldType* field);
 
   explicit ValueFieldConverter(ConvertFunc convert_func)
       : convert_func_(convert_func) {}
 
+  ValueFieldConverter(const ValueFieldConverter&) = delete;
+  ValueFieldConverter& operator=(const ValueFieldConverter&) = delete;
+
   bool Convert(const base::Value& value, FieldType* field) const override {
     return convert_func_(&value, field);
   }
 
  private:
   ConvertFunc convert_func_;
-
-  DISALLOW_COPY_AND_ASSIGN(ValueFieldConverter);
 };
 
 template <typename FieldType>
@@ -219,16 +224,15 @@
   explicit CustomFieldConverter(ConvertFunc convert_func)
       : convert_func_(convert_func) {}
 
+  CustomFieldConverter(const CustomFieldConverter&) = delete;
+  CustomFieldConverter& operator=(const CustomFieldConverter&) = delete;
+
   bool Convert(const base::Value& value, FieldType* field) const override {
-    std::string string_value;
-    return value.GetAsString(&string_value) &&
-        convert_func_(string_value, field);
+    return value.is_string() && convert_func_(value.GetString(), field);
   }
 
  private:
   ConvertFunc convert_func_;
-
-  DISALLOW_COPY_AND_ASSIGN(CustomFieldConverter);
 };
 
 template <typename NestedType>
@@ -236,13 +240,15 @@
  public:
   NestedValueConverter() = default;
 
+  NestedValueConverter(const NestedValueConverter&) = delete;
+  NestedValueConverter& operator=(const NestedValueConverter&) = delete;
+
   bool Convert(const base::Value& value, NestedType* field) const override {
     return converter_.Convert(value, field);
   }
 
  private:
   JSONValueConverter<NestedType> converter_;
-  DISALLOW_COPY_AND_ASSIGN(NestedValueConverter);
 };
 
 template <typename Element>
@@ -251,34 +257,34 @@
  public:
   RepeatedValueConverter() = default;
 
+  RepeatedValueConverter(const RepeatedValueConverter&) = delete;
+  RepeatedValueConverter& operator=(const RepeatedValueConverter&) = delete;
+
   bool Convert(const base::Value& value,
                std::vector<std::unique_ptr<Element>>* field) const override {
-    const base::ListValue* list = NULL;
-    if (!value.GetAsList(&list)) {
+    const Value::List* list = value.GetIfList();
+    if (!list) {
       // The field is not a list.
       return false;
     }
 
-    field->reserve(list->GetSize());
-    for (size_t i = 0; i < list->GetSize(); ++i) {
-      const base::Value* element = NULL;
-      if (!list->Get(i, &element))
-        continue;
-
-      std::unique_ptr<Element> e(new Element);
-      if (basic_converter_.Convert(*element, e.get())) {
+    field->reserve(list->size());
+    size_t i = 0;
+    for (const Value& element : *list) {
+      auto e = std::make_unique<Element>();
+      if (basic_converter_.Convert(element, e.get())) {
         field->push_back(std::move(e));
       } else {
         DVLOG(1) << "failure at " << i << "-th element";
         return false;
       }
+      i++;
     }
     return true;
   }
 
  private:
   BasicValueConverter<Element> basic_converter_;
-  DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter);
 };
 
 template <typename NestedType>
@@ -287,119 +293,120 @@
  public:
   RepeatedMessageConverter() = default;
 
+  RepeatedMessageConverter(const RepeatedMessageConverter&) = delete;
+  RepeatedMessageConverter& operator=(const RepeatedMessageConverter&) = delete;
+
   bool Convert(const base::Value& value,
                std::vector<std::unique_ptr<NestedType>>* field) const override {
-    const base::ListValue* list = NULL;
-    if (!value.GetAsList(&list))
+    const Value::List* list = value.GetIfList();
+    if (!list)
       return false;
 
-    field->reserve(list->GetSize());
-    for (size_t i = 0; i < list->GetSize(); ++i) {
-      const base::Value* element = NULL;
-      if (!list->Get(i, &element))
-        continue;
-
-      std::unique_ptr<NestedType> nested(new NestedType);
-      if (converter_.Convert(*element, nested.get())) {
+    field->reserve(list->size());
+    size_t i = 0;
+    for (const Value& element : *list) {
+      auto nested = std::make_unique<NestedType>();
+      if (converter_.Convert(element, nested.get())) {
         field->push_back(std::move(nested));
       } else {
         DVLOG(1) << "failure at " << i << "-th element";
         return false;
       }
+      i++;
     }
     return true;
   }
 
  private:
   JSONValueConverter<NestedType> converter_;
-  DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter);
 };
 
 template <typename NestedType>
 class RepeatedCustomValueConverter
     : public ValueConverter<std::vector<std::unique_ptr<NestedType>>> {
  public:
-  typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field);
+  typedef bool (*ConvertFunc)(const base::Value* value, NestedType* field);
 
   explicit RepeatedCustomValueConverter(ConvertFunc convert_func)
       : convert_func_(convert_func) {}
 
+  RepeatedCustomValueConverter(const RepeatedCustomValueConverter&) = delete;
+  RepeatedCustomValueConverter& operator=(const RepeatedCustomValueConverter&) =
+      delete;
+
   bool Convert(const base::Value& value,
                std::vector<std::unique_ptr<NestedType>>* field) const override {
-    const base::ListValue* list = NULL;
-    if (!value.GetAsList(&list))
+    const Value::List* list = value.GetIfList();
+    if (!list)
       return false;
 
-    field->reserve(list->GetSize());
-    for (size_t i = 0; i < list->GetSize(); ++i) {
-      const base::Value* element = NULL;
-      if (!list->Get(i, &element))
-        continue;
-
-      std::unique_ptr<NestedType> nested(new NestedType);
-      if ((*convert_func_)(element, nested.get())) {
+    field->reserve(list->size());
+    size_t i = 0;
+    for (const Value& element : *list) {
+      auto nested = std::make_unique<NestedType>();
+      if ((*convert_func_)(&element, nested.get())) {
         field->push_back(std::move(nested));
       } else {
         DVLOG(1) << "failure at " << i << "-th element";
         return false;
       }
+      i++;
     }
     return true;
   }
 
  private:
   ConvertFunc convert_func_;
-  DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter);
 };
 
-
 }  // namespace internal
 
 template <class StructType>
 class JSONValueConverter {
  public:
-  JSONValueConverter() {
-    StructType::RegisterJSONConverter(this);
-  }
+  JSONValueConverter() { StructType::RegisterJSONConverter(this); }
 
-  void RegisterIntField(const std::string& field_name,
-                        int StructType::* field) {
+  JSONValueConverter(const JSONValueConverter&) = delete;
+  JSONValueConverter& operator=(const JSONValueConverter&) = delete;
+
+  void RegisterIntField(const std::string& field_name, int StructType::*field) {
     fields_.push_back(
         std::make_unique<internal::FieldConverter<StructType, int>>(
             field_name, field, new internal::BasicValueConverter<int>));
   }
 
   void RegisterStringField(const std::string& field_name,
-                           std::string StructType::* field) {
+                           std::string StructType::*field) {
     fields_.push_back(
         std::make_unique<internal::FieldConverter<StructType, std::string>>(
             field_name, field, new internal::BasicValueConverter<std::string>));
   }
 
   void RegisterStringField(const std::string& field_name,
-                           string16 StructType::* field) {
+                           std::u16string StructType::*field) {
     fields_.push_back(
-        std::make_unique<internal::FieldConverter<StructType, string16>>(
-            field_name, field, new internal::BasicValueConverter<string16>));
+        std::make_unique<internal::FieldConverter<StructType, std::u16string>>(
+            field_name, field,
+            new internal::BasicValueConverter<std::u16string>));
   }
 
   void RegisterBoolField(const std::string& field_name,
-                         bool StructType::* field) {
+                         bool StructType::*field) {
     fields_.push_back(
         std::make_unique<internal::FieldConverter<StructType, bool>>(
             field_name, field, new internal::BasicValueConverter<bool>));
   }
 
   void RegisterDoubleField(const std::string& field_name,
-                           double StructType::* field) {
+                           double StructType::*field) {
     fields_.push_back(
         std::make_unique<internal::FieldConverter<StructType, double>>(
             field_name, field, new internal::BasicValueConverter<double>));
   }
 
   template <class NestedType>
-  void RegisterNestedField(
-      const std::string& field_name, NestedType StructType::* field) {
+  void RegisterNestedField(const std::string& field_name,
+                           NestedType StructType::*field) {
     fields_.push_back(
         std::make_unique<internal::FieldConverter<StructType, NestedType>>(
             field_name, field, new internal::NestedValueConverter<NestedType>));
@@ -416,10 +423,10 @@
   }
 
   template <typename FieldType>
-  void RegisterCustomValueField(
-      const std::string& field_name,
-      FieldType StructType::* field,
-      bool (*convert_func)(const base::Value*, FieldType*)) {
+  void RegisterCustomValueField(const std::string& field_name,
+                                FieldType StructType::*field,
+                                bool (*convert_func)(const base::Value*,
+                                                     FieldType*)) {
     fields_.push_back(
         std::make_unique<internal::FieldConverter<StructType, FieldType>>(
             field_name, field,
@@ -446,10 +453,12 @@
 
   void RegisterRepeatedString(
       const std::string& field_name,
-      std::vector<std::unique_ptr<string16>> StructType::*field) {
-    fields_.push_back(std::make_unique<internal::FieldConverter<
-                          StructType, std::vector<std::unique_ptr<string16>>>>(
-        field_name, field, new internal::RepeatedValueConverter<string16>));
+      std::vector<std::unique_ptr<std::u16string>> StructType::*field) {
+    fields_.push_back(
+        std::make_unique<internal::FieldConverter<
+            StructType, std::vector<std::unique_ptr<std::u16string>>>>(
+            field_name, field,
+            new internal::RepeatedValueConverter<std::u16string>));
   }
 
   void RegisterRepeatedDouble(
@@ -493,15 +502,16 @@
   }
 
   bool Convert(const base::Value& value, StructType* output) const {
-    const DictionaryValue* dictionary_value = NULL;
-    if (!value.GetAsDictionary(&dictionary_value))
+    const Value::Dict* dict = value.GetIfDict();
+    if (!dict)
       return false;
 
     for (size_t i = 0; i < fields_.size(); ++i) {
       const internal::FieldConverterBase<StructType>* field_converter =
           fields_[i].get();
-      const base::Value* field = NULL;
-      if (dictionary_value->Get(field_converter->field_path(), &field)) {
+      const base::Value* field =
+          dict->FindByDottedPath(field_converter->field_path());
+      if (field) {
         if (!field_converter->ConvertField(*field, output)) {
           DVLOG(1) << "failure at field " << field_converter->field_path();
           return false;
@@ -514,8 +524,6 @@
  private:
   std::vector<std::unique_ptr<internal::FieldConverterBase<StructType>>>
       fields_;
-
-  DISALLOW_COPY_AND_ASSIGN(JSONValueConverter);
 };
 
 }  // namespace base
diff --git a/base/json/json_value_converter_unittest.cc b/base/json/json_value_converter_unittest.cc
index 0946820..f385486 100644
--- a/base/json/json_value_converter_unittest.cc
+++ b/base/json/json_value_converter_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -12,6 +12,7 @@
 #include "base/strings/string_piece.h"
 #include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 namespace {
@@ -19,7 +20,8 @@
 // Very simple messages.
 struct SimpleMessage {
   enum SimpleEnum {
-    FOO, BAR,
+    FOO,
+    BAR,
   };
   int foo;
   std::string bar;
@@ -48,13 +50,14 @@
   }
 
   static bool GetValueString(const base::Value* value, std::string* result) {
-    const base::DictionaryValue* dict = nullptr;
-    if (!value->GetAsDictionary(&dict))
+    const Value::Dict* dict = value->GetIfDict();
+    if (!dict)
       return false;
-
-    if (!dict->GetString("val", result))
+    const std::string* str = dict->FindString("val");
+    if (!str)
       return false;
-
+    if (result)
+      *result = *str;
     return true;
   }
 
@@ -66,13 +69,10 @@
     converter->RegisterCustomField<SimpleEnum>(
         "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum);
     converter->RegisterRepeatedInt("ints", &SimpleMessage::ints);
-    converter->RegisterCustomValueField<bool>("bstruct",
-                                              &SimpleMessage::bstruct,
-                                              &HasFieldPresent);
+    converter->RegisterCustomValueField<bool>(
+        "bstruct", &SimpleMessage::bstruct, &HasFieldPresent);
     converter->RegisterRepeatedCustomValue<std::string>(
-        "string_values",
-        &SimpleMessage::string_values,
-        &GetValueString);
+        "string_values", &SimpleMessage::string_values, &GetValueString);
   }
 };
 
@@ -106,10 +106,11 @@
       "  \"ints\": [1, 2]"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  absl::optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
-  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+  EXPECT_TRUE(converter.Convert(*value, &message));
 
   EXPECT_EQ(1, message.foo);
   EXPECT_EQ("bar", message.bar);
@@ -148,10 +149,11 @@
       "  }]\n"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  absl::optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   NestedMessage message;
   base::JSONValueConverter<NestedMessage> converter;
-  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+  EXPECT_TRUE(converter.Convert(*value, &message));
 
   EXPECT_EQ(1.0, message.foo);
   EXPECT_EQ(1, message.child.foo);
@@ -185,15 +187,16 @@
   const char normal_data[] =
       "{\n"
       "  \"foo\": 1,\n"
-      "  \"bar\": 2,\n" // "bar" is an integer here.
+      "  \"bar\": 2,\n"  // "bar" is an integer here.
       "  \"baz\": true,\n"
       "  \"ints\": [1, 2]"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  absl::optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
-  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  EXPECT_FALSE(converter.Convert(*value, &message));
   // Do not check the values below.  |message| may be modified during
   // Convert() even it fails.
 }
@@ -206,11 +209,12 @@
       "  \"ints\": [1, 2]"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  absl::optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
   // Convert() still succeeds even if the input doesn't have "bar" field.
-  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+  EXPECT_TRUE(converter.Convert(*value, &message));
 
   EXPECT_EQ(1, message.foo);
   EXPECT_TRUE(message.baz);
@@ -229,10 +233,11 @@
       "  \"ints\": [1, 2]"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  absl::optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
-  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  EXPECT_FALSE(converter.Convert(*value, &message));
   // No check the values as mentioned above.
 }
 
@@ -246,10 +251,11 @@
       "  \"ints\": [1, false]"
       "}\n";
 
-  std::unique_ptr<Value> value = base::JSONReader::Read(normal_data);
+  absl::optional<Value> value = base::JSONReader::Read(normal_data);
+  ASSERT_TRUE(value);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
-  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  EXPECT_FALSE(converter.Convert(*value, &message));
   // No check the values as mentioned above.
 }
 
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc
index b12e5e7..16bf99e 100644
--- a/base/json/json_value_serializer_unittest.cc
+++ b/base/json/json_value_serializer_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -17,8 +17,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "starboard/common/string.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 
@@ -70,21 +70,21 @@
   str_serializer.set_pretty_print(true);
   ASSERT_TRUE(str_serializer.Serialize(value));
   // Unify line endings between platforms.
-  ReplaceSubstringsAfterOffset(&serialized_json, 0,
-                               kWinLineEnds, kLinuxLineEnds);
+  ReplaceSubstringsAfterOffset(&serialized_json, 0, kWinLineEnds,
+                               kLinuxLineEnds);
   // Now compare the input with the output.
   ASSERT_EQ(kProperJSON, serialized_json);
 }
 
 void ValidateJsonList(const std::string& json) {
-  std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read(json));
+  absl::optional<Value> value = JSONReader::Read(json);
+  ASSERT_TRUE(value);
+  Value::List* list = value->GetIfList();
   ASSERT_TRUE(list);
-  ASSERT_EQ(1U, list->GetSize());
-  Value* elt = nullptr;
-  ASSERT_TRUE(list->Get(0, &elt));
-  int value = 0;
-  ASSERT_TRUE(elt && elt->GetAsInteger(&value));
-  ASSERT_EQ(1, value);
+  ASSERT_EQ(1U, list->size());
+  const Value& elt = (*list)[0];
+  ASSERT_TRUE(elt.is_int());
+  ASSERT_EQ(1, elt.GetInt());
 }
 
 // Test proper JSON deserialization from string is working.
@@ -135,12 +135,15 @@
   ASSERT_FALSE(value);
   ASSERT_NE(0, error_code);
   ASSERT_FALSE(error_message.empty());
-  // Repeat with commas allowed.
+  // Repeat with commas allowed. The Deserialize call shouldn't change the
+  // value of error_code. To test that, we first set it to a nonsense value
+  // (-789) and ASSERT_EQ that it remains that nonsense value.
+  error_code = -789;
   JSONStringValueDeserializer str_deserializer2(kProperJSONWithCommas,
                                                 JSON_ALLOW_TRAILING_COMMAS);
   value = str_deserializer2.Deserialize(&error_code, &error_message);
   ASSERT_TRUE(value);
-  ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+  ASSERT_EQ(-789, error_code);
   // Verify if the same JSON is still there.
   CheckJSONIsStillTheSame(*value);
 }
@@ -151,8 +154,7 @@
   ASSERT_TRUE(tempdir.CreateUniqueTempDir());
   // Write it down in the file.
   FilePath temp_file(tempdir.GetPath().AppendASCII("test.json"));
-  ASSERT_EQ(static_cast<int>(strlen(kProperJSON)),
-            WriteFile(temp_file, kProperJSON, strlen(kProperJSON)));
+  ASSERT_TRUE(WriteFile(temp_file, kProperJSON));
 
   // Try to deserialize it through the serializer.
   JSONFileValueDeserializer file_deserializer(temp_file);
@@ -175,9 +177,7 @@
   ASSERT_TRUE(tempdir.CreateUniqueTempDir());
   // Write it down in the file.
   FilePath temp_file(tempdir.GetPath().AppendASCII("test.json"));
-  ASSERT_EQ(static_cast<int>(strlen(kProperJSONWithCommas)),
-            WriteFile(temp_file, kProperJSONWithCommas,
-                      strlen(kProperJSONWithCommas)));
+  ASSERT_TRUE(WriteFile(temp_file, kProperJSONWithCommas));
 
   // Try to deserialize it through the serializer.
   JSONFileValueDeserializer file_deserializer(temp_file);
@@ -189,12 +189,15 @@
   ASSERT_FALSE(value);
   ASSERT_NE(0, error_code);
   ASSERT_FALSE(error_message.empty());
-  // Repeat with commas allowed.
+  // Repeat with commas allowed. The Deserialize call shouldn't change the
+  // value of error_code. To test that, we first set it to a nonsense value
+  // (-789) and ASSERT_EQ that it remains that nonsense value.
+  error_code = -789;
   JSONFileValueDeserializer file_deserializer2(temp_file,
                                                JSON_ALLOW_TRAILING_COMMAS);
   value = file_deserializer2.Deserialize(&error_code, &error_message);
   ASSERT_TRUE(value);
-  ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+  ASSERT_EQ(-789, error_code);
   // Verify if the same JSON is still there.
   CheckJSONIsStillTheSame(*value);
 }
@@ -211,33 +214,25 @@
   std::unique_ptr<Value> root_expected;
   root_expected = deserializer_expected.Deserialize(nullptr, nullptr);
   ASSERT_TRUE(root_expected);
-  ASSERT_TRUE(root->Equals(root_expected.get()));
+  ASSERT_EQ(*root, *root_expected);
 }
 
 TEST(JSONValueSerializerTest, Roundtrip) {
   static const char kOriginalSerialization[] =
-    "{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}";
+      "{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}";
   JSONStringValueDeserializer deserializer(kOriginalSerialization);
-  std::unique_ptr<DictionaryValue> root_dict =
-      DictionaryValue::From(deserializer.Deserialize(nullptr, nullptr));
+  std::unique_ptr<Value> root = deserializer.Deserialize(nullptr, nullptr);
+  ASSERT_TRUE(root);
+  const Value::Dict* root_dict = root->GetIfDict();
   ASSERT_TRUE(root_dict);
 
-  Value* null_value = nullptr;
-  ASSERT_TRUE(root_dict->Get("null", &null_value));
+  const Value* null_value = root_dict->Find("null");
   ASSERT_TRUE(null_value);
   ASSERT_TRUE(null_value->is_none());
 
-  bool bool_value = false;
-  ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value));
-  ASSERT_TRUE(bool_value);
-
-  int int_value = 0;
-  ASSERT_TRUE(root_dict->GetInteger("int", &int_value));
-  ASSERT_EQ(42, int_value);
-
-  double double_value = 0.0;
-  ASSERT_TRUE(root_dict->GetDouble("double", &double_value));
-  ASSERT_DOUBLE_EQ(3.14, double_value);
+  ASSERT_TRUE(root_dict->FindBool("bool").value());
+  ASSERT_EQ(42, root_dict->FindInt("int").value());
+  ASSERT_DOUBLE_EQ(3.14, root_dict->FindDouble("double").value());
 
   std::string test_serialization;
   JSONStringValueSerializer mutable_serializer(&test_serialization);
@@ -248,27 +243,24 @@
   ASSERT_TRUE(mutable_serializer.Serialize(*root_dict));
   // JSON output uses a different newline style on Windows than on other
   // platforms.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #define JSON_NEWLINE "\r\n"
 #else
 #define JSON_NEWLINE "\n"
 #endif
   const std::string pretty_serialization =
-    "{" JSON_NEWLINE
-    "   \"bool\": true," JSON_NEWLINE
-    "   \"double\": 3.14," JSON_NEWLINE
-    "   \"int\": 42," JSON_NEWLINE
-    "   \"list\": [ 1, 2 ]," JSON_NEWLINE
-    "   \"null\": null" JSON_NEWLINE
-    "}" JSON_NEWLINE;
+      "{" JSON_NEWLINE "   \"bool\": true," JSON_NEWLINE
+      "   \"double\": 3.14," JSON_NEWLINE "   \"int\": 42," JSON_NEWLINE
+      "   \"list\": [ 1, 2 ]," JSON_NEWLINE "   \"null\": null" JSON_NEWLINE
+      "}" JSON_NEWLINE;
 #undef JSON_NEWLINE
   ASSERT_EQ(pretty_serialization, test_serialization);
 }
 
 TEST(JSONValueSerializerTest, StringEscape) {
-  string16 all_chars;
+  std::u16string all_chars;
   for (int i = 1; i < 256; ++i) {
-    all_chars += static_cast<char16>(i);
+    all_chars += static_cast<char16_t>(i);
   }
   // Generated in in Firefox using the following js (with an extra backslash for
   // double quote):
@@ -296,12 +288,12 @@
       "\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4\xC3\xB5\xC3\xB6\xC3\xB7\xC3\xB8\xC3\xB9"
       "\xC3\xBA\xC3\xBB\xC3\xBC\xC3\xBD\xC3\xBE\xC3\xBF";
 
-  std::string expected_output = "{\"all_chars\":\"" + all_chars_expected +
-                                 "\"}";
+  std::string expected_output =
+      "{\"all_chars\":\"" + all_chars_expected + "\"}";
   // Test JSONWriter interface
   std::string output_js;
-  DictionaryValue valueRoot;
-  valueRoot.SetString("all_chars", all_chars);
+  Value::Dict valueRoot;
+  valueRoot.Set("all_chars", all_chars);
   JSONWriter::Write(valueRoot, &output_js);
   ASSERT_EQ(expected_output, output_js);
 
@@ -313,9 +305,9 @@
 
 TEST(JSONValueSerializerTest, UnicodeStrings) {
   // unicode string json -> escaped ascii text
-  DictionaryValue root;
-  string16 test(WideToUTF16(L"\x7F51\x9875"));
-  root.SetString("web", test);
+  Value::Dict root;
+  std::u16string test(u"\x7F51\x9875");
+  root.Set("web", test);
 
   static const char kExpected[] = "{\"web\":\"\xE7\xBD\x91\xE9\xA1\xB5\"}";
 
@@ -329,18 +321,17 @@
   std::unique_ptr<Value> deserial_root =
       deserializer.Deserialize(nullptr, nullptr);
   ASSERT_TRUE(deserial_root);
-  DictionaryValue* dict_root =
-      static_cast<DictionaryValue*>(deserial_root.get());
-  string16 web_value;
-  ASSERT_TRUE(dict_root->GetString("web", &web_value));
-  ASSERT_EQ(test, web_value);
+  const Value::Dict* deserial_root_dict = deserial_root->GetIfDict();
+  const std::string* web_value = deserial_root_dict->FindString("web");
+  ASSERT_TRUE(web_value);
+  ASSERT_EQ("\xE7\xBD\x91\xE9\xA1\xB5", *web_value);
 }
 
 TEST(JSONValueSerializerTest, HexStrings) {
   // hex string json -> escaped ascii text
-  DictionaryValue root;
-  string16 test(WideToUTF16(L"\x01\x02"));
-  root.SetString("test", test);
+  Value::Dict root;
+  std::u16string test(u"\x01\x02");
+  root.Set("test", test);
 
   static const char kExpected[] = "{\"test\":\"\\u0001\\u0002\"}";
 
@@ -354,20 +345,20 @@
   std::unique_ptr<Value> deserial_root =
       deserializer.Deserialize(nullptr, nullptr);
   ASSERT_TRUE(deserial_root);
-  DictionaryValue* dict_root =
-      static_cast<DictionaryValue*>(deserial_root.get());
-  string16 test_value;
-  ASSERT_TRUE(dict_root->GetString("test", &test_value));
-  ASSERT_EQ(test, test_value);
+  Value::Dict* deserial_root_dict = deserial_root->GetIfDict();
+  const std::string* test_value = deserial_root_dict->FindString("test");
+  ASSERT_TRUE(test_value);
+  ASSERT_EQ("\u0001\u0002", *test_value);
 
   // Test converting escaped regular chars
   static const char kEscapedChars[] = "{\"test\":\"\\u0067\\u006f\"}";
   JSONStringValueDeserializer deserializer2(kEscapedChars);
   deserial_root = deserializer2.Deserialize(nullptr, nullptr);
   ASSERT_TRUE(deserial_root);
-  dict_root = static_cast<DictionaryValue*>(deserial_root.get());
-  ASSERT_TRUE(dict_root->GetString("test", &test_value));
-  ASSERT_EQ(ASCIIToUTF16("go"), test_value);
+  deserial_root_dict = deserial_root->GetIfDict();
+  test_value = deserial_root_dict->FindString("test");
+  ASSERT_TRUE(test_value);
+  ASSERT_EQ("go", *test_value);
 }
 
 TEST(JSONValueSerializerTest, JSONReaderComments) {
@@ -379,15 +370,14 @@
   ValidateJsonList("[ 1 //// ,2\r\n ]");
 
   // It's ok to have a comment in a string.
-  std::unique_ptr<ListValue> list =
-      ListValue::From(JSONReader::Read("[\"// ok\\n /* foo */ \"]"));
+  absl::optional<Value> value = JSONReader::Read("[\"// ok\\n /* foo */ \"]");
+  ASSERT_TRUE(value);
+  Value::List* list = value->GetIfList();
   ASSERT_TRUE(list);
-  ASSERT_EQ(1U, list->GetSize());
-  Value* elt = nullptr;
-  ASSERT_TRUE(list->Get(0, &elt));
-  std::string value;
-  ASSERT_TRUE(elt && elt->GetAsString(&value));
-  ASSERT_EQ("// ok\n /* foo */ ", value);
+  ASSERT_EQ(1U, list->size());
+  const Value& elt = (*list)[0];
+  ASSERT_TRUE(elt.is_string());
+  ASSERT_EQ("// ok\n /* foo */ ", elt.GetString());
 
   // You can't nest comments.
   ASSERT_FALSE(JSONReader::Read("/* /* inner */ outer */ [ 1 ]"));
@@ -416,26 +406,21 @@
   ASSERT_TRUE(PathExists(original_file_path));
 
   JSONFileValueDeserializer deserializer(original_file_path);
-  std::unique_ptr<DictionaryValue> root_dict =
-      DictionaryValue::From(deserializer.Deserialize(nullptr, nullptr));
+  std::unique_ptr<Value> root = deserializer.Deserialize(nullptr, nullptr);
+  ASSERT_TRUE(root);
+  const Value::Dict* root_dict = root->GetIfDict();
   ASSERT_TRUE(root_dict);
 
-  Value* null_value = nullptr;
-  ASSERT_TRUE(root_dict->Get("null", &null_value));
+  const Value* null_value = root_dict->Find("null");
   ASSERT_TRUE(null_value);
   ASSERT_TRUE(null_value->is_none());
 
-  bool bool_value = false;
-  ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value));
-  ASSERT_TRUE(bool_value);
+  ASSERT_TRUE(root_dict->FindBool("bool").value());
+  ASSERT_EQ(42, root_dict->FindInt("int").value());
 
-  int int_value = 0;
-  ASSERT_TRUE(root_dict->GetInteger("int", &int_value));
-  ASSERT_EQ(42, int_value);
-
-  std::string string_value;
-  ASSERT_TRUE(root_dict->GetString("string", &string_value));
-  ASSERT_EQ("hello", string_value);
+  const std::string* string_value = root_dict->FindString("string");
+  ASSERT_TRUE(string_value);
+  ASSERT_EQ("hello", *string_value);
 
   // Now try writing.
   const FilePath written_file_path =
@@ -450,7 +435,7 @@
 #if !defined(STARBOARD)
   EXPECT_TRUE(TextContentsEqual(original_file_path, written_file_path));
 #endif  // !defined(STARBOARD)
-  EXPECT_TRUE(DeleteFile(written_file_path, false));
+  EXPECT_TRUE(DeleteFile(written_file_path));
 }
 
 TEST_F(JSONFileValueSerializerTest, RoundtripNested) {
@@ -483,7 +468,7 @@
 #if !defined(STARBOARD)
   EXPECT_TRUE(TextContentsEqual(original_file_path, written_file_path));
 #endif  // !defined(STARBOARD)
-  EXPECT_TRUE(DeleteFile(written_file_path, false));
+  EXPECT_TRUE(DeleteFile(written_file_path));
 }
 
 TEST_F(JSONFileValueSerializerTest, NoWhitespace) {
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index 237be4f..9195e64 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.cc
@@ -1,208 +1,237 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/json_writer.h"
 
+#include <stdint.h>
+
 #include <cmath>
 #include <limits>
 
 #include "base/json/string_escape.h"
 #include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "starboard/types.h"
 
 namespace base {
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 const char kPrettyPrintLineEnding[] = "\r\n";
 #else
 const char kPrettyPrintLineEnding[] = "\n";
 #endif
 
 // static
-bool JSONWriter::Write(const Value& node, std::string* json) {
-  return WriteWithOptions(node, 0, json);
+bool JSONWriter::Write(ValueView node, std::string* json, size_t max_depth) {
+  return WriteWithOptions(node, 0, json, max_depth);
 }
 
 // static
-bool JSONWriter::WriteWithOptions(const Value& node,
+bool JSONWriter::WriteWithOptions(ValueView node,
                                   int options,
-                                  std::string* json) {
+                                  std::string* json,
+                                  size_t max_depth) {
   json->clear();
   // Is there a better way to estimate the size of the output?
-  json->reserve(1024);
+  if (json->capacity() < 1024) {
+    json->reserve(1024);
+  }
 
-  JSONWriter writer(options, json);
-  bool result = writer.BuildJSONString(node, 0U);
+  JSONWriter writer(options, json, max_depth);
+  bool result = node.Visit([&writer](const auto& member) {
+    return writer.BuildJSONString(member, 0);
+  });
 
-  if (options & OPTIONS_PRETTY_PRINT)
+  if (options & OPTIONS_PRETTY_PRINT) {
     json->append(kPrettyPrintLineEnding);
+  }
 
   return result;
 }
 
-JSONWriter::JSONWriter(int options, std::string* json)
+JSONWriter::JSONWriter(int options, std::string* json, size_t max_depth)
     : omit_binary_values_((options & OPTIONS_OMIT_BINARY_VALUES) != 0),
       omit_double_type_preservation_(
           (options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION) != 0),
       pretty_print_((options & OPTIONS_PRETTY_PRINT) != 0),
-      json_string_(json) {
+      json_string_(json),
+      max_depth_(max_depth),
+      stack_depth_(0) {
   DCHECK(json);
+  CHECK_LE(max_depth, internal::kAbsoluteMaxDepth);
 }
 
-bool JSONWriter::BuildJSONString(const Value& node, size_t depth) {
-  switch (node.type()) {
-    case Value::Type::NONE: {
-      json_string_->append("null");
-      return true;
+bool JSONWriter::BuildJSONString(absl::monostate node, size_t depth) {
+  json_string_->append("null");
+  return true;
+}
+
+bool JSONWriter::BuildJSONString(bool node, size_t depth) {
+  json_string_->append(node ? "true" : "false");
+  return true;
+}
+
+bool JSONWriter::BuildJSONString(int node, size_t depth) {
+  json_string_->append(NumberToString(node));
+  return true;
+}
+
+bool JSONWriter::BuildJSONString(double node, size_t depth) {
+  if (omit_double_type_preservation_ &&
+      IsValueInRangeForNumericType<int64_t>(node) && std::floor(node) == node) {
+    json_string_->append(NumberToString(static_cast<int64_t>(node)));
+    return true;
+  }
+
+  std::string real = NumberToString(node);
+  // Ensure that the number has a .0 if there's no decimal or 'e'.  This
+  // makes sure that when we read the JSON back, it's interpreted as a
+  // real rather than an int.
+  if (real.find_first_of(".eE") == std::string::npos) {
+    real.append(".0");
+  }
+
+  // The JSON spec requires that non-integer values in the range (-1,1)
+  // have a zero before the decimal point - ".52" is not valid, "0.52" is.
+  if (real[0] == '.') {
+    real.insert(0, 1, '0');
+  } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
+    // "-.1" bad "-0.1" good
+    real.insert(1, 1, '0');
+  }
+  json_string_->append(real);
+  return true;
+}
+
+bool JSONWriter::BuildJSONString(StringPiece node, size_t depth) {
+  EscapeJSONString(node, true, json_string_);
+  return true;
+}
+
+bool JSONWriter::BuildJSONString(const Value::BlobStorage& node, size_t depth) {
+  // Successful only if we're allowed to omit it.
+  DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value.";
+  return omit_binary_values_;
+}
+
+bool JSONWriter::BuildJSONString(const Value::Dict& node, size_t depth) {
+  internal::StackMarker depth_check(max_depth_, &stack_depth_);
+
+  if (depth_check.IsTooDeep()) {
+    return false;
+  }
+
+  json_string_->push_back('{');
+  if (pretty_print_) {
+    json_string_->append(kPrettyPrintLineEnding);
+  }
+
+  bool first_value_has_been_output = false;
+  bool result = true;
+  for (const auto [key, value] : node) {
+    if (omit_binary_values_ && value.type() == Value::Type::BINARY) {
+      continue;
     }
 
-    case Value::Type::BOOLEAN: {
-      bool value;
-      bool result = node.GetAsBoolean(&value);
-      DCHECK(result);
-      json_string_->append(value ? "true" : "false");
-      return result;
-    }
-
-    case Value::Type::INTEGER: {
-      int value;
-      bool result = node.GetAsInteger(&value);
-      DCHECK(result);
-      json_string_->append(IntToString(value));
-      return result;
-    }
-
-    case Value::Type::DOUBLE: {
-      double value;
-      bool result = node.GetAsDouble(&value);
-      DCHECK(result);
-      if (omit_double_type_preservation_ &&
-          value <= std::numeric_limits<int64_t>::max() &&
-          value >= std::numeric_limits<int64_t>::min() &&
-          std::floor(value) == value) {
-        json_string_->append(Int64ToString(static_cast<int64_t>(value)));
-        return result;
-      }
-      std::string real = NumberToString(value);
-      // Ensure that the number has a .0 if there's no decimal or 'e'.  This
-      // makes sure that when we read the JSON back, it's interpreted as a
-      // real rather than an int.
-      if (real.find('.') == std::string::npos &&
-          real.find('e') == std::string::npos &&
-          real.find('E') == std::string::npos) {
-        real.append(".0");
-      }
-      // The JSON spec requires that non-integer values in the range (-1,1)
-      // have a zero before the decimal point - ".52" is not valid, "0.52" is.
-      if (real[0] == '.') {
-        real.insert(static_cast<size_t>(0), static_cast<size_t>(1), '0');
-      } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
-        // "-.1" bad "-0.1" good
-        real.insert(static_cast<size_t>(1), static_cast<size_t>(1), '0');
-      }
-      json_string_->append(real);
-      return result;
-    }
-
-    case Value::Type::STRING: {
-      std::string value;
-      bool result = node.GetAsString(&value);
-      DCHECK(result);
-      EscapeJSONString(value, true, json_string_);
-      return result;
-    }
-
-    case Value::Type::LIST: {
-      json_string_->push_back('[');
-      if (pretty_print_)
-        json_string_->push_back(' ');
-
-      const ListValue* list = nullptr;
-      bool first_value_has_been_output = false;
-      bool result = node.GetAsList(&list);
-      DCHECK(result);
-      for (const auto& value : *list) {
-        if (omit_binary_values_ && value.type() == Value::Type::BINARY)
-          continue;
-
-        if (first_value_has_been_output) {
-          json_string_->push_back(',');
-          if (pretty_print_)
-            json_string_->push_back(' ');
-        }
-
-        if (!BuildJSONString(value, depth))
-          result = false;
-
-        first_value_has_been_output = true;
-      }
-
-      if (pretty_print_)
-        json_string_->push_back(' ');
-      json_string_->push_back(']');
-      return result;
-    }
-
-    case Value::Type::DICTIONARY: {
-      json_string_->push_back('{');
-      if (pretty_print_)
-        json_string_->append(kPrettyPrintLineEnding);
-
-      const DictionaryValue* dict = nullptr;
-      bool first_value_has_been_output = false;
-      bool result = node.GetAsDictionary(&dict);
-      DCHECK(result);
-      for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
-           itr.Advance()) {
-        if (omit_binary_values_ && itr.value().type() == Value::Type::BINARY) {
-          continue;
-        }
-
-        if (first_value_has_been_output) {
-          json_string_->push_back(',');
-          if (pretty_print_)
-            json_string_->append(kPrettyPrintLineEnding);
-        }
-
-        if (pretty_print_)
-          IndentLine(depth + 1U);
-
-        EscapeJSONString(itr.key(), true, json_string_);
-        json_string_->push_back(':');
-        if (pretty_print_)
-          json_string_->push_back(' ');
-
-        if (!BuildJSONString(itr.value(), depth + 1U))
-          result = false;
-
-        first_value_has_been_output = true;
-      }
-
+    if (first_value_has_been_output) {
+      json_string_->push_back(',');
       if (pretty_print_) {
         json_string_->append(kPrettyPrintLineEnding);
-        IndentLine(depth);
       }
-
-      json_string_->push_back('}');
-      return result;
     }
 
-    case Value::Type::BINARY:
-      // Successful only if we're allowed to omit it.
-      DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value.";
-      return omit_binary_values_;
+    if (pretty_print_) {
+      IndentLine(depth + 1U);
+    }
+
+    EscapeJSONString(key, true, json_string_);
+    json_string_->push_back(':');
+    if (pretty_print_) {
+      json_string_->push_back(' ');
+    }
+
+    result &= value.Visit([this, depth = depth + 1](const auto& member) {
+      return BuildJSONString(member, depth);
+    });
+
+    first_value_has_been_output = true;
   }
-  NOTREACHED();
-  return false;
+
+  if (pretty_print_) {
+    if (first_value_has_been_output) {
+      json_string_->append(kPrettyPrintLineEnding);
+    }
+    IndentLine(depth);
+  }
+
+  json_string_->push_back('}');
+  return result;
+}
+
+bool JSONWriter::BuildJSONString(const Value::List& node, size_t depth) {
+  internal::StackMarker depth_check(max_depth_, &stack_depth_);
+
+  if (depth_check.IsTooDeep()) {
+    return false;
+  }
+
+  json_string_->push_back('[');
+  if (pretty_print_) {
+    json_string_->push_back(' ');
+  }
+
+  bool first_value_has_been_output = false;
+  bool result = true;
+  for (const auto& value : node) {
+    if (omit_binary_values_ && value.type() == Value::Type::BINARY) {
+      continue;
+    }
+
+    if (first_value_has_been_output) {
+      json_string_->push_back(',');
+      if (pretty_print_) {
+        json_string_->push_back(' ');
+      }
+    }
+
+    result &= value.Visit([this, depth](const auto& member) {
+      return BuildJSONString(member, depth);
+    });
+
+    first_value_has_been_output = true;
+  }
+
+  if (pretty_print_) {
+    json_string_->push_back(' ');
+  }
+  json_string_->push_back(']');
+  return result;
 }
 
 void JSONWriter::IndentLine(size_t depth) {
   json_string_->append(depth * 3U, ' ');
 }
 
+absl::optional<std::string> WriteJson(ValueView node, size_t max_depth) {
+  std::string result;
+  if (!JSONWriter::Write(node, &result, max_depth)) {
+    return absl::nullopt;
+  }
+  return result;
+}
+
+absl::optional<std::string> WriteJsonWithOptions(ValueView node,
+                                                 uint32_t options,
+                                                 size_t max_depth) {
+  std::string result;
+  if (!JSONWriter::WriteWithOptions(node, static_cast<int>(options), &result,
+                                    max_depth)) {
+    return absl::nullopt;
+  }
+  return result;
+}
+
 }  // namespace base
diff --git a/base/json/json_writer.h b/base/json/json_writer.h
index a260432..ddb943d 100644
--- a/base/json/json_writer.h
+++ b/base/json/json_writer.h
@@ -1,60 +1,114 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_JSON_JSON_WRITER_H_
 #define BASE_JSON_JSON_WRITER_H_
 
+#include <stddef.h>
+#include <cstdint>
 #include <string>
 
 #include "base/base_export.h"
-#include "base/macros.h"
-#include "starboard/types.h"
+#include "base/json/json_common.h"
+#include "base/memory/raw_ptr.h"
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 
-class Value;
+enum JsonOptions {
+  // This option instructs the writer that if a Binary value is encountered,
+  // the value (and key if within a dictionary) will be omitted from the
+  // output, and success will be returned. Otherwise, if a binary value is
+  // encountered, failure will be returned.
+  OPTIONS_OMIT_BINARY_VALUES = 1 << 0,
+
+  // This option instructs the writer to write doubles that have no fractional
+  // part as a normal integer (i.e., without using exponential notation
+  // or appending a '.0') as long as the value is within the range of a
+  // 64-bit int.
+  OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION = 1 << 1,
+
+  // Return a slightly nicer formatted json string (pads with whitespace to
+  // help with readability).
+  OPTIONS_PRETTY_PRINT = 1 << 2,
+};
+
+// Given a root node, generates and returns a JSON string.
+//
+// Returns `absl::nullopt` if
+//    * the nesting depth exceeds `max_depth`, or
+//    * the JSON contains binary values.
+BASE_EXPORT absl::optional<std::string> WriteJson(
+    ValueView node,
+    size_t max_depth = internal::kAbsoluteMaxDepth);
+
+// Given a root node, generates and returns a JSON string.
+// The string is formatted according to `options` which is a bitmask of
+// `JsonOptions`.
+//
+// Returns `absl::nullopt` if
+//    * the nesting depth exceeds `max_depth,` or
+//    * the JSON contains binary values
+//      (unless `JsonOptions::OPTIONS_OMIT_BINARY_VALUES` is passed).
+BASE_EXPORT absl::optional<std::string> WriteJsonWithOptions(
+    ValueView node,
+    uint32_t options,
+    size_t max_depth = internal::kAbsoluteMaxDepth);
 
 class BASE_EXPORT JSONWriter {
  public:
-  enum Options {
-    // This option instructs the writer that if a Binary value is encountered,
-    // the value (and key if within a dictionary) will be omitted from the
-    // output, and success will be returned. Otherwise, if a binary value is
-    // encountered, failure will be returned.
-    OPTIONS_OMIT_BINARY_VALUES = 1 << 0,
+  using Options = JsonOptions;
+  // TODO: Once we support c++20 we replace these with
+  // `using enum ::JsonOptions`.
+  static constexpr auto OPTIONS_OMIT_BINARY_VALUES =
+      JsonOptions::OPTIONS_OMIT_BINARY_VALUES;
+  static constexpr auto OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION =
+      JsonOptions::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION;
+  static constexpr auto OPTIONS_PRETTY_PRINT =
+      JsonOptions::OPTIONS_PRETTY_PRINT;
 
-    // This option instructs the writer to write doubles that have no fractional
-    // part as a normal integer (i.e., without using exponential notation
-    // or appending a '.0') as long as the value is within the range of a
-    // 64-bit int.
-    OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION = 1 << 1,
-
-    // Return a slightly nicer formatted json string (pads with whitespace to
-    // help with readability).
-    OPTIONS_PRETTY_PRINT = 1 << 2,
-  };
+  JSONWriter(const JSONWriter&) = delete;
+  JSONWriter& operator=(const JSONWriter&) = delete;
 
   // Given a root node, generates a JSON string and puts it into |json|.
   // The output string is overwritten and not appended.
   //
   // TODO(tc): Should we generate json if it would be invalid json (e.g.,
-  // |node| is not a DictionaryValue/ListValue or if there are inf/-inf float
+  // |node| is not a dictionary/list Value or if there are inf/-inf float
   // values)? Return true on success and false on failure.
-  static bool Write(const Value& node, std::string* json);
+  //
+  // Deprecated: use the standalone method `WriteJson()` instead.
+  static bool Write(ValueView node,
+                    std::string* json,
+                    size_t max_depth = internal::kAbsoluteMaxDepth);
 
   // Same as above but with |options| which is a bunch of JSONWriter::Options
   // bitwise ORed together. Return true on success and false on failure.
-  static bool WriteWithOptions(const Value& node,
+  //
+  // Deprecated: use the standalone method `WriteJsonWithOptions()` instead.
+  static bool WriteWithOptions(ValueView node,
                                int options,
-                               std::string* json);
+                               std::string* json,
+                               size_t max_depth = internal::kAbsoluteMaxDepth);
 
  private:
-  JSONWriter(int options, std::string* json);
+  JSONWriter(int options,
+             std::string* json,
+             size_t max_depth = internal::kAbsoluteMaxDepth);
 
   // Called recursively to build the JSON string. When completed,
   // |json_string_| will contain the JSON.
-  bool BuildJSONString(const Value& node, size_t depth);
+  bool BuildJSONString(absl::monostate node, size_t depth);
+  bool BuildJSONString(bool node, size_t depth);
+  bool BuildJSONString(int node, size_t depth);
+  bool BuildJSONString(double node, size_t depth);
+  bool BuildJSONString(StringPiece node, size_t depth);
+  bool BuildJSONString(const Value::BlobStorage& node, size_t depth);
+  bool BuildJSONString(const Value::Dict& node, size_t depth);
+  bool BuildJSONString(const Value::List& node, size_t depth);
 
   // Adds space to json_string_ for the indent level.
   void IndentLine(size_t depth);
@@ -64,9 +118,13 @@
   bool pretty_print_;
 
   // Where we write JSON data as we generate it.
-  std::string* json_string_;
+  raw_ptr<std::string> json_string_;
 
-  DISALLOW_COPY_AND_ASSIGN(JSONWriter);
+  // Maximum depth to write.
+  const size_t max_depth_;
+
+  // The number of times the writer has recursed (current stack depth).
+  size_t stack_depth_;
 };
 
 }  // namespace base
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc
index 2d81af3..0fc6da9 100644
--- a/base/json/json_writer_unittest.cc
+++ b/base/json/json_writer_unittest.cc
@@ -1,154 +1,235 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/json_writer.h"
+#include "base/json/json_reader.h"
 
-#include "base/memory/ptr_util.h"
+#include "base/containers/span.h"
+#include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+#if BUILDFLAG(IS_WIN)
+#include "base/strings/string_util.h"
+#endif
 
 namespace base {
 
-TEST(JSONWriterTest, BasicTypes) {
-  std::string output_js;
+namespace {
 
-  // Test null.
-  EXPECT_TRUE(JSONWriter::Write(Value(), &output_js));
-  EXPECT_EQ("null", output_js);
-
-  // Test empty dict.
-  EXPECT_TRUE(JSONWriter::Write(DictionaryValue(), &output_js));
-  EXPECT_EQ("{}", output_js);
-
-  // Test empty list.
-  EXPECT_TRUE(JSONWriter::Write(ListValue(), &output_js));
-  EXPECT_EQ("[]", output_js);
-
-  // Test integer values.
-  EXPECT_TRUE(JSONWriter::Write(Value(42), &output_js));
-  EXPECT_EQ("42", output_js);
-
-  // Test boolean values.
-  EXPECT_TRUE(JSONWriter::Write(Value(true), &output_js));
-  EXPECT_EQ("true", output_js);
-
-  // Test Real values should always have a decimal or an 'e'.
-  EXPECT_TRUE(JSONWriter::Write(Value(1.0), &output_js));
-  EXPECT_EQ("1.0", output_js);
-
-  // Test Real values in the the range (-1, 1) must have leading zeros
-  EXPECT_TRUE(JSONWriter::Write(Value(0.2), &output_js));
-  EXPECT_EQ("0.2", output_js);
-
-  // Test Real values in the the range (-1, 1) must have leading zeros
-  EXPECT_TRUE(JSONWriter::Write(Value(-0.8), &output_js));
-  EXPECT_EQ("-0.8", output_js);
-
-  // Test String values.
-  EXPECT_TRUE(JSONWriter::Write(Value("foo"), &output_js));
-  EXPECT_EQ("\"foo\"", output_js);
-}
-
-TEST(JSONWriterTest, NestedTypes) {
-  std::string output_js;
-
-  // Writer unittests like empty list/dict nesting,
-  // list list nesting, etc.
-  DictionaryValue root_dict;
-  std::unique_ptr<ListValue> list(new ListValue());
-  std::unique_ptr<DictionaryValue> inner_dict(new DictionaryValue());
-  inner_dict->SetInteger("inner int", 10);
-  list->Append(std::move(inner_dict));
-  list->Append(std::make_unique<ListValue>());
-  list->AppendBoolean(true);
-  root_dict.Set("list", std::move(list));
-
-  // Test the pretty-printer.
-  EXPECT_TRUE(JSONWriter::Write(root_dict, &output_js));
-  EXPECT_EQ("{\"list\":[{\"inner int\":10},[],true]}", output_js);
-  EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      root_dict, JSONWriter::OPTIONS_PRETTY_PRINT, &output_js));
-
+std::string FixNewlines(const std::string& json) {
   // The pretty-printer uses a different newline style on Windows than on
   // other platforms.
-#if defined(OS_WIN)
-#define JSON_NEWLINE "\r\n"
+#if BUILDFLAG(IS_WIN)
+  std::string result;
+  ReplaceChars(json, "\n", "\r\n", &result);
+  return result;
 #else
-#define JSON_NEWLINE "\n"
+  return json;
 #endif
-  EXPECT_EQ("{" JSON_NEWLINE
-            "   \"list\": [ {" JSON_NEWLINE
-            "      \"inner int\": 10" JSON_NEWLINE
-            "   }, [  ], true ]" JSON_NEWLINE
-            "}" JSON_NEWLINE,
-            output_js);
-#undef JSON_NEWLINE
 }
 
-TEST(JSONWriterTest, KeysWithPeriods) {
-  std::string output_js;
+}  // namespace
 
-  DictionaryValue period_dict;
-  period_dict.SetKey("a.b", base::Value(3));
-  period_dict.SetKey("c", base::Value(2));
-  std::unique_ptr<DictionaryValue> period_dict2(new DictionaryValue());
-  period_dict2->SetKey("g.h.i.j", base::Value(1));
-  period_dict.SetWithoutPathExpansion("d.e.f", std::move(period_dict2));
-  EXPECT_TRUE(JSONWriter::Write(period_dict, &output_js));
-  EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
+TEST(JsonWriterTest, BasicTypes) {
+  // Test null.
+  EXPECT_EQ(WriteJson(Value()), "null");
 
-  DictionaryValue period_dict3;
-  period_dict3.SetInteger("a.b", 2);
-  period_dict3.SetKey("a.b", base::Value(1));
-  EXPECT_TRUE(JSONWriter::Write(period_dict3, &output_js));
-  EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
+  // Test empty dict.
+  EXPECT_EQ(WriteJson(Value(Value::Type::DICT)), "{}");
+
+  // Test empty list.
+  EXPECT_EQ(WriteJson(Value(Value::Type::LIST)), "[]");
+
+  // Test integer values.
+  EXPECT_EQ(WriteJson(Value(42)), "42");
+
+  // Test boolean values.
+  EXPECT_EQ(WriteJson(Value(true)), "true");
+
+  // Test Real values should always have a decimal or an 'e'.
+  EXPECT_EQ(WriteJson(Value(1.0)), "1.0");
+
+  // Test Real values in the range (-1, 1) must have leading zeros
+  EXPECT_EQ(WriteJson(Value(0.2)), "0.2");
+
+  // Test Real values in the range (-1, 1) must have leading zeros
+  EXPECT_EQ(WriteJson(Value(-0.8)), "-0.8");
+
+  // Test String values.
+  EXPECT_EQ(WriteJson(Value("foo")), "\"foo\"");
 }
 
-TEST(JSONWriterTest, BinaryValues) {
-  std::string output_js;
+TEST(JsonWriterTest, NestedTypes) {
+  // Writer unittests like empty list/dict nesting,
+  // list list nesting, etc.
+  auto dict =
+      Value::Dict().Set("list", Value::List()
+                                    .Append(Value::Dict().Set("inner int", 10))
+                                    .Append(Value::Dict())
+                                    .Append(Value::List())
+                                    .Append(true));
+
+  EXPECT_EQ(WriteJson(dict), "{\"list\":[{\"inner int\":10},{},[],true]}");
+
+  // Test the pretty-printer.
+  EXPECT_EQ(WriteJsonWithOptions(dict, JSONWriter::OPTIONS_PRETTY_PRINT),
+            FixNewlines(R"({
+   "list": [ {
+      "inner int": 10
+   }, {
+   }, [  ], true ]
+}
+)"));
+}
+
+TEST(JsonWriterTest, KeysWithPeriods) {
+  EXPECT_EQ(WriteJson(Value::Dict()  //
+                          .Set("a.b", 3)
+                          .Set("c", 2)
+                          .Set("d.e.f", Value::Dict().Set("g.h.i.j", 1))),
+            R"({"a.b":3,"c":2,"d.e.f":{"g.h.i.j":1}})");
+
+  EXPECT_EQ(WriteJson(Value::Dict()  //
+                          .Set("a", Value::Dict().Set("b", 2))
+                          .Set("a.b", 1)),
+            R"({"a":{"b":2},"a.b":1})");
+}
+
+TEST(JsonWriterTest, BinaryValues) {
+  const auto kBinaryData =
+      base::make_span(reinterpret_cast<const uint8_t*>("asdf"), 4u);
 
   // Binary values should return errors unless suppressed via the
-  // OPTIONS_OMIT_BINARY_VALUES flag.
-  std::unique_ptr<Value> root(Value::CreateWithCopiedBuffer("asdf", 4));
-  EXPECT_FALSE(JSONWriter::Write(*root, &output_js));
-  EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      *root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
-  EXPECT_TRUE(output_js.empty());
+  // `OPTIONS_OMIT_BINARY_VALUES` flag.
+  EXPECT_EQ(WriteJson(Value(kBinaryData)), absl::nullopt);
+  EXPECT_EQ(WriteJsonWithOptions(Value(kBinaryData),
+                                 JsonOptions::OPTIONS_OMIT_BINARY_VALUES),
+            "");
 
-  ListValue binary_list;
-  binary_list.Append(Value::CreateWithCopiedBuffer("asdf", 4));
-  binary_list.Append(std::make_unique<Value>(5));
-  binary_list.Append(Value::CreateWithCopiedBuffer("asdf", 4));
-  binary_list.Append(std::make_unique<Value>(2));
-  binary_list.Append(Value::CreateWithCopiedBuffer("asdf", 4));
-  EXPECT_FALSE(JSONWriter::Write(binary_list, &output_js));
-  EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
-  EXPECT_EQ("[5,2]", output_js);
+  auto binary_list = Value::List()
+                         .Append(Value(kBinaryData))
+                         .Append(5)
+                         .Append(Value(kBinaryData))
+                         .Append(2)
+                         .Append(Value(kBinaryData));
+  EXPECT_EQ(WriteJson(binary_list), absl::nullopt);
+  EXPECT_EQ(
+      WriteJsonWithOptions(binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES),
+      "[5,2]");
 
-  DictionaryValue binary_dict;
-  binary_dict.Set("a", Value::CreateWithCopiedBuffer("asdf", 4));
-  binary_dict.SetInteger("b", 5);
-  binary_dict.Set("c", Value::CreateWithCopiedBuffer("asdf", 4));
-  binary_dict.SetInteger("d", 2);
-  binary_dict.Set("e", Value::CreateWithCopiedBuffer("asdf", 4));
-  EXPECT_FALSE(JSONWriter::Write(binary_dict, &output_js));
-  EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
-  EXPECT_EQ("{\"b\":5,\"d\":2}", output_js);
+  auto binary_dict = Value::Dict()
+                         .Set("a", Value(kBinaryData))
+                         .Set("b", 5)
+                         .Set("c", Value(kBinaryData))
+                         .Set("d", 2)
+                         .Set("e", Value(kBinaryData));
+  EXPECT_EQ(WriteJson(binary_dict), absl::nullopt);
+  EXPECT_EQ(
+      WriteJsonWithOptions(binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES),
+      R"({"b":5,"d":2})");
 }
 
-TEST(JSONWriterTest, DoublesAsInts) {
-  std::string output_js;
-
+TEST(JsonWriterTest, DoublesAsInts) {
   // Test allowing a double with no fractional part to be written as an integer.
   Value double_value(1e10);
+  EXPECT_EQ(
+      WriteJsonWithOptions(double_value,
+                           JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION),
+      "10000000000");
+}
+
+TEST(JsonWriterTest, StackOverflow) {
+  Value::List deep_list;
+  const size_t max_depth = 100000;
+
+  for (size_t i = 0; i < max_depth; ++i) {
+    Value::List new_top_list;
+    new_top_list.Append(std::move(deep_list));
+    deep_list = std::move(new_top_list);
+  }
+
+  Value deep_list_value(std::move(deep_list));
+  EXPECT_EQ(WriteJson(deep_list_value), absl::nullopt);
+  EXPECT_EQ(
+      WriteJsonWithOptions(deep_list_value, JSONWriter::OPTIONS_PRETTY_PRINT),
+      absl::nullopt);
+
+  // We cannot just let `deep_list` tear down since it
+  // would cause a stack overflow. Therefore, we tear
+  // down the deep list manually.
+  deep_list = std::move(deep_list_value).TakeList();
+  while (!deep_list.empty()) {
+    DCHECK_EQ(deep_list.size(), 1u);
+    Value::List inner_list = std::move(deep_list[0]).TakeList();
+    deep_list = std::move(inner_list);
+  }
+}
+
+TEST(JsonWriterTest, TestMaxDepthWithValidNodes) {
+  // Create JSON to the max depth - 1.  Nodes at that depth are still valid
+  // for writing which matches the JSONParser logic.
+  std::string nested_json;
+  for (int i = 0; i < 199; ++i) {
+    std::string node = "[";
+    for (int j = 0; j < 5; j++) {
+      node.append(StringPrintf("%d,", j));
+    }
+    nested_json.insert(0, node);
+    nested_json.append("]");
+  }
+
+  // Ensure we can read and write the JSON
+  auto json_val = JSONReader::ReadAndReturnValueWithError(
+      nested_json, JSON_ALLOW_TRAILING_COMMAS);
+  EXPECT_TRUE(json_val.has_value());
+  const Value& value = *json_val;
+  EXPECT_NE(WriteJson(value), absl::nullopt);
+}
+
+// Test that the JSONWriter::Write method still works.
+TEST(JsonWriterTest, JSONWriterWriteSuccess) {
+  std::string output_js;
+
+  EXPECT_TRUE(
+      JSONWriter::Write(base::Value::Dict().Set("key", "value"), &output_js));
+  EXPECT_EQ(output_js, R"({"key":"value"})");
+}
+
+// Test that the JSONWriter::Write method still works.
+TEST(JsonWriterTest, JSONWriterWriteFailure) {
+  std::string output_js;
+
+  EXPECT_FALSE(JSONWriter::Write(
+      base::Value::Dict()  //
+          .Set("key",
+               base::Value::Dict().Set("nested-key", base::Value::Dict())),
+      &output_js, /*max_depth=*/1));
+}
+
+// Test that the JSONWriter::WriteWithOptions method still works.
+TEST(JsonWriterTest, JSONWriterWriteWithOptionsSuccess) {
+  std::string output_js;
   EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      double_value, JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
+      base::Value::Dict().Set("key", "value"), JSONWriter::OPTIONS_PRETTY_PRINT,
       &output_js));
-  EXPECT_EQ("10000000000", output_js);
+  EXPECT_EQ(output_js, FixNewlines(R"({
+   "key": "value"
+}
+)"));
+}
+
+// Test that the JSONWriter::WriteWithOptions method still works.
+TEST(JsonWriterTest, JSONWriterWriteWithOptionsFailure) {
+  std::string output_js;
+
+  EXPECT_FALSE(JSONWriter::WriteWithOptions(
+      base::Value::Dict().Set(
+          "key", base::Value::Dict().Set("nested-key", base::Value::Dict())),
+      JSONWriter::OPTIONS_PRETTY_PRINT, &output_js, /*max_depth=*/1));
 }
 
 }  // namespace base
diff --git a/base/json/string_escape.cc b/base/json/string_escape.cc
index d866c14..84db0f8 100644
--- a/base/json/string_escape.cc
+++ b/base/json/string_escape.cc
@@ -1,18 +1,21 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright 2006-2008 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/string_escape.h"
 
+#include <stddef.h>
+#include <stdint.h>
+
 #include <limits>
 #include <string>
 
+#include "base/check_op.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversion_utils.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/third_party/icu/icu_utf.h"
-#include "starboard/types.h"
 
 namespace base {
 
@@ -22,7 +25,7 @@
 const char kU16EscapeFormat[] = "\\u%04X";
 
 // The code point to output for an invalid input code unit.
-const uint32_t kReplacementCodePoint = 0xFFFD;
+const base_icu::UChar32 kReplacementCodePoint = 0xFFFD;
 
 // Used below in EscapeSpecialCodePoint().
 static_assert('<' == 0x3C, "less than sign must be 0x3c");
@@ -30,7 +33,7 @@
 // Try to escape the |code_point| if it is a known special character. If
 // successful, returns true and appends the escape sequence to |dest|. This
 // isn't required by the spec, but it's more readable by humans.
-bool EscapeSpecialCodePoint(uint32_t code_point, std::string* dest) {
+bool EscapeSpecialCodePoint(base_icu::UChar32 code_point, std::string* dest) {
   // WARNING: if you add a new case here, you need to update the reader as well.
   // Note: \v is in the reader, but not here since the JSON spec doesn't
   // allow it.
@@ -82,16 +85,11 @@
   if (put_in_quotes)
     dest->push_back('"');
 
-  // Casting is necessary because ICU uses int32_t. Try and do so safely.
-  CHECK_LE(str.length(),
-           static_cast<size_t>(std::numeric_limits<int32_t>::max()));
-  const int32_t length = static_cast<int32_t>(str.length());
-
-  for (int32_t i = 0; i < length; ++i) {
-    uint32_t code_point;
+  const size_t length = str.length();
+  for (size_t i = 0; i < length; ++i) {
+    base_icu::UChar32 code_point;
     if (!ReadUnicodeCharacter(str.data(), length, &i, &code_point) ||
-        code_point == static_cast<decltype(code_point)>(CBU_SENTINEL) ||
-        !IsValidCharacter(code_point)) {
+        code_point == CBU_SENTINEL) {
       code_point = kReplacementCodePoint;
       did_replacement = true;
     }
@@ -126,15 +124,13 @@
 
 std::string GetQuotedJSONString(StringPiece str) {
   std::string dest;
-  bool ok = EscapeJSONStringImpl(str, true, &dest);
-  DCHECK(ok);
+  EscapeJSONStringImpl(str, true, &dest);
   return dest;
 }
 
 std::string GetQuotedJSONString(StringPiece16 str) {
   std::string dest;
-  bool ok = EscapeJSONStringImpl(str, true, &dest);
-  DCHECK(ok);
+  EscapeJSONStringImpl(str, true, &dest);
   return dest;
 }
 
@@ -145,15 +141,16 @@
   if (put_in_quotes)
     dest.push_back('"');
 
-  for (StringPiece::const_iterator it = str.begin(); it != str.end(); ++it) {
-    unsigned char c = *it;
+  for (char c : str) {
     if (EscapeSpecialCodePoint(c, &dest))
       continue;
 
-    if (c < 32 || c > 126)
-      base::StringAppendF(&dest, kU16EscapeFormat, c);
-    else
-      dest.push_back(*it);
+    if (c < 32 || c > 126) {
+      base::StringAppendF(&dest, kU16EscapeFormat,
+                          static_cast<unsigned char>(c));
+    } else {
+      dest.push_back(c);
+    }
   }
 
   if (put_in_quotes)
diff --git a/base/json/string_escape.h b/base/json/string_escape.h
index f75f475..ca7f7fa 100644
--- a/base/json/string_escape.h
+++ b/base/json/string_escape.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -52,7 +52,7 @@
 // interpret it as UTF-16 and convert it to UTF-8.
 //
 // The output of this function takes the *appearance* of JSON but is not in
-// fact valid according to RFC 4627.
+// fact valid according to RFC 8259.
 BASE_EXPORT std::string EscapeBytesAsInvalidJSONString(StringPiece str,
                                                        bool put_in_quotes);
 
diff --git a/base/json/string_escape_fuzzer.cc b/base/json/string_escape_fuzzer.cc
index 3cd8509..9a63aab 100644
--- a/base/json/string_escape_fuzzer.cc
+++ b/base/json/string_escape_fuzzer.cc
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,8 +6,6 @@
 
 #include <memory>
 
-#include "starboard/memory.h"
-
 // Entry point for LibFuzzer.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   if (size < 2)
@@ -30,8 +28,8 @@
     return 0;
 
   size_t actual_size_char16 = actual_size_char8 / 2;
-  base::StringPiece16 input_string16(
-      reinterpret_cast<base::char16*>(input.get()), actual_size_char16);
+  base::StringPiece16 input_string16(reinterpret_cast<char16_t*>(input.get()),
+                                     actual_size_char16);
   escaped_string.clear();
   base::EscapeJSONString(input_string16, put_in_quotes, &escaped_string);
 
diff --git a/base/json/string_escape_unittest.cc b/base/json/string_escape_unittest.cc
index bc7f3c2..0a4106e 100644
--- a/base/json/string_escape_unittest.cc
+++ b/base/json/string_escape_unittest.cc
@@ -1,13 +1,13 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/json/string_escape.h"
 
-#include "base/macros.h"
+#include <stddef.h>
+
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "starboard/types.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -22,43 +22,78 @@
       {"b\x0f\x7f\xf0\xff!",  // \xf0\xff is not a valid UTF-8 unit.
        "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"},
       {"c<>d", "c\\u003C>d"},
-      {"Hello\xe2\x80\xa8world", "Hello\\u2028world"},
-      {"\xe2\x80\xa9purple", "\\u2029purple"},
-      {"\xF3\xBF\xBF\xBF", "\xEF\xBF\xBD"},
+      {"Hello\xE2\x80\xA8world", "Hello\\u2028world"},  // U+2028
+      {"\xE2\x80\xA9purple", "\\u2029purple"},          // U+2029
+      // Unicode non-characters.
+      {"\xEF\xB7\x90", "\xEF\xB7\x90"},          // U+FDD0
+      {"\xEF\xB7\x9F", "\xEF\xB7\x9F"},          // U+FDDF
+      {"\xEF\xB7\xAF", "\xEF\xB7\xAF"},          // U+FDEF
+      {"\xEF\xBF\xBE", "\xEF\xBF\xBE"},          // U+FFFE
+      {"\xEF\xBF\xBF", "\xEF\xBF\xBF"},          // U+FFFF
+      {"\xF0\x9F\xBF\xBE", "\xF0\x9F\xBF\xBE"},  // U+01FFFE
+      {"\xF0\x9F\xBF\xBF", "\xF0\x9F\xBF\xBF"},  // U+01FFFF
+      {"\xF0\xAF\xBF\xBE", "\xF0\xAF\xBF\xBE"},  // U+02FFFE
+      {"\xF0\xAF\xBF\xBF", "\xF0\xAF\xBF\xBF"},  // U+02FFFF
+      {"\xF0\xBF\xBF\xBE", "\xF0\xBF\xBF\xBE"},  // U+03FFFE
+      {"\xF0\xBF\xBF\xBF", "\xF0\xBF\xBF\xBF"},  // U+03FFFF
+      {"\xF1\x8F\xBF\xBE", "\xF1\x8F\xBF\xBE"},  // U+04FFFE
+      {"\xF1\x8F\xBF\xBF", "\xF1\x8F\xBF\xBF"},  // U+04FFFF
+      {"\xF1\x9F\xBF\xBE", "\xF1\x9F\xBF\xBE"},  // U+05FFFE
+      {"\xF1\x9F\xBF\xBF", "\xF1\x9F\xBF\xBF"},  // U+05FFFF
+      {"\xF1\xAF\xBF\xBE", "\xF1\xAF\xBF\xBE"},  // U+06FFFE
+      {"\xF1\xAF\xBF\xBF", "\xF1\xAF\xBF\xBF"},  // U+06FFFF
+      {"\xF1\xBF\xBF\xBE", "\xF1\xBF\xBF\xBE"},  // U+07FFFE
+      {"\xF1\xBF\xBF\xBF", "\xF1\xBF\xBF\xBF"},  // U+07FFFF
+      {"\xF2\x8F\xBF\xBE", "\xF2\x8F\xBF\xBE"},  // U+08FFFE
+      {"\xF2\x8F\xBF\xBF", "\xF2\x8F\xBF\xBF"},  // U+08FFFF
+      {"\xF2\x9F\xBF\xBE", "\xF2\x9F\xBF\xBE"},  // U+09FFFE
+      {"\xF2\x9F\xBF\xBF", "\xF2\x9F\xBF\xBF"},  // U+09FFFF
+      {"\xF2\xAF\xBF\xBE", "\xF2\xAF\xBF\xBE"},  // U+0AFFFE
+      {"\xF2\xAF\xBF\xBF", "\xF2\xAF\xBF\xBF"},  // U+0AFFFF
+      {"\xF2\xBF\xBF\xBE", "\xF2\xBF\xBF\xBE"},  // U+0BFFFE
+      {"\xF2\xBF\xBF\xBF", "\xF2\xBF\xBF\xBF"},  // U+0BFFFF
+      {"\xF3\x8F\xBF\xBE", "\xF3\x8F\xBF\xBE"},  // U+0CFFFE
+      {"\xF3\x8F\xBF\xBF", "\xF3\x8F\xBF\xBF"},  // U+0CFFFF
+      {"\xF3\x9F\xBF\xBE", "\xF3\x9F\xBF\xBE"},  // U+0DFFFE
+      {"\xF3\x9F\xBF\xBF", "\xF3\x9F\xBF\xBF"},  // U+0DFFFF
+      {"\xF3\xAF\xBF\xBE", "\xF3\xAF\xBF\xBE"},  // U+0EFFFE
+      {"\xF3\xAF\xBF\xBF", "\xF3\xAF\xBF\xBF"},  // U+0EFFFF
+      {"\xF3\xBF\xBF\xBE", "\xF3\xBF\xBF\xBE"},  // U+0FFFFE
+      {"\xF3\xBF\xBF\xBF", "\xF3\xBF\xBF\xBF"},  // U+0FFFFF
+      {"\xF4\x8F\xBF\xBE", "\xF4\x8F\xBF\xBE"},  // U+10FFFE
+      {"\xF4\x8F\xBF\xBF", "\xF4\x8F\xBF\xBF"},  // U+10FFFF
   };
 
-  for (size_t i = 0; i < arraysize(cases); ++i) {
-    const char* in_ptr = cases[i].to_escape;
+  for (const auto& i : cases) {
+    const char* in_ptr = i.to_escape;
     std::string in_str = in_ptr;
 
     std::string out;
     EscapeJSONString(in_ptr, false, &out);
-    EXPECT_EQ(std::string(cases[i].escaped), out);
-    EXPECT_TRUE(IsStringUTF8(out));
+    EXPECT_EQ(std::string(i.escaped), out);
+    EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
 
     out.erase();
-    bool convert_ok = EscapeJSONString(in_str, false, &out);
-    EXPECT_EQ(std::string(cases[i].escaped), out);
-    EXPECT_TRUE(IsStringUTF8(out));
+    EscapeJSONString(in_str, false, &out);
+    EXPECT_EQ(std::string(i.escaped), out);
+    EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
 
-    if (convert_ok) {
-      std::string fooout = GetQuotedJSONString(in_str);
-      EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", fooout);
-      EXPECT_TRUE(IsStringUTF8(out));
-    }
+    std::string fooout = GetQuotedJSONString(in_str);
+    EXPECT_EQ("\"" + std::string(i.escaped) + "\"", fooout);
+    EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
   }
 
   std::string in = cases[0].to_escape;
   std::string out;
   EscapeJSONString(in, false, &out);
-  EXPECT_TRUE(IsStringUTF8(out));
+  EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
 
   // test quoting
   std::string out_quoted;
   EscapeJSONString(in, true, &out_quoted);
   EXPECT_EQ(out.length() + 2, out_quoted.length());
   EXPECT_EQ(out_quoted.find(out), 1U);
-  EXPECT_TRUE(IsStringUTF8(out_quoted));
+  EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out_quoted));
 
   // now try with a NULL in the string
   std::string null_prepend = "test";
@@ -69,7 +104,7 @@
   out.clear();
   EscapeJSONString(in, false, &out);
   EXPECT_EQ(expected, out);
-  EXPECT_TRUE(IsStringUTF8(out));
+  EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
 }
 
 TEST(JSONStringEscapeTest, EscapeUTF16) {
@@ -77,43 +112,80 @@
     const wchar_t* to_escape;
     const char* escaped;
   } cases[] = {
-    {L"b\uffb1\u00ff", "b\xEF\xBE\xB1\xC3\xBF"},
-    {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
-    {L"a\b\f\n\r\t\v\1\\.\"z",
-        "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
-    {L"b\x0f\x7f\xf0\xff!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"},
-    {L"c<>d", "c\\u003C>d"},
-    {L"Hello\u2028world", "Hello\\u2028world"},
-    {L"\u2029purple", "\\u2029purple"},
+      {L"b\uffb1\u00ff", "b\xEF\xBE\xB1\xC3\xBF"},
+      {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
+      {L"a\b\f\n\r\t\v\1\\.\"z", "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
+      {L"b\x0F\x7F\xF0\xFF!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"},
+      {L"c<>d", "c\\u003C>d"},
+      {L"Hello\u2028world", "Hello\\u2028world"},
+      {L"\u2029purple", "\\u2029purple"},
+      // Unicode non-characters.
+      {L"\uFDD0", "\xEF\xB7\x90"},          // U+FDD0
+      {L"\uFDDF", "\xEF\xB7\x9F"},          // U+FDDF
+      {L"\uFDEF", "\xEF\xB7\xAF"},          // U+FDEF
+      {L"\uFFFE", "\xEF\xBF\xBE"},          // U+FFFE
+      {L"\uFFFF", "\xEF\xBF\xBF"},          // U+FFFF
+      {L"\U0001FFFE", "\xF0\x9F\xBF\xBE"},  // U+01FFFE
+      {L"\U0001FFFF", "\xF0\x9F\xBF\xBF"},  // U+01FFFF
+      {L"\U0002FFFE", "\xF0\xAF\xBF\xBE"},  // U+02FFFE
+      {L"\U0002FFFF", "\xF0\xAF\xBF\xBF"},  // U+02FFFF
+      {L"\U0003FFFE", "\xF0\xBF\xBF\xBE"},  // U+03FFFE
+      {L"\U0003FFFF", "\xF0\xBF\xBF\xBF"},  // U+03FFFF
+      {L"\U0004FFFE", "\xF1\x8F\xBF\xBE"},  // U+04FFFE
+      {L"\U0004FFFF", "\xF1\x8F\xBF\xBF"},  // U+04FFFF
+      {L"\U0005FFFE", "\xF1\x9F\xBF\xBE"},  // U+05FFFE
+      {L"\U0005FFFF", "\xF1\x9F\xBF\xBF"},  // U+05FFFF
+      {L"\U0006FFFE", "\xF1\xAF\xBF\xBE"},  // U+06FFFE
+      {L"\U0006FFFF", "\xF1\xAF\xBF\xBF"},  // U+06FFFF
+      {L"\U0007FFFE", "\xF1\xBF\xBF\xBE"},  // U+07FFFE
+      {L"\U0007FFFF", "\xF1\xBF\xBF\xBF"},  // U+07FFFF
+      {L"\U0008FFFE", "\xF2\x8F\xBF\xBE"},  // U+08FFFE
+      {L"\U0008FFFF", "\xF2\x8F\xBF\xBF"},  // U+08FFFF
+      {L"\U0009FFFE", "\xF2\x9F\xBF\xBE"},  // U+09FFFE
+      {L"\U0009FFFF", "\xF2\x9F\xBF\xBF"},  // U+09FFFF
+      {L"\U000AFFFE", "\xF2\xAF\xBF\xBE"},  // U+0AFFFE
+      {L"\U000AFFFF", "\xF2\xAF\xBF\xBF"},  // U+0AFFFF
+      {L"\U000BFFFE", "\xF2\xBF\xBF\xBE"},  // U+0BFFFE
+      {L"\U000BFFFF", "\xF2\xBF\xBF\xBF"},  // U+0BFFFF
+      {L"\U000CFFFE", "\xF3\x8F\xBF\xBE"},  // U+0CFFFE
+      {L"\U000CFFFF", "\xF3\x8F\xBF\xBF"},  // U+0CFFFF
+      {L"\U000DFFFE", "\xF3\x9F\xBF\xBE"},  // U+0DFFFE
+      {L"\U000DFFFF", "\xF3\x9F\xBF\xBF"},  // U+0DFFFF
+      {L"\U000EFFFE", "\xF3\xAF\xBF\xBE"},  // U+0EFFFE
+      {L"\U000EFFFF", "\xF3\xAF\xBF\xBF"},  // U+0EFFFF
+      {L"\U000FFFFE", "\xF3\xBF\xBF\xBE"},  // U+0FFFFE
+      {L"\U000FFFFF", "\xF3\xBF\xBF\xBF"},  // U+0FFFFF
+      {L"\U0010FFFE", "\xF4\x8F\xBF\xBE"},  // U+10FFFE
+      {L"\U0010FFFF", "\xF4\x8F\xBF\xBF"},  // U+10FFFF
   };
 
-  for (size_t i = 0; i < arraysize(cases); ++i) {
-    string16 in = WideToUTF16(cases[i].to_escape);
+  for (const auto& i : cases) {
+    std::u16string in = WideToUTF16(i.to_escape);
 
     std::string out;
     EscapeJSONString(in, false, &out);
-    EXPECT_EQ(std::string(cases[i].escaped), out);
-    EXPECT_TRUE(IsStringUTF8(out));
+    EXPECT_EQ(std::string(i.escaped), out);
+    EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
 
     out = GetQuotedJSONString(in);
-    EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", out);
-    EXPECT_TRUE(IsStringUTF8(out));
+    EXPECT_EQ("\"" + std::string(i.escaped) + "\"", out);
+    EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
   }
 
-  string16 in = WideToUTF16(cases[0].to_escape);
+  std::u16string in = WideToUTF16(cases[0].to_escape);
   std::string out;
   EscapeJSONString(in, false, &out);
-  EXPECT_TRUE(IsStringUTF8(out));
+  EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
 
   // test quoting
   std::string out_quoted;
   EscapeJSONString(in, true, &out_quoted);
   EXPECT_EQ(out.length() + 2, out_quoted.length());
   EXPECT_EQ(out_quoted.find(out), 1U);
-  EXPECT_TRUE(IsStringUTF8(out));
+  EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
 
   // now try with a NULL in the string
-  string16 null_prepend = WideToUTF16(L"test");
+  std::u16string null_prepend = u"test";
   null_prepend.push_back(0);
   in = null_prepend + in;
   std::string expected = "test\\u0000";
@@ -121,13 +193,13 @@
   out.clear();
   EscapeJSONString(in, false, &out);
   EXPECT_EQ(expected, out);
-  EXPECT_TRUE(IsStringUTF8(out));
+  EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
 }
 
 TEST(JSONStringEscapeTest, EscapeUTF16OutsideBMP) {
   {
     // {a, U+10300, !}, SMP.
-    string16 test;
+    std::u16string test;
     test.push_back('a');
     test.push_back(0xD800);
     test.push_back(0xDF00);
@@ -138,7 +210,7 @@
   }
   {
     // {U+20021, U+2002B}, SIP.
-    string16 test;
+    std::u16string test;
     test.push_back(0xD840);
     test.push_back(0xDC21);
     test.push_back(0xD840);
@@ -149,7 +221,7 @@
   }
   {
     // {?, U+D800, @}, lone surrogate.
-    string16 test;
+    std::u16string test;
     test.push_back('?');
     test.push_back(0xD800);
     test.push_back('@');
@@ -168,19 +240,19 @@
     {"\xe5\xc4\x4f\x05\xb6\xfd", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"},
   };
 
-  for (size_t i = 0; i < arraysize(cases); ++i) {
-    std::string in = std::string(cases[i].to_escape);
-    EXPECT_FALSE(IsStringUTF8(in));
+  for (const auto& i : cases) {
+    std::string in = std::string(i.to_escape);
+    EXPECT_FALSE(IsStringUTF8AllowingNoncharacters(in));
 
-    EXPECT_EQ(std::string(cases[i].escaped),
-        EscapeBytesAsInvalidJSONString(in, false));
-    EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"",
-        EscapeBytesAsInvalidJSONString(in, true));
+    EXPECT_EQ(std::string(i.escaped),
+              EscapeBytesAsInvalidJSONString(in, false));
+    EXPECT_EQ("\"" + std::string(i.escaped) + "\"",
+              EscapeBytesAsInvalidJSONString(in, true));
   }
 
   const char kEmbedNull[] = { '\xab', '\x39', '\0', '\x9f', '\xab' };
-  std::string in(kEmbedNull, arraysize(kEmbedNull));
-  EXPECT_FALSE(IsStringUTF8(in));
+  std::string in(kEmbedNull, std::size(kEmbedNull));
+  EXPECT_FALSE(IsStringUTF8AllowingNoncharacters(in));
   EXPECT_EQ(std::string("\\u00AB9\\u0000\\u009F\\u00AB"),
             EscapeBytesAsInvalidJSONString(in, false));
 }
diff --git a/base/json/values_util.cc b/base/json/values_util.cc
new file mode 100644
index 0000000..8f14256
--- /dev/null
+++ b/base/json/values_util.cc
@@ -0,0 +1,123 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/values_util.h"
+
+#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "base/unguessable_token.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+// Warning: The Values involved could be stored on persistent storage like files
+// on disks. Therefore, changes in implementation could lead to data corruption
+// and must be done with caution.
+
+namespace base {
+
+namespace {
+
+// Helper to serialize/deserialize an UnguessableToken.
+//
+// It assumes a little-endian CPU, which is arguably a bug.
+union UnguessableTokenRepresentation {
+  struct Field {
+    uint64_t high;
+    uint64_t low;
+  } field;
+
+  uint8_t buffer[sizeof(Field)];
+};
+
+}  // namespace
+
+Value Int64ToValue(int64_t integer) {
+  return Value(NumberToString(integer));
+}
+
+absl::optional<int64_t> ValueToInt64(const Value* value) {
+  return value ? ValueToInt64(*value) : absl::nullopt;
+}
+
+absl::optional<int64_t> ValueToInt64(const Value& value) {
+  if (!value.is_string())
+    return absl::nullopt;
+
+  int64_t integer;
+  if (!StringToInt64(value.GetString(), &integer))
+    return absl::nullopt;
+
+  return integer;
+}
+
+Value TimeDeltaToValue(TimeDelta time_delta) {
+  return Int64ToValue(time_delta.InMicroseconds());
+}
+
+absl::optional<TimeDelta> ValueToTimeDelta(const Value* value) {
+  return value ? ValueToTimeDelta(*value) : absl::nullopt;
+}
+
+absl::optional<TimeDelta> ValueToTimeDelta(const Value& value) {
+  absl::optional<int64_t> integer = ValueToInt64(value);
+  if (!integer)
+    return absl::nullopt;
+  return Microseconds(*integer);
+}
+
+Value TimeToValue(Time time) {
+  return TimeDeltaToValue(time.ToDeltaSinceWindowsEpoch());
+}
+
+absl::optional<Time> ValueToTime(const Value* value) {
+  return value ? ValueToTime(*value) : absl::nullopt;
+}
+
+absl::optional<Time> ValueToTime(const Value& value) {
+  absl::optional<TimeDelta> time_delta = ValueToTimeDelta(value);
+  if (!time_delta)
+    return absl::nullopt;
+  return Time::FromDeltaSinceWindowsEpoch(*time_delta);
+}
+
+Value FilePathToValue(FilePath file_path) {
+  return Value(file_path.AsUTF8Unsafe());
+}
+
+absl::optional<FilePath> ValueToFilePath(const Value* value) {
+  return value ? ValueToFilePath(*value) : absl::nullopt;
+}
+
+absl::optional<FilePath> ValueToFilePath(const Value& value) {
+  if (!value.is_string())
+    return absl::nullopt;
+  return FilePath::FromUTF8Unsafe(value.GetString());
+}
+
+Value UnguessableTokenToValue(UnguessableToken token) {
+  UnguessableTokenRepresentation repr;
+  repr.field.high = token.GetHighForSerialization();
+  repr.field.low = token.GetLowForSerialization();
+  return Value(HexEncode(repr.buffer, sizeof(repr.buffer)));
+}
+
+absl::optional<UnguessableToken> ValueToUnguessableToken(const Value* value) {
+  return value ? ValueToUnguessableToken(*value) : absl::nullopt;
+}
+
+absl::optional<UnguessableToken> ValueToUnguessableToken(const Value& value) {
+  if (!value.is_string())
+    return absl::nullopt;
+  UnguessableTokenRepresentation repr;
+  if (!HexStringToSpan(value.GetString(), repr.buffer))
+    return absl::nullopt;
+  absl::optional<base::UnguessableToken> token =
+      UnguessableToken::Deserialize(repr.field.high, repr.field.low);
+  if (!token.has_value()) {
+    return absl::nullopt;
+  }
+  return token;
+}
+
+}  // namespace base
diff --git a/base/json/values_util.h b/base/json/values_util.h
new file mode 100644
index 0000000..2c3722d
--- /dev/null
+++ b/base/json/values_util.h
@@ -0,0 +1,60 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_JSON_VALUES_UTIL_H_
+#define BASE_JSON_VALUES_UTIL_H_
+
+#include "base/base_export.h"
+#include "base/values.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace base {
+class FilePath;
+class Time;
+class TimeDelta;
+class UnguessableToken;
+
+// Simple helper functions for converting between Value and other types.
+// The Value representation is stable, suitable for persistent storage
+// e.g. as JSON on disk.
+//
+// It is valid to pass nullptr to the ValueToEtc functions. They will just
+// return absl::nullopt.
+
+// Converts between an int64_t and a string-flavored Value (a human
+// readable string of that number).
+BASE_EXPORT Value Int64ToValue(int64_t integer);
+BASE_EXPORT absl::optional<int64_t> ValueToInt64(const Value* value);
+BASE_EXPORT absl::optional<int64_t> ValueToInt64(const Value& value);
+
+// Converts between a TimeDelta (an int64_t number of microseconds) and a
+// string-flavored Value (a human readable string of that number).
+BASE_EXPORT Value TimeDeltaToValue(TimeDelta time_delta);
+BASE_EXPORT absl::optional<TimeDelta> ValueToTimeDelta(const Value* value);
+BASE_EXPORT absl::optional<TimeDelta> ValueToTimeDelta(const Value& value);
+
+// Converts between a Time (an int64_t number of microseconds since the
+// Windows epoch) and a string-flavored Value (a human readable string of
+// that number).
+BASE_EXPORT Value TimeToValue(Time time);
+BASE_EXPORT absl::optional<Time> ValueToTime(const Value* value);
+BASE_EXPORT absl::optional<Time> ValueToTime(const Value& value);
+
+// Converts between a FilePath (a std::string or std::u16string) and a
+// string-flavored Value (the UTF-8 representation).
+BASE_EXPORT Value FilePathToValue(FilePath file_path);
+BASE_EXPORT absl::optional<FilePath> ValueToFilePath(const Value* value);
+BASE_EXPORT absl::optional<FilePath> ValueToFilePath(const Value& value);
+
+// Converts between a UnguessableToken (128 bits) and a string-flavored
+// Value (32 hexadecimal digits).
+BASE_EXPORT Value UnguessableTokenToValue(UnguessableToken token);
+BASE_EXPORT absl::optional<UnguessableToken> ValueToUnguessableToken(
+    const Value* value);
+BASE_EXPORT absl::optional<UnguessableToken> ValueToUnguessableToken(
+    const Value& value);
+
+}  // namespace base
+
+#endif  // BASE_JSON_VALUES_UTIL_H_
diff --git a/base/json/values_util_unittest.cc b/base/json/values_util_unittest.cc
new file mode 100644
index 0000000..ef7cb98
--- /dev/null
+++ b/base/json/values_util_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/values_util.h"
+
+#include <limits>
+
+#include "base/files/file_path.h"
+#include "base/strings/string_piece.h"
+#include "base/time/time.h"
+#include "base/unguessable_token.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+TEST(ValuesUtilTest, BasicInt64Limits) {
+  constexpr struct {
+    int64_t input;
+    StringPiece expected;
+  } kTestCases[] = {
+      {0, "0"},
+      {-1234, "-1234"},
+      {5678, "5678"},
+      {std::numeric_limits<int64_t>::lowest(), "-9223372036854775808"},
+      {std::numeric_limits<int64_t>::max(), "9223372036854775807"},
+  };
+  for (const auto& test_case : kTestCases) {
+    int64_t input = test_case.input;
+    TimeDelta time_delta_input = Microseconds(input);
+    Time time_input = Time::FromDeltaSinceWindowsEpoch(time_delta_input);
+    Value expected(test_case.expected);
+    SCOPED_TRACE(testing::Message()
+                 << "input: " << input << ", expected: " << expected);
+
+    EXPECT_EQ(Int64ToValue(input), expected);
+    EXPECT_EQ(*ValueToInt64(&expected), input);
+
+    EXPECT_EQ(TimeDeltaToValue(time_delta_input), expected);
+    EXPECT_EQ(*ValueToTimeDelta(&expected), time_delta_input);
+
+    EXPECT_EQ(TimeToValue(time_input), expected);
+    EXPECT_EQ(*ValueToTime(&expected), time_input);
+  }
+}
+
+TEST(ValuesUtilTest, InvalidInt64Values) {
+  const std::unique_ptr<Value> kTestCases[] = {
+      nullptr,
+      std::make_unique<Value>(),
+      std::make_unique<Value>(0),
+      std::make_unique<Value>(1234),
+      std::make_unique<Value>(true),
+      std::make_unique<Value>(Value::Type::BINARY),
+      std::make_unique<Value>(Value::Type::LIST),
+      std::make_unique<Value>(Value::Type::DICT),
+      std::make_unique<Value>(""),
+      std::make_unique<Value>("abcd"),
+      std::make_unique<Value>("1234.0"),
+      std::make_unique<Value>("1234a"),
+      std::make_unique<Value>("a1234"),
+  };
+  for (const auto& test_case : kTestCases) {
+    EXPECT_FALSE(ValueToInt64(test_case.get()));
+    EXPECT_FALSE(ValueToTimeDelta(test_case.get()));
+    EXPECT_FALSE(ValueToTime(test_case.get()));
+  }
+}
+
+TEST(ValuesUtilTest, FilePath) {
+  // Ω is U+03A9 GREEK CAPITAL LETTER OMEGA, a non-ASCII character.
+  constexpr StringPiece kTestCases[] = {
+      "/unix/Ω/path.dat",
+      "C:\\windows\\Ω\\path.dat",
+  };
+  for (auto test_case : kTestCases) {
+    FilePath input = FilePath::FromUTF8Unsafe(test_case);
+    Value expected(test_case);
+    SCOPED_TRACE(testing::Message() << "test_case: " << test_case);
+
+    EXPECT_EQ(FilePathToValue(input), expected);
+    EXPECT_EQ(*ValueToFilePath(&expected), input);
+  }
+}
+
+TEST(ValuesUtilTest, UnguessableToken) {
+  constexpr struct {
+    uint64_t high;
+    uint64_t low;
+    StringPiece expected;
+  } kTestCases[] = {
+      {0x123456u, 0x9ABCu, "5634120000000000BC9A000000000000"},
+  };
+  for (const auto& test_case : kTestCases) {
+    UnguessableToken input =
+        UnguessableToken::CreateForTesting(test_case.high, test_case.low);
+    Value expected(test_case.expected);
+    SCOPED_TRACE(testing::Message() << "expected: " << test_case.expected);
+
+    EXPECT_EQ(UnguessableTokenToValue(input), expected);
+    EXPECT_EQ(*ValueToUnguessableToken(&expected), input);
+  }
+}
+
+}  // namespace
+
+}  // namespace base