Squashed 'third_party/allwpilib_2019/' changes from 99e4f7dd2..c36bbcc9a

936627bd9 wpilibc: Remove direct CameraServer dependency (#1989)
8e333c0aa Use FPGA Time instead of wall clock time for odometry (#1996)
d4430b765 Gearsbot example: Use standard argument order (#1995)
75438ab2c Add RamseteCommand (#1951)
989df1b46 Bump Native Utils and OpenCV dependencies (#1993)
dbc33b61e Fix Timer usage in TrapezoidProfileCommand (#1992)
79f8c5644 Add TrapezoidProfileCommand (#1962)
9440edf2b Refactor TrajectoryGenerator (#1972)
73a30182c Add frc2::Timer (#1968)
36ea865ed Add toString for geometry and trajectory classes (#1991)
cbe05e7e8 Update ProfiledPIDController API (#1967)
d04eb3546 Deprecate old PID classes (#1964)
02264db69 Add JNI dependencies to myRobotCpp (#1980)
2a76c996e Use VID/PID detection for PS3Eye (#1977)
a3820bbdf Remove HAL_BaseInitialize (#1981)
a83fb4793 Update to 2020v5 image (#1983)
4b0ed910e Make SwerveDriveKinematics.toChassisSpeeds() public (#1976)
103c1b121 Remove DS caching from the HAL level (#1971)
6635ea75e Fix NPE in SendableRegistry.foreachLiveWindow() (#1974)
cfe23c5cd Fix grammar error in comment for configureButtonBindings (#1969)
4bde2654e Fix mac azure build (#1973)
4f034e6c1 generateTrajectory: default reversed param to false (#1953)
acf960f72 Sim GUI: Add option to disable outputs on DS disable
2d3dac99f Sim GUI: Handle low resolutions and scale default window positions
07c86e0cd Sim GUI: Support High DPI monitors
46ad95512 SimDeviceData: Add missing null check
5bce489b9 Add ProggyDotted font to imgui (both cmake and gradle)
55af553ac Simulation GUI: Map gamepad the same way as DS
c59f9cea5 CameraServer: Add VID/PID support for Linux USB devices (#1960)
3fc89c84d Make splinePointsFromSplines public (#1963)
2c5093797 Fix implicitly deleted move constructors (#1954)
f3ad927f4 Update Java SmartDashboard and LiveWindow to match C++
05c25deb7 Fix move handling of C++ Sendable in SmartDashboard and LiveWindow
d726591ce Fix Gazebo sim plugin build (#1959)
2ff694fa4 Unbreak gradle build when other compilers installed (#1958)
53816155b Improve command decorator names (#1945)
a38f183a9 Fix GenResources.cmake so it's usable in a submodule (#1956)
b3398dca3 Set gradlebase correctly for all examples (#1950)
2c311013d Add Aarch64Bionic platform detection (#1922)
c10f2003c Add generateTrajectory overload (#1944)
63cfa64fb Add getters for pose in odometry classes (#1943)
2402c2bad Fix C++ command group recursive constructor bug (#1941)
f4eedf597 Fix ConcurrentModificationException in CommandScheduler (#1938)
bb0b207d2 Fix array out of bounds exception caused by parallel race group (#1935)
7bd69e591 Fix typo in temperature (#1940)
ec9738245 Bump to 2020 v4 image (#1931)
46303a822 Add messaging to extension loading in the HAL (#1926)
d169d6be9 Set extract_static for Doxygen config so that static members show up (#1930)
4e183eb10 Bump to 2020 v3 image (#1929)
84c185803 LiveWindow: catch errors in callback/builder functions (#1921)
0e3b0f3da Remove deprecated free() calls (#1925)
7f839b87c Remove timeouts from azure builds (#1924)
45b766a5d Fix main thread ID being potentially incorrect for simulation (#1923)
56d782b16 Add secondary camera name for PS3Eye (#1920)
2b4894038 Add simulation GUI plugin
f97d16073 Add imgui build to cmake
55a844a3e HAL sim: Add encoder channel B access
10deba854 Remove sendables from SendableRegistry when close() is called (#1917)
a9f0e4668 Implement sim devices for ADXL345, ADXL362, ADXRS450, Ultrasonic
aa9064586 Add ability to associate other devices with a SimDevice
81c2c8a7d Add simulation generic device/value support
e8d6f8a2c Move mockdata/HAL_Value.h to hal/Value.h
1b266717a Add simulation module support to cmake build (#1906)
fb8f3bd06 Add testbench yaml file (#1915)
846d8def0 Update to 2020 v2 image (#1913)
d6ac6e512 Fix PortForwarder package declaration (#1912)
227157086 Fix PS3Eye exposure setting (#1911)
885744d7e Add myRobot C++ version to cmake build (#1907)
366091fa8 Document that ConditionalCommand requires all subsystems (#1909)
c58b072c8 Fix Drive usage reporting order (#1908)
762c88adb Update compiler versions in readme (#1905)
af8ce568d Add Ramsete unicycle controller (#1790)
b2c2934d0 Fix javadoc warnings about invalid usage of ">" (#1904)
cce26ec78 Replace CRLF line endings with LF (#1902)
cb54602d4 Add support for writing RTR CAN Frames to the CAN API (#1900)
9f740e590 Use OS for serial port instead of NI VISA (#1875)
b23baf611 Add ability to run robot main loop in a separate thread (#1895)
457f94ba2 Add trajectory generation using hermite splines (#1843)
fd612052f Update native utils to use new frchome directory (#1884)
8858ec55c Remove periodic can read call (#1868)
41efb8015 Update CANAPITypes.h (#1860)
c93be1b2d Remove LabVIEW HAL support (#1901)
680f8919e Remove eigen, units and libuv from doxygen generation (#1898)
c5812524f Bump GradleJNI plugin version (#1899)
971303da8 Add PortForwarder class (#1890)
50db77bf2 Fix wpiutil cmake eigen install source directory (#1891)
85d42c199 C++ PIDCommand: Add GetMeasurement() and UseOutput() (#1892)
2dfbb855d wpilibj: Fix SwerveDriveKinematics ctor parameter name (#1889)
471f375a3 Simplify Sendable interface (#1864)
1d8c4d016 Replace ::value and ::type with _v and _t suffixes (#1885)
a5650b943 Add Units Utility class for Java (#1829)
904479ad4 Deprecate GearTooth class for removal (#1878)
86b666bba Add equality comparator to geometry classes (#1882)
62f07c182 Make one-arg Rotation2d constructor implicit (#1883)
f405582f8 Add kinematics suite (#1787)
561cbbd14 Deprecate Filter class for removal (#1876)
84e2973aa Remove unused include from Filesystem.h (#1877)
f49859ebf Remove NI VISA headers, as they are now included in NI Libraries (#1879)
bc59db5e6 Rename DEBUG macro to DEBUG0 (#1871)
dd928b4cb Remove JNI logging (#1872)
3e0f7d099 Use units for new NotifierCommand (#1869)
5ffe15d5f Remove ability to build all combined artifacts (#1867)
516cbef2c  Remove RoboRIO ifdef from simulation headers (#1859)
9b6ffc201 Replace SetOutputRange() with SetIntegratorRange()
ff8b8f0a8 Remove percent tolerance from PID controller
0ca8d667d Clean up AutoCloseable and other Java warnings (#1866)
7112add67 Watchdog: use units::second_t instead of double (#1863)
761bc3ef8 Change C++ WaitCommand to use units (#1865)
1fb301123 Add MathUtils.clamp() for Java (#1861)
eb3e0c9c9 Fix cmake Eigen include directory (#1862)
2250b7fbe Rename GearsBotNew example to GearsBot
c9f9feff1 Replace deprecated API usage in C++ examples
d6b9c7e14 CONTRIBUTING.md: Point to frc-docs instead of screensteps (#1858)
d10a1a797 Fix eigen build in vcpkg (#1856)
2bdb44325 Add frc2 includes to list of "other lib" regexes (#1855)
4b2b21d24 Replace outdated Java collections (#508)
8993ce5bf Move Eigen headers out of main include folder (#1854)
0f532a117 Add PWMSparkMax (#1751)
f7ad363d8 Add jni cross compile options for aarch64 (#1853)
9afea3340 Add support for aarch64 jetson bionic builds (#1844)
d787b5d60 Add more items to .gitignore (#1850)
5dd0d1b7d Use units in SPI
07ac711b3 Fix units deprecated warning in IterativeRobot
decfd858b Correctly report -1 for POV on disconnected joystick (#1852)
076ed7770 Add new C++ Command framework (#1785)
a0be07c37 Refactor HAL handle move construction/assignment (#1845)
558c38308 Add new Java Command framework (#1682)
1379735af Delete RobotState and SensorUtil constructors (#1847)
e3d86fee4 Move circular buffer class from wpilib to wpiutil (#1840)
4cd8a5667 TimedRobot.cpp: Fix deprecation warning (#1846)
b2861f894 Use 2020 artifacts and artifactory server (#1838)
98cc32703 Update to use artifactory to publish artifacts (#1833)
fa0640300 Move drive integration tests into wpilibj/src/test (#1836)
e716c36b8 Fix Nat.java generation to be incremental (#1831)
9fd2b5e3f Fix MSVC builds on cmake windows in vcpkg (#1835)
7e95010a2 Add compile-time EJML matrix wrapper to wpiutil (#1804)
3ebc5a6d3 Add ProfiledPIDController
fc98a79db Clean up PIDController interface in preparation for ProfiledPIDController
fdc098267 Fix compilation error in elevator trapezoid profile example (#1826)
a3dd84e85 Make XBoxController Button enum public (#1823)
a216b9e9e Add TrapezoidProfile example (#1814)
8f386f6bb wpilibc: Add unit-safety to C++ geometry classes (#1811)
c07ac2353 wpilibc: Add overloads for units (#1815)
f1d71da8a Move GetStackTrace and Demangle to wpiutil, add Windows support (#1819)
ef037457e Make LinearFilter copyable and moveable (#1789)
76930250c Remove objective-cpp support (#1816)
1c246418f Move TrapezoidProfileTest to trajectory folder (#1812)
95a54a0f2 Add java arcade drive example (#1810)
a4530243e HAL sim: Fix incorrectly setting dio port to initialized on cleanup (#1813)
09d00a622 Update Java examples to use new PIDController (#1809)
ba9b51742 Add missing Java examples (#841)
6411bd79c InterruptableSensorBase: Fix callback function deletion (#1807)
810e58ea8 I2C: Add tip about writeBulk() to transaction() (#1806)
607d6c148 Fix wpilibj integration tests jar name (#1808)
c9873e81b Remove PIDControllerRunner and mutex from new PIDController (#1795)
98d0706de Fix cscore build with OpenCV 4 (#1803)
fbe67c90c Make Sendable setters synchronous (#1799)
c67a488a0 Format SendableBuilderImpl javadocs (#1802)
8e93ce892 Fix PIDControllerRunner member destruction order (#1801)
c98ca7310 Add EJML dependency to wpiutil (#1769)
3b12276bc SendableBase: remove unnecessary synchronization (#1797)
e6d348f38 Fix missing default name in Java PIDController (#1792)
df12fc2a8 Java cleanups (#1776)
39561751f Update GradleVSCode version (#1786)
37d316aa0 Add C++20 std::math constants shim (#1788)
dd4310959 Deprecate frc/WPILib.h (#1779)
823174f30 Update native utils to 2020.0.4 (#1783)
37c695266 Squelch -Wdeprecated-copy for Eigen with GCC >= 9
04c9b000f Revert "Fix build of Eigen 3.3.7 with GCC 9"
ca3e71e21 wpiutil: Fix Process::Spawn() (#1778)
d946d5a2b Fix Eigen compilation errors and add tests (#1777)
8b1b9ac75 Fix build of Eigen 3.3.7 with GCC 9
2f680ba99 Add Eigen linear algebra library
a885db7d4 Make MotorEncoderTest use LinearFilter (#1775)
ee2410169 Add geometry classes (#1766)
48fe54271 Add HALSIM_SetSendError implementation (#1773)
dff58c87f Fix unused warning in release build (#1771)
dde61aad3 Remove TimerEventHandler typedef from Notifier class (#1767)
0f6ef80ab Add RobotState#IsEStopped and DriverStation#IsEStopped (#952)
e48886187 Move unit tests from integration test suite (#1170)
dffa1a5cb Make null checks more descriptive (#1688)
fe59d854d Notifier: add null check (#1684)
10731f3d6 Update uv Udp wrapper for latest features
89f7b72b6 Update libuv to 1.30.1 release
85f2f8740 wpiutil: Add unique_function (#1761)
73ec94078 Remove SampleRobot (#1658)
62be0392b Replace std::lock_guard and std::lock with std::scoped_lock (#1758)
24d31df55 Make sure move constructor is generated for TrapezoidProfile (#1757)
841ef5d73 Remove template types from lock RAII wrapper usages (#1756)
e582518ba Fix some move constructors (#1754)
8757bc471 Remove pre-C++17 shims (#1752)
ea9512977 Add replacement PIDController class (#1300)
9b798d228 Add TrapezoidProfile class (#1673)
804926fb5 Unconditionally skip athena builds for sim (#1748)
118e9d29d Add C++14 units library (#1749)
c705953d7 Add usage reporting to LinearFilter (#1750)
852d1b9ca Don't cross-build gazebo for raspbian (#1747)
eedb3a1ad Fix GCC 9 warnings (#1730)
60dce66a4 Remove wpi::ArrayRef std::initializer_list constructor (#1745)
9e19b29c3 Use base azure image for primary wpilib build (#1744)
299425071 Update jni library, fix cross builds of the jni symbol check (#1742)
a6b0e9b85 Only disable execution of cross compile google tests (#1741)
3c2093119 Use docker container to run wpiformat (#1740)
5fe2eebce Revert "Don't build halsim_gazebo on raspbian (#1737)" (#1743)
4b1b92bb7 Replace wpi::optional with C++17 std::optional (#1732)
0fbb0d989 Update to 2020 compilers (#1733)
2dc94e605 Disable google tests on cross compilers (#1738)
d9cb57a42 Don't build halsim_gazebo on raspbian (#1737)
f7cfdd7ce Replace crlf line endings with lf (#1731)
b6d5d90d9 Add JaCoCo Support (#1734)
c7ab2baa6 Add way to disable the jni check tasks from a property (#1736)
0c45c5b7e Fix skip athena and skip raspbian flags (#1735)
3dfb01d45 Update to new Native Utils (#1696)
30e936837 Clean up LinearDigitalFilter class (#782)
311e2de4c Remove deprecated Joystick constants (#1715)
c08fd6682 Update CAN manufacturer list (#1706)
258bba0c2 ErrorBase and WPIError improvements (#1727)
372ca4f45 cmake: Enable googletest unit tests (#1720)
223d47af0 HALSIM: support mocking of HAL_SendError() (#1728)
55cb683db Change compiler flags to C++17 (#1723)
ee8a33c56 wpiutil: SafeThread: Add thread id, support getting shared_ptr (#1722)
61426d08d wpiutil: Signal: make operator() const (#1721)
b630b63ef Remove functions in LiveWindow deprecated since 2018 (#1716)
1d0c05d4f Styleguide fixes for #1718 (#1719)
f07569df1 Fix newer GCC/clang compiler warnings (#1718)
0120f3124 C++ SPI: Fix SetClockRate to take int (#1717)
c2829ed98 Configure gradle to ignore unresolved headers (#1711)
221e66f46 Allow disabling static init of JNI libraries (#1672)
738852e11 cmake: Add cross toolchain files for Rio and Pi (#1710)
27b697b08 Remove frc directory include shims (#1714)
9e45373a7 Remove functions and classes deprecated for 2018 season (#1059)
eeb1025ac SPI: Report port as instance for usage reporting (#1704)
bc6f1e246 Windows compiler options improvements (#1709)
bb48ae391 cmake: Move example programs into folders (#1654)
221011494 Update for C++17 and fix MSVC warnings (#1694)
fb1239a2a Add raw sources and sinks to cscore (#1670)
7de947734 Add lambda overloads for interrupts (#1636)
90957aeea Move libuv to its own subfolder in build (#1661)
47aae502a Styleguide fixes (#1702)
0bff98b5e Correct DifferentialDrive::ArcadeDrive param docs (#1698)
b52e40b80 Allow widgets to be added by passing value suppliers (#1690)
4a00cd77b Add usage reporting for the Shuffleboard API (#1685)
e25e515f2  Publish artifacts on azure (#1678)
322ef9b96 Force Java 11, fix javadoc generation (#1695)
d42ef5df0 Fix Watchdog print formatting (#1693)
f432f65be Update copyright year in license to 2019 (#1524)
1726b77ac wpiutil: uv: Remove copy from SimpleBufferPool (#1680)
620bec9ca wpiutil: uv: Add LoopClosing status to Handle (#1647)
7cd6e2e7f UsbCamera: Solve race in windows initialization (#1638)
7732836bd Completely disable watchdog tests on mac (#1679)
698edfda9 Remove framework load, disable mac timeout test (#1676)
1c454b000 Add Shuffleboard calls to IterativeRobotBase in C++ (#1607)
f42905b32 Include missing headers in HAL.h (#1660)
bdc822fad Only generate passthrough URLs for RoboRIO (#1624)
d3affb16b Make failure of HAL_GetFPGATime() more descriptive (#1633)
2de3bf7f5 Update LLVM from stable upstream (#1653)
3cf4f38f5 Fix build on macos10.14.4 (#1648)
4e0c10f48 Fix CAN Clean using wrong ID (#1668)
3b0631324 Fix Gray to BGR conversion in CameraServer (#1665)
6cd1c73ef Fix GUID comparison creating weird symbol (#1659)
063bbab6f MavenArtifacts.md: update links to HTTPS (#1674)
aab4c494d Fix type in build.gradle (#1604)
bf46af260 Disable extraneous data warnings in libjpeg (#1630)
655763a9a Limit length of message sent to DS SendError call (#1618)
a095ec2d8 Fix linker errors with free functions in Threads.h (#1625)
12ab035aa Fix receive side of LabVIEW USB streams (#1621)

Change-Id: Ibd382e1a48925c200850cf90a8121e35c0fcffe3
git-subtree-dir: third_party/allwpilib_2019
git-subtree-split: c36bbcc9a9095489fc078229db4fba3ecd0f9b78
diff --git a/wpiutil/src/main/native/cpp/EventLoopRunner.cpp b/wpiutil/src/main/native/cpp/EventLoopRunner.cpp
index b885385..1c54bdf 100644
--- a/wpiutil/src/main/native/cpp/EventLoopRunner.cpp
+++ b/wpiutil/src/main/native/cpp/EventLoopRunner.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -49,7 +49,10 @@
 void EventLoopRunner::Stop() {
   ExecAsync([](uv::Loop& loop) {
     // close all handles; this will (eventually) stop the loop
-    loop.Walk([](uv::Handle& h) { h.Close(); });
+    loop.Walk([](uv::Handle& h) {
+      h.SetLoopClosing(true);
+      h.Close();
+    });
   });
   m_owner.Join();
 }
diff --git a/wpiutil/src/main/native/cpp/HttpServerConnection.cpp b/wpiutil/src/main/native/cpp/HttpServerConnection.cpp
index 9e65691..0308e8c 100644
--- a/wpiutil/src/main/native/cpp/HttpServerConnection.cpp
+++ b/wpiutil/src/main/native/cpp/HttpServerConnection.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -77,7 +77,7 @@
 
 void HttpServerConnection::SendData(ArrayRef<uv::Buffer> bufs,
                                     bool closeAfter) {
-  m_stream.Write(bufs, [ closeAfter, stream = &m_stream ](
+  m_stream.Write(bufs, [closeAfter, stream = &m_stream](
                            MutableArrayRef<uv::Buffer> bufs, uv::Error) {
     for (auto&& buf : bufs) buf.Deallocate();
     if (closeAfter) stream->Close();
@@ -113,7 +113,7 @@
   // can send content without copying
   bufs.emplace_back(content);
 
-  m_stream.Write(bufs, [ closeAfter = !m_keepAlive, stream = &m_stream ](
+  m_stream.Write(bufs, [closeAfter = !m_keepAlive, stream = &m_stream](
                            MutableArrayRef<uv::Buffer> bufs, uv::Error) {
     // don't deallocate the static content
     for (auto&& buf : bufs.drop_back()) buf.Deallocate();
diff --git a/wpiutil/src/main/native/cpp/PortForwarder.cpp b/wpiutil/src/main/native/cpp/PortForwarder.cpp
new file mode 100644
index 0000000..fe54b63
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/PortForwarder.cpp
@@ -0,0 +1,150 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "wpi/PortForwarder.h"
+
+#include "wpi/DenseMap.h"
+#include "wpi/EventLoopRunner.h"
+#include "wpi/SmallString.h"
+#include "wpi/raw_ostream.h"
+#include "wpi/uv/GetAddrInfo.h"
+#include "wpi/uv/Tcp.h"
+#include "wpi/uv/Timer.h"
+
+using namespace wpi;
+
+struct PortForwarder::Impl {
+ public:
+  EventLoopRunner runner;
+  DenseMap<unsigned int, std::weak_ptr<uv::Tcp>> servers;
+};
+
+PortForwarder::PortForwarder() : m_impl{new Impl} {}
+
+PortForwarder& PortForwarder::GetInstance() {
+  static PortForwarder instance;
+  return instance;
+}
+
+static void CopyStream(uv::Stream& in, std::weak_ptr<uv::Stream> outWeak) {
+  in.data.connect([&in, outWeak](uv::Buffer& buf, size_t len) {
+    uv::Buffer buf2 = buf.Dup();
+    buf2.len = len;
+    auto out = outWeak.lock();
+    if (!out) {
+      in.Close();
+      return;
+    }
+    out->Write(buf2, [](auto bufs, uv::Error) {
+      for (auto buf : bufs) buf.Deallocate();
+    });
+  });
+}
+
+void PortForwarder::Add(unsigned int port, const Twine& remoteHost,
+                        unsigned int remotePort) {
+  m_impl->runner.ExecSync([&](uv::Loop& loop) {
+    auto server = uv::Tcp::Create(loop);
+
+    // bind to local port
+    server->Bind("", port);
+
+    // when we get a connection, accept it
+    server->connection.connect([serverPtr = server.get(),
+                                host = remoteHost.str(), remotePort] {
+      auto& loop = serverPtr->GetLoopRef();
+      auto client = serverPtr->Accept();
+      if (!client) return;
+
+      // close on error
+      client->error.connect(
+          [clientPtr = client.get()](uv::Error err) { clientPtr->Close(); });
+
+      // connected flag
+      auto connected = std::make_shared<bool>(false);
+      client->SetData(connected);
+
+      auto remote = uv::Tcp::Create(loop);
+      remote->error.connect(
+          [remotePtr = remote.get(),
+           clientWeak = std::weak_ptr<uv::Tcp>(client)](uv::Error err) {
+            remotePtr->Close();
+            if (auto client = clientWeak.lock()) client->Close();
+          });
+
+      // convert port to string
+      SmallString<16> remotePortStr;
+      raw_svector_ostream(remotePortStr) << remotePort;
+
+      // resolve address
+      uv::GetAddrInfo(
+          loop,
+          [clientWeak = std::weak_ptr<uv::Tcp>(client),
+           remoteWeak = std::weak_ptr<uv::Tcp>(remote)](const addrinfo& addr) {
+            auto remote = remoteWeak.lock();
+            if (!remote) return;
+
+            // connect to remote address/port
+            remote->Connect(*addr.ai_addr, [remotePtr = remote.get(),
+                                            remoteWeak, clientWeak] {
+              auto client = clientWeak.lock();
+              if (!client) {
+                remotePtr->Close();
+                return;
+              }
+              *(client->GetData<bool>()) = true;
+
+              // close both when either side closes
+              client->end.connect([clientPtr = client.get(), remoteWeak] {
+                clientPtr->Close();
+                if (auto remote = remoteWeak.lock()) remote->Close();
+              });
+              remotePtr->end.connect([remotePtr, clientWeak] {
+                remotePtr->Close();
+                if (auto client = clientWeak.lock()) client->Close();
+              });
+
+              // copy bidirectionally
+              client->StartRead();
+              remotePtr->StartRead();
+              CopyStream(*client, remoteWeak);
+              CopyStream(*remotePtr, clientWeak);
+            });
+          },
+          host, remotePortStr);
+
+      // time out for connection
+      uv::Timer::SingleShot(loop, uv::Timer::Time{500},
+                            [connectedWeak = std::weak_ptr<bool>(connected),
+                             clientWeak = std::weak_ptr<uv::Tcp>(client),
+                             remoteWeak = std::weak_ptr<uv::Tcp>(remote)] {
+                              if (auto connected = connectedWeak.lock()) {
+                                if (!*connected) {
+                                  if (auto client = clientWeak.lock())
+                                    client->Close();
+                                  if (auto remote = remoteWeak.lock())
+                                    remote->Close();
+                                }
+                              }
+                            });
+    });
+
+    // start listening for incoming connections
+    server->Listen();
+
+    m_impl->servers[port] = server;
+  });
+}
+
+void PortForwarder::Remove(unsigned int port) {
+  m_impl->runner.ExecSync([&](uv::Loop& loop) {
+    if (auto server = m_impl->servers.lookup(port).lock()) {
+      server->Close();
+      m_impl->servers.erase(port);
+    }
+  });
+}
diff --git a/wpiutil/src/main/native/cpp/SafeThread.cpp b/wpiutil/src/main/native/cpp/SafeThread.cpp
index 52ac700..3a906bd 100644
--- a/wpiutil/src/main/native/cpp/SafeThread.cpp
+++ b/wpiutil/src/main/native/cpp/SafeThread.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -29,14 +29,15 @@
 }
 
 void detail::SafeThreadOwnerBase::Start(std::shared_ptr<SafeThread> thr) {
-  std::lock_guard<wpi::mutex> lock(m_mutex);
+  std::scoped_lock lock(m_mutex);
   if (auto thr = m_thread.lock()) return;
   m_stdThread = std::thread([=] { thr->Main(); });
+  thr->m_threadId = m_stdThread.get_id();
   m_thread = thr;
 }
 
 void detail::SafeThreadOwnerBase::Stop() {
-  std::lock_guard<wpi::mutex> lock(m_mutex);
+  std::scoped_lock lock(m_mutex);
   if (auto thr = m_thread.lock()) {
     thr->m_active = false;
     thr->m_cond.notify_all();
@@ -46,7 +47,7 @@
 }
 
 void detail::SafeThreadOwnerBase::Join() {
-  std::unique_lock<wpi::mutex> lock(m_mutex);
+  std::unique_lock lock(m_mutex);
   if (auto thr = m_thread.lock()) {
     auto stdThread = std::move(m_stdThread);
     m_thread.reset();
@@ -62,25 +63,24 @@
 void detail::swap(SafeThreadOwnerBase& lhs, SafeThreadOwnerBase& rhs) noexcept {
   using std::swap;
   if (&lhs == &rhs) return;
-  std::lock(lhs.m_mutex, rhs.m_mutex);
-  std::lock_guard<wpi::mutex> lock_lhs(lhs.m_mutex, std::adopt_lock);
-  std::lock_guard<wpi::mutex> lock_rhs(rhs.m_mutex, std::adopt_lock);
+  std::scoped_lock lock(lhs.m_mutex, rhs.m_mutex);
   std::swap(lhs.m_stdThread, rhs.m_stdThread);
   std::swap(lhs.m_thread, rhs.m_thread);
 }
 
 detail::SafeThreadOwnerBase::operator bool() const {
-  std::lock_guard<wpi::mutex> lock(m_mutex);
+  std::scoped_lock lock(m_mutex);
   return !m_thread.expired();
 }
 
 std::thread::native_handle_type
 detail::SafeThreadOwnerBase::GetNativeThreadHandle() {
-  std::lock_guard<wpi::mutex> lock(m_mutex);
+  std::scoped_lock lock(m_mutex);
   return m_stdThread.native_handle();
 }
 
-std::shared_ptr<SafeThread> detail::SafeThreadOwnerBase::GetThread() const {
-  std::lock_guard<wpi::mutex> lock(m_mutex);
+std::shared_ptr<SafeThread> detail::SafeThreadOwnerBase::GetThreadSharedPtr()
+    const {
+  std::scoped_lock lock(m_mutex);
   return m_thread.lock();
 }
diff --git a/wpiutil/src/main/native/cpp/TCPAcceptor.cpp b/wpiutil/src/main/native/cpp/TCPAcceptor.cpp
index 0abf862..90d9496 100644
--- a/wpiutil/src/main/native/cpp/TCPAcceptor.cpp
+++ b/wpiutil/src/main/native/cpp/TCPAcceptor.cpp
@@ -27,6 +27,7 @@
 #include <cstring>
 
 #ifdef _WIN32
+#define _WINSOCK_DEPRECATED_NO_WARNINGS
 #include <WinSock2.h>
 #include <Ws2tcpip.h>
 #pragma comment(lib, "Ws2_32.lib")
@@ -53,7 +54,7 @@
 #ifdef _WIN32
   WSAData wsaData;
   WORD wVersionRequested = MAKEWORD(2, 2);
-  WSAStartup(wVersionRequested, &wsaData);
+  (void)WSAStartup(wVersionRequested, &wsaData);
 #endif
 }
 
@@ -151,9 +152,7 @@
     return;
   address.sin_port = htons(m_port);
 
-  fd_set sdset;
-  struct timeval tv;
-  int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0);
+  int result = -1, sd = socket(AF_INET, SOCK_STREAM, 0);
   if (sd < 0) return;
 
   // Set socket to non-blocking
diff --git a/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp b/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp
index e0a8a92..de8bc2c 100644
--- a/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp
+++ b/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -74,7 +74,7 @@
     // don't start a new worker if we had a previously still-active connection
     // attempt to the same server
     {
-      std::lock_guard<wpi::mutex> lock(local->mtx);
+      std::scoped_lock lock(local->mtx);
       if (local->active.count(active_tracker) > 0) continue;  // already in set
     }
 
@@ -85,7 +85,7 @@
       if (!result->done) {
         // add to global state
         {
-          std::lock_guard<wpi::mutex> lock(local->mtx);
+          std::scoped_lock lock(local->mtx);
           local->active.insert(active_tracker);
         }
 
@@ -95,13 +95,13 @@
 
         // remove from global state
         {
-          std::lock_guard<wpi::mutex> lock(local->mtx);
+          std::scoped_lock lock(local->mtx);
           local->active.erase(active_tracker);
         }
 
         // successful connection
         if (stream) {
-          std::lock_guard<wpi::mutex> lock(result->mtx);
+          std::scoped_lock lock(result->mtx);
           if (!result->done.exchange(true)) result->stream = std::move(stream);
         }
       }
@@ -112,7 +112,7 @@
   }
 
   // wait for a result, timeout, or all finished
-  std::unique_lock<wpi::mutex> lock(result->mtx);
+  std::unique_lock lock(result->mtx);
   if (timeout == 0) {
     result->cv.wait(
         lock, [&] { return result->stream || result->count >= num_workers; });
diff --git a/wpiutil/src/main/native/cpp/WebSocket.cpp b/wpiutil/src/main/native/cpp/WebSocket.cpp
index a38be20..82c83bb 100644
--- a/wpiutil/src/main/native/cpp/WebSocket.cpp
+++ b/wpiutil/src/main/native/cpp/WebSocket.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -228,7 +228,7 @@
   });
 
   // Start handshake timer if a timeout was specified
-  if (options.handshakeTimeout != uv::Timer::Time::max()) {
+  if (options.handshakeTimeout != (uv::Timer::Time::max)()) {
     auto timer = uv::Timer::Create(m_stream.GetLoopRef());
     timer->timeout.connect(
         [this]() { Terminate(1006, "connection timed out"); });
@@ -286,8 +286,9 @@
   SmallVector<uv::Buffer, 4> bufs;
   if (code != 1005) {
     raw_uv_ostream os{bufs, 4096};
-    os << ArrayRef<uint8_t>{static_cast<uint8_t>((code >> 8) & 0xff),
-                            static_cast<uint8_t>(code & 0xff)};
+    const uint8_t codeMsb[] = {static_cast<uint8_t>((code >> 8) & 0xff),
+                               static_cast<uint8_t>(code & 0xff)};
+    os << ArrayRef<uint8_t>(codeMsb);
     reason.print(os);
   }
   Send(kFlagFin | kOpClose, bufs, [](auto bufs, uv::Error) {
@@ -335,7 +336,7 @@
     if (m_frameSize == UINT64_MAX) {
       // Need at least two bytes to determine header length
       if (m_header.size() < 2u) {
-        size_t toCopy = std::min(2u - m_header.size(), data.size());
+        size_t toCopy = (std::min)(2u - m_header.size(), data.size());
         m_header.append(data.bytes_begin(), data.bytes_begin() + toCopy);
         data = data.drop_front(toCopy);
         if (m_header.size() < 2u) return;  // need more data
@@ -362,7 +363,7 @@
 
       // Need to complete header to calculate message size
       if (m_header.size() < m_headerSize) {
-        size_t toCopy = std::min(m_headerSize - m_header.size(), data.size());
+        size_t toCopy = (std::min)(m_headerSize - m_header.size(), data.size());
         m_header.append(data.bytes_begin(), data.bytes_begin() + toCopy);
         data = data.drop_front(toCopy);
         if (m_header.size() < m_headerSize) return;  // need more data
@@ -394,7 +395,7 @@
 
     if (m_frameSize != UINT64_MAX) {
       size_t need = m_frameStart + m_frameSize - m_payload.size();
-      size_t toCopy = std::min(need, data.size());
+      size_t toCopy = (std::min)(need, data.size());
       m_payload.append(data.bytes_begin(), data.bytes_begin() + toCopy);
       data = data.drop_front(toCopy);
       need -= toCopy;
@@ -520,18 +521,20 @@
     os << static_cast<unsigned char>((m_server ? 0x00 : kFlagMasking) | size);
   } else if (size <= 0xffff) {
     os << static_cast<unsigned char>((m_server ? 0x00 : kFlagMasking) | 126);
-    os << ArrayRef<uint8_t>{static_cast<uint8_t>((size >> 8) & 0xff),
-                            static_cast<uint8_t>(size & 0xff)};
+    const uint8_t sizeMsb[] = {static_cast<uint8_t>((size >> 8) & 0xff),
+                               static_cast<uint8_t>(size & 0xff)};
+    os << ArrayRef<uint8_t>(sizeMsb);
   } else {
     os << static_cast<unsigned char>((m_server ? 0x00 : kFlagMasking) | 127);
-    os << ArrayRef<uint8_t>{static_cast<uint8_t>((size >> 56) & 0xff),
-                            static_cast<uint8_t>((size >> 48) & 0xff),
-                            static_cast<uint8_t>((size >> 40) & 0xff),
-                            static_cast<uint8_t>((size >> 32) & 0xff),
-                            static_cast<uint8_t>((size >> 24) & 0xff),
-                            static_cast<uint8_t>((size >> 16) & 0xff),
-                            static_cast<uint8_t>((size >> 8) & 0xff),
-                            static_cast<uint8_t>(size & 0xff)};
+    const uint8_t sizeMsb[] = {static_cast<uint8_t>((size >> 56) & 0xff),
+                               static_cast<uint8_t>((size >> 48) & 0xff),
+                               static_cast<uint8_t>((size >> 40) & 0xff),
+                               static_cast<uint8_t>((size >> 32) & 0xff),
+                               static_cast<uint8_t>((size >> 24) & 0xff),
+                               static_cast<uint8_t>((size >> 16) & 0xff),
+                               static_cast<uint8_t>((size >> 8) & 0xff),
+                               static_cast<uint8_t>(size & 0xff)};
+    os << ArrayRef<uint8_t>(sizeMsb);
   }
 
   // clients need to mask the input data
diff --git a/wpiutil/src/main/native/cpp/WebSocketServer.cpp b/wpiutil/src/main/native/cpp/WebSocketServer.cpp
index 3ad5e0e..056cb62 100644
--- a/wpiutil/src/main/native/cpp/WebSocketServer.cpp
+++ b/wpiutil/src/main/native/cpp/WebSocketServer.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -96,7 +96,7 @@
     auto ws = m_helper.Accept(m_stream, protocol);
 
     // Connect the websocket open event to our connected event.
-    ws->open.connect_extended([ self, s = ws.get() ](auto conn, StringRef) {
+    ws->open.connect_extended([self, s = ws.get()](auto conn, StringRef) {
       self->connected(self->m_req.GetUrl(), *s);
       conn.disconnect();  // one-shot
     });
diff --git a/wpiutil/src/main/native/cpp/future.cpp b/wpiutil/src/main/native/cpp/future.cpp
index fb31658..7ce0875 100644
--- a/wpiutil/src/main/native/cpp/future.cpp
+++ b/wpiutil/src/main/native/cpp/future.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -16,12 +16,12 @@
 }
 
 void PromiseFactoryBase::IgnoreResult(uint64_t request) {
-  std::unique_lock<wpi::mutex> lock(m_resultMutex);
+  std::unique_lock lock(m_resultMutex);
   EraseRequest(request);
 }
 
 uint64_t PromiseFactoryBase::CreateRequest() {
-  std::unique_lock<wpi::mutex> lock(m_resultMutex);
+  std::unique_lock lock(m_resultMutex);
   uint64_t req = ++m_uid;
   m_requests.push_back(req);
   return req;
@@ -39,14 +39,14 @@
 }  // namespace detail
 
 future<void> PromiseFactory<void>::MakeReadyFuture() {
-  std::unique_lock<wpi::mutex> lock(GetResultMutex());
+  std::unique_lock lock(GetResultMutex());
   uint64_t req = CreateErasedRequest();
   m_results.emplace_back(req);
   return future<void>{this, req};
 }
 
 void PromiseFactory<void>::SetValue(uint64_t request) {
-  std::unique_lock<wpi::mutex> lock(GetResultMutex());
+  std::unique_lock lock(GetResultMutex());
   if (!EraseRequest(request)) return;
   auto it = std::find_if(m_thens.begin(), m_thens.end(),
                          [=](const auto& x) { return x.request == request; });
@@ -63,7 +63,7 @@
 
 void PromiseFactory<void>::SetThen(uint64_t request, uint64_t outRequest,
                                    ThenFunction func) {
-  std::unique_lock<wpi::mutex> lock(GetResultMutex());
+  std::unique_lock lock(GetResultMutex());
   auto it = std::find_if(m_results.begin(), m_results.end(),
                          [=](const auto& r) { return r == request; });
   if (it != m_results.end()) {
@@ -75,7 +75,7 @@
 }
 
 bool PromiseFactory<void>::IsReady(uint64_t request) noexcept {
-  std::unique_lock<wpi::mutex> lock(GetResultMutex());
+  std::unique_lock lock(GetResultMutex());
   auto it = std::find_if(m_results.begin(), m_results.end(),
                          [=](const auto& r) { return r == request; });
   return it != m_results.end();
@@ -83,7 +83,7 @@
 
 void PromiseFactory<void>::GetResult(uint64_t request) {
   // wait for response
-  std::unique_lock<wpi::mutex> lock(GetResultMutex());
+  std::unique_lock lock(GetResultMutex());
   while (IsActive()) {
     // Did we get a response to *our* request?
     auto it = std::find_if(m_results.begin(), m_results.end(),
@@ -100,7 +100,7 @@
 
 void PromiseFactory<void>::WaitResult(uint64_t request) {
   // wait for response
-  std::unique_lock<wpi::mutex> lock(GetResultMutex());
+  std::unique_lock lock(GetResultMutex());
   while (IsActive()) {
     // Did we get a response to *our* request?
     auto it = std::find_if(m_results.begin(), m_results.end(),
diff --git a/wpiutil/src/main/native/cpp/http_parser.cpp b/wpiutil/src/main/native/cpp/http_parser.cpp
index 0900219..fb56010 100644
--- a/wpiutil/src/main/native/cpp/http_parser.cpp
+++ b/wpiutil/src/main/native/cpp/http_parser.cpp
@@ -25,6 +25,10 @@
 #include <string.h>
 #include <limits.h>
 
+#ifdef _WIN32
+#pragma warning(disable : 4018 26451)
+#endif
+
 #ifndef ULLONG_MAX
 # define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
 #endif
diff --git a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp
new file mode 100644
index 0000000..c14b3f4
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp
@@ -0,0 +1,54 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "edu_wpi_first_wpiutil_WPIUtilJNI.h"
+#include "wpi/PortForwarder.h"
+#include "wpi/jni_util.h"
+
+using namespace wpi::java;
+
+extern "C" {
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
+  JNIEnv* env;
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
+    return JNI_ERR;
+
+  return JNI_VERSION_1_6;
+}
+
+JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {}
+
+/*
+ * Class:     edu_wpi_first_wpiutil_WPIUtilJNI
+ * Method:    addPortForwarder
+ * Signature: (ILjava/lang/String;I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpiutil_WPIUtilJNI_addPortForwarder
+  (JNIEnv* env, jclass, jint port, jstring remoteHost, jint remotePort)
+{
+  wpi::PortForwarder::GetInstance().Add(static_cast<unsigned int>(port),
+                                        JStringRef{env, remoteHost}.str(),
+                                        static_cast<unsigned int>(remotePort));
+}
+
+/*
+ * Class:     edu_wpi_first_wpiutil_WPIUtilJNI
+ * Method:    removePortForwarder
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpiutil_WPIUtilJNI_removePortForwarder
+  (JNIEnv* env, jclass, jint port)
+{
+  wpi::PortForwarder::GetInstance().Remove(port);
+}
+
+}  // extern "C"
diff --git a/wpiutil/src/main/native/cpp/json.cpp b/wpiutil/src/main/native/cpp/json.cpp
index 9becfdd..ba9cd8e 100644
--- a/wpiutil/src/main/native/cpp/json.cpp
+++ b/wpiutil/src/main/native/cpp/json.cpp
@@ -142,24 +142,24 @@
         case value_t::object:
         {
             std::allocator<object_t> alloc;
-            alloc.destroy(object);
-            alloc.deallocate(object, 1);
+            std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
+            std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
             break;
         }
 
         case value_t::array:
         {
             std::allocator<array_t> alloc;
-            alloc.destroy(array);
-            alloc.deallocate(array, 1);
+            std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
+            std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
             break;
         }
 
         case value_t::string:
         {
             std::allocator<std::string> alloc;
-            alloc.destroy(string);
-            alloc.deallocate(string, 1);
+            std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
+            std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
             break;
         }
 
@@ -621,8 +621,8 @@
 
         case value_t::object:
         {
-            // delegate call to std::allocator<json>::max_size()
-            return std::allocator<json>().max_size();
+            // delegate call to std::allocator<object_t>::max_size()
+            return std::allocator_traits<object_t>::max_size(*m_value.object);
         }
 
         default:
diff --git a/wpiutil/src/main/native/cpp/json_binary_writer.cpp b/wpiutil/src/main/native/cpp/json_binary_writer.cpp
index 75c39aa..2c0bbee 100644
--- a/wpiutil/src/main/native/cpp/json_binary_writer.cpp
+++ b/wpiutil/src/main/native/cpp/json_binary_writer.cpp
@@ -956,7 +956,7 @@
 
         case value_t::number_unsigned:
         {
-            if (j.m_value.number_unsigned <= (std::numeric_limits<int8_t>::max)())
+            if (j.m_value.number_unsigned <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
             {
                 return 'i';
             }
@@ -964,11 +964,11 @@
             {
                 return 'U';
             }
-            else if (j.m_value.number_unsigned <= (std::numeric_limits<int16_t>::max)())
+            else if (j.m_value.number_unsigned <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
             {
                 return 'I';
             }
-            else if (j.m_value.number_unsigned <= (std::numeric_limits<int32_t>::max)())
+            else if (j.m_value.number_unsigned <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
             {
                 return 'l';
             }
diff --git a/wpiutil/src/main/native/cpp/json_serializer.h b/wpiutil/src/main/native/cpp/json_serializer.h
index a9b36d2..6983920 100644
--- a/wpiutil/src/main/native/cpp/json_serializer.h
+++ b/wpiutil/src/main/native/cpp/json_serializer.h
@@ -52,10 +52,8 @@
     @param[in] ichar  indentation character to use
     */
     serializer(raw_ostream& s, const char ichar)
-        : o(s), loc(std::localeconv()),
-          thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)),
-          decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)),
-          indent_char(ichar), indent_string(512, indent_char)
+        : o(s), loc(std::localeconv()), indent_char(ichar),
+          indent_string(512, indent_char)
     {}
 
     // delete because of pointer members
@@ -189,13 +187,6 @@
 
     /// the locale
     const std::lconv* loc = nullptr;
-    /// the locale's thousand separator character
-    const char thousands_sep = '\0';
-    /// the locale's decimal point character
-    const char decimal_point = '\0';
-
-    /// string buffer
-    std::array<char, 512> string_buffer{{}};
 
     /// the indentation character
     const char indent_char;
diff --git a/wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp b/wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp
index bf51c36..abe3744 100644
--- a/wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp
@@ -8,9 +8,9 @@
  *===------------------------------------------------------------------------=*/
 /*
  * Copyright 2001-2004 Unicode, Inc.
- * 
+ *
  * Disclaimer
- * 
+ *
  * This source code is provided as is by Unicode, Inc. No claims are
  * made as to fitness for any particular purpose. No warranties of any
  * kind are expressed or implied. The recipient agrees to determine
@@ -18,9 +18,9 @@
  * purchased on magnetic or optical media from Unicode, Inc., the
  * sole remedy for any claim will be exchange of defective media
  * within 90 days of receipt.
- * 
+ *
  * Limitations on Rights to Redistribute This Code
- * 
+ *
  * Unicode, Inc. hereby grants the right to freely use the information
  * supplied in this file in the creation of products supporting the
  * Unicode Standard, and to make copies of this file in any form
@@ -117,7 +117,7 @@
  * This table contains as many values as there might be trailing bytes
  * in a UTF-8 sequence.
  */
-static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 
+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
                      0x03C82080UL, 0xFA082080UL, 0x82082080UL };
 
 /*
@@ -143,7 +143,7 @@
 /* --------------------------------------------------------------------- */
 
 ConversionResult ConvertUTF32toUTF16 (
-        const UTF32** sourceStart, const UTF32* sourceEnd, 
+        const UTF32** sourceStart, const UTF32* sourceEnd,
         UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF32* source = *sourceStart;
@@ -192,7 +192,7 @@
 /* --------------------------------------------------------------------- */
 
 ConversionResult ConvertUTF16toUTF32 (
-        const UTF16** sourceStart, const UTF16* sourceEnd, 
+        const UTF16** sourceStart, const UTF16* sourceEnd,
         UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF16* source = *sourceStart;
@@ -246,7 +246,7 @@
     return result;
 }
 ConversionResult ConvertUTF16toUTF8 (
-        const UTF16** sourceStart, const UTF16* sourceEnd, 
+        const UTF16** sourceStart, const UTF16* sourceEnd,
         UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF16* source = *sourceStart;
@@ -255,7 +255,7 @@
         UTF32 ch;
         unsigned short bytesToWrite = 0;
         const UTF32 byteMask = 0xBF;
-        const UTF32 byteMark = 0x80; 
+        const UTF32 byteMark = 0x80;
         const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
         ch = *source++;
         /* If we have a surrogate pair, convert to UTF32 first. */
@@ -316,7 +316,7 @@
 /* --------------------------------------------------------------------- */
 
 ConversionResult ConvertUTF32toUTF8 (
-        const UTF32** sourceStart, const UTF32* sourceEnd, 
+        const UTF32** sourceStart, const UTF32* sourceEnd,
         UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF32* source = *sourceStart;
@@ -325,7 +325,7 @@
         UTF32 ch;
         unsigned short bytesToWrite = 0;
         const UTF32 byteMask = 0xBF;
-        const UTF32 byteMark = 0x80; 
+        const UTF32 byteMark = 0x80;
         ch = *source++;
         if (flags == strictConversion ) {
             /* UTF-16 surrogate values are illegal in UTF-32 */
@@ -347,7 +347,7 @@
                                             ch = UNI_REPLACEMENT_CHAR;
                                             result = sourceIllegal;
         }
-        
+
         target += bytesToWrite;
         if (target > targetEnd) {
             --source; /* Back up source pointer! */
@@ -540,7 +540,7 @@
 /* --------------------------------------------------------------------- */
 
 ConversionResult ConvertUTF8toUTF16 (
-        const UTF8** sourceStart, const UTF8* sourceEnd, 
+        const UTF8** sourceStart, const UTF8* sourceEnd,
         UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF8* source = *sourceStart;
@@ -613,7 +613,7 @@
 /* --------------------------------------------------------------------- */
 
 static ConversionResult ConvertUTF8toUTF32Impl(
-        const UTF8** sourceStart, const UTF8* sourceEnd, 
+        const UTF8** sourceStart, const UTF8* sourceEnd,
         UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags,
         Boolean InputIsPartial) {
     ConversionResult result = conversionOK;
diff --git a/wpiutil/src/main/native/cpp/llvm/Error.cpp b/wpiutil/src/main/native/cpp/llvm/Error.cpp
new file mode 100644
index 0000000..7bf9c5f
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/llvm/Error.cpp
@@ -0,0 +1,138 @@
+//===----- lib/Support/Error.cpp - Error and associated utilities ---------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "wpi/Error.h"
+#include "wpi/Twine.h"
+#include "wpi/ErrorHandling.h"
+#include "wpi/ManagedStatic.h"
+#include <system_error>
+
+using namespace wpi;
+
+namespace {
+
+  enum class ErrorErrorCode : int {
+    MultipleErrors = 1,
+    FileError,
+    InconvertibleError
+  };
+
+  // FIXME: This class is only here to support the transition to wpi::Error. It
+  // will be removed once this transition is complete. Clients should prefer to
+  // deal with the Error value directly, rather than converting to error_code.
+  class ErrorErrorCategory : public std::error_category {
+  public:
+    const char *name() const noexcept override { return "Error"; }
+
+    std::string message(int condition) const override {
+      switch (static_cast<ErrorErrorCode>(condition)) {
+      case ErrorErrorCode::MultipleErrors:
+        return "Multiple errors";
+      case ErrorErrorCode::InconvertibleError:
+        return "Inconvertible error value. An error has occurred that could "
+               "not be converted to a known std::error_code. Please file a "
+               "bug.";
+      case ErrorErrorCode::FileError:
+          return "A file error occurred.";
+      }
+      wpi_unreachable("Unhandled error code");
+    }
+  };
+
+}
+
+static ManagedStatic<ErrorErrorCategory> ErrorErrorCat;
+
+namespace wpi {
+
+void ErrorInfoBase::anchor() {}
+char ErrorInfoBase::ID = 0;
+char ErrorList::ID = 0;
+void ECError::anchor() {}
+char ECError::ID = 0;
+char StringError::ID = 0;
+char FileError::ID = 0;
+
+void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) {
+  if (!E)
+    return;
+  OS << ErrorBanner;
+  handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
+    EI.log(OS);
+    OS << "\n";
+  });
+}
+
+
+std::error_code ErrorList::convertToErrorCode() const {
+  return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors),
+                         *ErrorErrorCat);
+}
+
+std::error_code inconvertibleErrorCode() {
+  return std::error_code(static_cast<int>(ErrorErrorCode::InconvertibleError),
+                         *ErrorErrorCat);
+}
+
+std::error_code FileError::convertToErrorCode() const {
+  return std::error_code(static_cast<int>(ErrorErrorCode::FileError),
+                         *ErrorErrorCat);
+}
+
+Error errorCodeToError(std::error_code EC) {
+  if (!EC)
+    return Error::success();
+  return Error(std::make_unique<ECError>(ECError(EC)));
+}
+
+std::error_code errorToErrorCode(Error Err) {
+  std::error_code EC;
+  handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
+    EC = EI.convertToErrorCode();
+  });
+  if (EC == inconvertibleErrorCode())
+    report_fatal_error(EC.message());
+  return EC;
+}
+
+StringError::StringError(std::error_code EC, const Twine &S)
+    : Msg(S.str()), EC(EC) {}
+
+StringError::StringError(const Twine &S, std::error_code EC)
+    : Msg(S.str()), EC(EC), PrintMsgOnly(true) {}
+
+void StringError::log(raw_ostream &OS) const {
+  if (PrintMsgOnly) {
+    OS << Msg;
+  } else {
+    OS << EC.message();
+    if (!Msg.empty())
+      OS << (" " + Msg);
+  }
+}
+
+std::error_code StringError::convertToErrorCode() const {
+  return EC;
+}
+
+Error createStringError(std::error_code EC, char const *Msg) {
+  return make_error<StringError>(Msg, EC);
+}
+
+void report_fatal_error(Error Err, bool GenCrashDiag) {
+  assert(Err && "report_fatal_error called with success value");
+  std::string ErrMsg;
+  {
+    raw_string_ostream ErrStream(ErrMsg);
+    logAllUnhandledErrors(std::move(Err), ErrStream);
+  }
+  report_fatal_error(ErrMsg);
+}
+
+} // end namespace wpi
diff --git a/wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp b/wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp
index 088e805..ef79456 100644
--- a/wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp
@@ -12,7 +12,191 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "wpi/ErrorHandling.h"
+#include "wpi/SmallVector.h"
+#include "wpi/Twine.h"
+#include "wpi/Error.h"
 #include "wpi/WindowsError.h"
+#include "wpi/raw_ostream.h"
+#include <cassert>
+#include <cstdlib>
+#include <mutex>
+#include <new>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#if defined(_MSC_VER)
+#include <io.h>
+#endif
+
+using namespace wpi;
+
+static fatal_error_handler_t ErrorHandler = nullptr;
+static void *ErrorHandlerUserData = nullptr;
+
+static fatal_error_handler_t BadAllocErrorHandler = nullptr;
+static void *BadAllocErrorHandlerUserData = nullptr;
+
+// Mutexes to synchronize installing error handlers and calling error handlers.
+// Do not use ManagedStatic, or that may allocate memory while attempting to
+// report an OOM.
+//
+// This usage of std::mutex has to be conditionalized behind ifdefs because
+// of this script:
+//   compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
+// That script attempts to statically link the LLVM symbolizer library with the
+// STL and hide all of its symbols with 'opt -internalize'. To reduce size, it
+// cuts out the threading portions of the hermetic copy of libc++ that it
+// builds. We can remove these ifdefs if that script goes away.
+static std::mutex ErrorHandlerMutex;
+static std::mutex BadAllocErrorHandlerMutex;
+
+void wpi::install_fatal_error_handler(fatal_error_handler_t handler,
+                                      void *user_data) {
+  std::scoped_lock Lock(ErrorHandlerMutex);
+  assert(!ErrorHandler && "Error handler already registered!\n");
+  ErrorHandler = handler;
+  ErrorHandlerUserData = user_data;
+}
+
+void wpi::remove_fatal_error_handler() {
+  std::scoped_lock Lock(ErrorHandlerMutex);
+  ErrorHandler = nullptr;
+  ErrorHandlerUserData = nullptr;
+}
+
+void wpi::report_fatal_error(const char *Reason, bool GenCrashDiag) {
+  report_fatal_error(Twine(Reason), GenCrashDiag);
+}
+
+void wpi::report_fatal_error(const std::string &Reason, bool GenCrashDiag) {
+  report_fatal_error(Twine(Reason), GenCrashDiag);
+}
+
+void wpi::report_fatal_error(StringRef Reason, bool GenCrashDiag) {
+  report_fatal_error(Twine(Reason), GenCrashDiag);
+}
+
+void wpi::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
+  wpi::fatal_error_handler_t handler = nullptr;
+  void* handlerData = nullptr;
+  {
+    // Only acquire the mutex while reading the handler, so as not to invoke a
+    // user-supplied callback under a lock.
+    std::scoped_lock Lock(ErrorHandlerMutex);
+    handler = ErrorHandler;
+    handlerData = ErrorHandlerUserData;
+  }
+
+  if (handler) {
+    handler(handlerData, Reason.str(), GenCrashDiag);
+  } else {
+    // Blast the result out to stderr.  We don't try hard to make sure this
+    // succeeds (e.g. handling EINTR) and we can't use errs() here because
+    // raw ostreams can call report_fatal_error.
+    SmallVector<char, 64> Buffer;
+    raw_svector_ostream OS(Buffer);
+    OS << "LLVM ERROR: " << Reason << "\n";
+    StringRef MessageStr = OS.str();
+#ifdef _WIN32
+    int written = ::_write(2, MessageStr.data(), MessageStr.size());
+#else
+    ssize_t written = ::write(2, MessageStr.data(), MessageStr.size());
+#endif
+    (void)written; // If something went wrong, we deliberately just give up.
+  }
+
+  exit(1);
+}
+
+void wpi::install_bad_alloc_error_handler(fatal_error_handler_t handler,
+                                          void *user_data) {
+  std::scoped_lock Lock(BadAllocErrorHandlerMutex);
+  assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
+  BadAllocErrorHandler = handler;
+  BadAllocErrorHandlerUserData = user_data;
+}
+
+void wpi::remove_bad_alloc_error_handler() {
+  std::scoped_lock Lock(BadAllocErrorHandlerMutex);
+  BadAllocErrorHandler = nullptr;
+  BadAllocErrorHandlerUserData = nullptr;
+}
+
+void wpi::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
+  fatal_error_handler_t Handler = nullptr;
+  void *HandlerData = nullptr;
+  {
+    // Only acquire the mutex while reading the handler, so as not to invoke a
+    // user-supplied callback under a lock.
+    std::scoped_lock Lock(BadAllocErrorHandlerMutex);
+    Handler = BadAllocErrorHandler;
+    HandlerData = BadAllocErrorHandlerUserData;
+  }
+
+  if (Handler) {
+    Handler(HandlerData, Reason, GenCrashDiag);
+    wpi_unreachable("bad alloc handler should not return");
+  }
+
+  // Don't call the normal error handler. It may allocate memory. Directly write
+  // an OOM to stderr and abort.
+  char OOMMessage[] = "LLVM ERROR: out of memory\n";
+#ifdef _WIN32
+  int written = ::_write(2, OOMMessage, strlen(OOMMessage));
+#else
+  ssize_t written = ::write(2, OOMMessage, strlen(OOMMessage));
+#endif
+  (void)written;
+  abort();
+}
+
+// Causes crash on allocation failure. It is called prior to the handler set by
+// 'install_bad_alloc_error_handler'.
+static void out_of_memory_new_handler() {
+  wpi::report_bad_alloc_error("Allocation failed");
+}
+
+// Installs new handler that causes crash on allocation failure. It does not
+// need to be called explicitly, if this file is linked to application, because
+// in this case it is called during construction of 'new_handler_installer'.
+void wpi::install_out_of_memory_new_handler() {
+  static bool out_of_memory_new_handler_installed = false;
+  if (!out_of_memory_new_handler_installed) {
+    std::set_new_handler(out_of_memory_new_handler);
+    out_of_memory_new_handler_installed = true;
+  }
+}
+
+// Static object that causes installation of 'out_of_memory_new_handler' before
+// execution of 'main'.
+static class NewHandlerInstaller {
+public:
+  NewHandlerInstaller() {
+    install_out_of_memory_new_handler();
+  }
+} new_handler_installer;
+
+void wpi::wpi_unreachable_internal(const char *msg, const char *file,
+                                   unsigned line) {
+  // This code intentionally doesn't call the ErrorHandler callback, because
+  // wpi_unreachable is intended to be used to indicate "impossible"
+  // situations, and not legitimate runtime errors.
+  if (msg)
+    errs() << msg << "\n";
+  errs() << "UNREACHABLE executed";
+  if (file)
+    errs() << " at " << file << ":" << line;
+  errs() << "!\n";
+  abort();
+#ifdef LLVM_BUILTIN_UNREACHABLE
+  // Windows systems and possibly others don't declare abort() to be noreturn,
+  // so use the unreachable builtin to avoid a Clang self-host warning.
+  LLVM_BUILTIN_UNREACHABLE;
+#endif
+}
 
 #ifdef _WIN32
 
diff --git a/wpiutil/src/main/native/cpp/llvm/Hashing.cpp b/wpiutil/src/main/native/cpp/llvm/Hashing.cpp
index 51c033e..e916751 100644
--- a/wpiutil/src/main/native/cpp/llvm/Hashing.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/Hashing.cpp
@@ -20,10 +20,10 @@
 // Provide a definition and static initializer for the fixed seed. This
 // initializer should always be zero to ensure its value can never appear to be
 // non-zero, even during dynamic initialization.
-size_t wpi::hashing::detail::fixed_seed_override = 0;
+uint64_t wpi::hashing::detail::fixed_seed_override = 0;
 
 // Implement the function for forced setting of the fixed seed.
 // FIXME: Use atomic operations here so that there is no data race.
-void wpi::set_fixed_execution_hash_seed(size_t fixed_value) {
+void wpi::set_fixed_execution_hash_seed(uint64_t fixed_value) {
   hashing::detail::fixed_seed_override = fixed_value;
 }
diff --git a/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp b/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp
new file mode 100644
index 0000000..0cfe58a
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp
@@ -0,0 +1,72 @@
+//===-- ManagedStatic.cpp - Static Global wrapper -------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the ManagedStatic class and wpi_shutdown().
+//
+//===----------------------------------------------------------------------===//
+
+#include "wpi/ManagedStatic.h"
+#include "wpi/mutex.h"
+#include <cassert>
+#include <mutex>
+using namespace wpi;
+
+static const ManagedStaticBase *StaticList = nullptr;
+static wpi::mutex *ManagedStaticMutex = nullptr;
+static std::once_flag mutex_init_flag;
+
+static void initializeMutex() {
+  ManagedStaticMutex = new wpi::mutex();
+}
+
+static wpi::mutex* getManagedStaticMutex() {
+  std::call_once(mutex_init_flag, initializeMutex);
+  return ManagedStaticMutex;
+}
+
+void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
+                                              void (*Deleter)(void*)) const {
+  assert(Creator);
+  std::scoped_lock Lock(*getManagedStaticMutex());
+
+  if (!Ptr.load(std::memory_order_relaxed)) {
+    void *Tmp = Creator();
+
+    Ptr.store(Tmp, std::memory_order_release);
+    DeleterFn = Deleter;
+
+    // Add to list of managed statics.
+    Next = StaticList;
+    StaticList = this;
+  }
+}
+
+void ManagedStaticBase::destroy() const {
+  assert(DeleterFn && "ManagedStatic not initialized correctly!");
+  assert(StaticList == this &&
+         "Not destroyed in reverse order of construction?");
+  // Unlink from list.
+  StaticList = Next;
+  Next = nullptr;
+
+  // Destroy memory.
+  DeleterFn(Ptr);
+
+  // Cleanup.
+  Ptr = nullptr;
+  DeleterFn = nullptr;
+}
+
+/// wpi_shutdown - Deallocate and destroy all ManagedStatic variables.
+void wpi::wpi_shutdown() {
+  std::scoped_lock Lock(*getManagedStaticMutex());
+
+  while (StaticList)
+    StaticList->destroy();
+}
diff --git a/wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp b/wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp
index 41c43e2..985e269 100644
--- a/wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp
@@ -132,7 +132,7 @@
 }
 
 void wpi::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
-                     optional<size_t> Width) {
+                     std::optional<size_t> Width) {
   const size_t kMaxWidth = 128u;
 
   size_t W = std::min(kMaxWidth, Width.value_or(0u));
@@ -162,7 +162,7 @@
 }
 
 void wpi::write_double(raw_ostream &S, double N, FloatStyle Style,
-                        optional<size_t> Precision) {
+                        std::optional<size_t> Precision) {
   size_t Prec = Precision.value_or(getDefaultPrecision(Style));
 
   if (std::isnan(N)) {
diff --git a/wpiutil/src/main/native/cpp/llvm/Path.cpp b/wpiutil/src/main/native/cpp/llvm/Path.cpp
index 12736b9..49f92d3 100644
--- a/wpiutil/src/main/native/cpp/llvm/Path.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/Path.cpp
@@ -12,7 +12,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "wpi/Path.h"
-
+#include "wpi/ArrayRef.h"
+#include "wpi/Endian.h"
+#include "wpi/Errc.h"
+#include "wpi/ErrorHandling.h"
+#include "wpi/FileSystem.h"
+#include "wpi/SmallString.h"
 #include <cctype>
 #include <cstring>
 
@@ -22,10 +27,8 @@
 #include <io.h>
 #endif
 
-#include "wpi/FileSystem.h"
-#include "wpi/SmallString.h"
-
 using namespace wpi;
+using namespace wpi::support::endian;
 
 namespace {
   using wpi::StringRef;
@@ -444,7 +447,7 @@
 
   // If prefixes have the same size we can simply copy the new one over.
   if (OldPrefix.size() == NewPrefix.size()) {
-    std::copy(NewPrefix.begin(), NewPrefix.end(), Path.begin());
+    wpi::copy(NewPrefix, Path.begin());
     return;
   }
 
@@ -674,9 +677,8 @@
   return std::error_code();
 }
 
-static std::error_code make_absolute(const Twine &current_directory,
-                                     SmallVectorImpl<char> &path,
-                                     bool use_current_directory) {
+void make_absolute(const Twine &current_directory,
+                   SmallVectorImpl<char> &path) {
   StringRef p(path.data(), path.size());
 
   bool rootDirectory = path::has_root_directory(p);
@@ -685,14 +687,11 @@
 
   // Already absolute.
   if (rootName && rootDirectory)
-    return std::error_code();
+    return;
 
   // All of the following conditions will need the current directory.
   SmallString<128> current_dir;
-  if (use_current_directory)
-    current_directory.toVector(current_dir);
-  else if (std::error_code ec = current_path(current_dir))
-    return ec;
+  current_directory.toVector(current_dir);
 
   // Relative path. Prepend the current directory.
   if (!rootName && !rootDirectory) {
@@ -700,7 +699,7 @@
     path::append(current_dir, p);
     // Set path to the result.
     path.swap(current_dir);
-    return std::error_code();
+    return;
   }
 
   if (!rootName && rootDirectory) {
@@ -709,7 +708,7 @@
     path::append(curDirRootName, p);
     // Set path to the result.
     path.swap(curDirRootName);
-    return std::error_code();
+    return;
   }
 
   if (rootName && !rootDirectory) {
@@ -721,21 +720,23 @@
     SmallString<128> res;
     path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath);
     path.swap(res);
-    return std::error_code();
+    return;
   }
 
-  assert(false && "All rootName and rootDirectory combinations should have "
+  wpi_unreachable("All rootName and rootDirectory combinations should have "
                    "occurred above!");
-  return std::error_code();
-}
-
-std::error_code make_absolute(const Twine &current_directory,
-                              SmallVectorImpl<char> &path) {
-  return make_absolute(current_directory, path, true);
 }
 
 std::error_code make_absolute(SmallVectorImpl<char> &path) {
-  return make_absolute(Twine(), path, false);
+  if (path::is_absolute(path))
+    return {};
+
+  SmallString<128> current_dir;
+  if (std::error_code ec = current_path(current_dir))
+    return ec;
+
+  make_absolute(current_dir, path);
+  return {};
 }
 
 bool exists(const basic_file_status &status) {
@@ -803,12 +804,13 @@
   return std::error_code();
 }
 
-void directory_entry::replace_filename(const Twine &filename,
-                                       basic_file_status st) {
-  SmallString<128> path = path::parent_path(Path);
-  path::append(path, filename);
-  Path = path.str();
-  Status = st;
+void directory_entry::replace_filename(const Twine &Filename, file_type Type,
+                                       basic_file_status Status) {
+  SmallString<128> PathStr = path::parent_path(Path);
+  path::append(PathStr, Filename);
+  this->Path = PathStr.str();
+  this->Type = Type;
+  this->Status = Status;
 }
 
 ErrorOr<perms> getPermissions(const Twine &Path) {
@@ -829,20 +831,3 @@
 #else
 #include "Unix/Path.inc"
 #endif
-
-namespace wpi {
-namespace sys {
-namespace path {
-
-bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1,
-                          const Twine &Path2, const Twine &Path3) {
-  if (getUserCacheDir(Result)) {
-    append(Result, Path1, Path2, Path3);
-    return true;
-  }
-  return false;
-}
-
-} // end namespace path
-} // end namsspace sys
-} // end namespace wpi
diff --git a/wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp b/wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp
index f91b6eb..1dab1fc 100644
--- a/wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp
@@ -15,7 +15,7 @@
 #include "wpi/SmallPtrSet.h"
 #include "wpi/DenseMapInfo.h"
 #include "wpi/MathExtras.h"
-#include "wpi/memory.h"
+#include "wpi/ErrorHandling.h"
 #include <algorithm>
 #include <cassert>
 #include <cstdlib>
@@ -32,7 +32,8 @@
   NumNonEmpty = NumTombstones = 0;
 
   // Install the new array.  Clear all the buckets to empty.
-  CurArray = (const void**)CheckedMalloc(sizeof(void*) * CurArraySize);
+  CurArray = (const void**)safe_malloc(sizeof(void*) * CurArraySize);
+
   memset(CurArray, -1, CurArraySize*sizeof(void*));
 }
 
@@ -96,7 +97,10 @@
   bool WasSmall = isSmall();
 
   // Install the new array.  Clear all the buckets to empty.
-  CurArray = (const void**) CheckedMalloc(sizeof(void*) * NewSize);
+  const void **NewBuckets = (const void**) safe_malloc(sizeof(void*) * NewSize);
+
+  // Reset member only if memory was allocated successfully
+  CurArray = NewBuckets;
   CurArraySize = NewSize;
   memset(CurArray, -1, NewSize*sizeof(void*));
 
@@ -123,7 +127,7 @@
     CurArray = SmallArray;
   // Otherwise, allocate new heap space (unless we were the same size)
   } else {
-    CurArray = (const void**)CheckedMalloc(sizeof(void*) * that.CurArraySize);
+    CurArray = (const void**)safe_malloc(sizeof(void*) * that.CurArraySize);
   }
 
   // Copy over the that array.
@@ -152,15 +156,12 @@
   // Otherwise, allocate new heap space (unless we were the same size)
   } else if (CurArraySize != RHS.CurArraySize) {
     if (isSmall())
-      CurArray = (const void**)malloc(sizeof(void*) * RHS.CurArraySize);
+      CurArray = (const void**)safe_malloc(sizeof(void*) * RHS.CurArraySize);
     else {
-      const void **T = (const void**)realloc(CurArray,
+      const void **T = (const void**)safe_realloc(CurArray,
                                              sizeof(void*) * RHS.CurArraySize);
-      if (!T)
-        free(CurArray);
       CurArray = T;
     }
-    assert(CurArray && "Failed to allocate memory?");
   }
 
   CopyHelper(RHS);
diff --git a/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp b/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp
index faa5ba7..974fec9 100644
--- a/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp
@@ -12,30 +12,32 @@
 //===----------------------------------------------------------------------===//
 
 #include "wpi/SmallVector.h"
-#include "wpi/memory.h"
+#include "wpi/MemAlloc.h"
 using namespace wpi;
 
 /// grow_pod - This is an implementation of the grow() method which only works
 /// on POD-like datatypes and is out of line to reduce code duplication.
-void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes,
+void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
                                size_t TSize) {
-  size_t CurSizeBytes = size_in_bytes();
-  size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow.
-  if (NewCapacityInBytes < MinSizeInBytes)
-    NewCapacityInBytes = MinSizeInBytes;
+  // Ensure we can fit the new capacity in 32 bits.
+  if (MinCapacity > UINT32_MAX)
+    report_bad_alloc_error("SmallVector capacity overflow during allocation");
+
+  size_t NewCapacity = 2 * capacity() + 1; // Always grow.
+  NewCapacity =
+      std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
 
   void *NewElts;
   if (BeginX == FirstEl) {
-    NewElts = CheckedMalloc(NewCapacityInBytes);
+    NewElts = safe_malloc(NewCapacity * TSize);
 
     // Copy the elements over.  No need to run dtors on PODs.
-    memcpy(NewElts, this->BeginX, CurSizeBytes);
+    memcpy(NewElts, this->BeginX, size() * TSize);
   } else {
     // If this wasn't grown from the inline copy, grow the allocated space.
-    NewElts = CheckedRealloc(this->BeginX, NewCapacityInBytes);
+    NewElts = safe_realloc(this->BeginX, NewCapacity * TSize);
   }
 
-  this->EndX = (char*)NewElts+CurSizeBytes;
   this->BeginX = NewElts;
-  this->CapacityX = (char*)this->BeginX + NewCapacityInBytes;
+  this->Capacity = NewCapacity;
 }
diff --git a/wpiutil/src/main/native/cpp/llvm/StringExtras.cpp b/wpiutil/src/main/native/cpp/llvm/StringExtras.cpp
index 41c3305..e4bfe8a 100644
--- a/wpiutil/src/main/native/cpp/llvm/StringExtras.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/StringExtras.cpp
@@ -58,16 +58,33 @@
   }
 }
 
-void wpi::PrintEscapedString(StringRef Name, raw_ostream &Out) {
+void wpi::printEscapedString(StringRef Name, raw_ostream &Out) {
   for (unsigned i = 0, e = Name.size(); i != e; ++i) {
     unsigned char C = Name[i];
-    if (isprint(C) && C != '\\' && C != '"')
+    if (isPrint(C) && C != '\\' && C != '"')
       Out << C;
     else
       Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
   }
 }
 
+void wpi::printHTMLEscaped(StringRef String, raw_ostream &Out) {
+  for (char C : String) {
+    if (C == '&')
+      Out << "&amp;";
+    else if (C == '<')
+      Out << "&lt;";
+    else if (C == '>')
+      Out << "&gt;";
+    else if (C == '\"')
+      Out << "&quot;";
+    else if (C == '\'')
+      Out << "&apos;";
+    else
+      Out << C;
+  }
+}
+
 void wpi::printLowerCase(StringRef String, raw_ostream &Out) {
   for (const char C : String)
     Out << toLower(C);
diff --git a/wpiutil/src/main/native/cpp/llvm/StringMap.cpp b/wpiutil/src/main/native/cpp/llvm/StringMap.cpp
index ea91dbb..5c625c7 100644
--- a/wpiutil/src/main/native/cpp/llvm/StringMap.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/StringMap.cpp
@@ -15,7 +15,6 @@
 #include "wpi/StringExtras.h"
 #include "wpi/Compiler.h"
 #include "wpi/MathExtras.h"
-#include "wpi/memory.h"
 #include <cassert>
 
 using namespace wpi;
@@ -59,7 +58,7 @@
   NumTombstones = 0;
 
   TheTable = static_cast<StringMapEntryBase **>(
-      CheckedCalloc(NewNumBuckets+1,
+      safe_calloc(NewNumBuckets+1,
                   sizeof(StringMapEntryBase **) + sizeof(unsigned)));
 
   // Set the member only if TheTable was successfully allocated
@@ -129,7 +128,6 @@
   }
 }
 
-
 /// FindKey - Look up the bucket that contains the specified key. If it exists
 /// in the map, return the bucket number of the key.  Otherwise return -1.
 /// This does not modify the map.
@@ -219,7 +217,7 @@
   // Allocate one extra bucket which will always be non-empty.  This allows the
   // iterators to stop at end.
   auto NewTableArray = static_cast<StringMapEntryBase **>(
-      CheckedCalloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
+      safe_calloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
 
   unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
   NewTableArray[NewSize] = (StringMapEntryBase*)2;
diff --git a/wpiutil/src/main/native/cpp/llvm/Unix/Path.inc b/wpiutil/src/main/native/cpp/llvm/Unix/Path.inc
index a1ea5a1..b786813 100644
--- a/wpiutil/src/main/native/cpp/llvm/Unix/Path.inc
+++ b/wpiutil/src/main/native/cpp/llvm/Unix/Path.inc
@@ -16,25 +16,45 @@
 //===          is guaranteed to work on *all* UNIX variants.
 //===----------------------------------------------------------------------===//
 
+#include "wpi/Errno.h"
 #include <fcntl.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
 #include <dirent.h>
-#define NAMLEN(dirent) strlen((dirent)->d_name)
+#include <pwd.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+using namespace wpi;
+
 namespace wpi {
 namespace sys  {
 namespace fs {
+
+const file_t kInvalidFile = -1;
+
+TimePoint<> basic_file_status::getLastAccessedTime() const {
+  return toTimePoint(fs_st_atime, fs_st_atime_nsec);
+}
+
+TimePoint<> basic_file_status::getLastModificationTime() const {
+  return toTimePoint(fs_st_mtime, fs_st_mtime_nsec);
+}
+
 UniqueID file_status::getUniqueID() const {
   return UniqueID(fs_st_dev, fs_st_ino);
 }
 
+uint32_t file_status::getLinkCount() const {
+  return fs_st_nlinks;
+}
+
 std::error_code current_path(SmallVectorImpl<char> &result) {
   result.clear();
 
@@ -93,9 +113,9 @@
     // Don't say that directories are executable.
     struct stat buf;
     if (0 != stat(P.begin(), &buf))
-      return std::make_error_code(std::errc::permission_denied);
+      return errc::permission_denied;
     if (!S_ISREG(buf.st_mode))
-      return std::make_error_code(std::errc::permission_denied);
+      return errc::permission_denied;
   }
 
   return std::error_code();
@@ -117,37 +137,48 @@
   return std::error_code();
 }
 
+static file_type typeForMode(mode_t Mode) {
+  if (S_ISDIR(Mode))
+    return file_type::directory_file;
+  else if (S_ISREG(Mode))
+    return file_type::regular_file;
+  else if (S_ISBLK(Mode))
+    return file_type::block_file;
+  else if (S_ISCHR(Mode))
+    return file_type::character_file;
+  else if (S_ISFIFO(Mode))
+    return file_type::fifo_file;
+  else if (S_ISSOCK(Mode))
+    return file_type::socket_file;
+  else if (S_ISLNK(Mode))
+    return file_type::symlink_file;
+  return file_type::type_unknown;
+}
+
 static std::error_code fillStatus(int StatRet, const struct stat &Status,
-                             file_status &Result) {
+                                  file_status &Result) {
   if (StatRet != 0) {
-    std::error_code ec(errno, std::generic_category());
-    if (ec == std::errc::no_such_file_or_directory)
+    std::error_code EC(errno, std::generic_category());
+    if (EC == errc::no_such_file_or_directory)
       Result = file_status(file_type::file_not_found);
     else
       Result = file_status(file_type::status_error);
-    return ec;
+    return EC;
   }
 
-  file_type Type = file_type::type_unknown;
-
-  if (S_ISDIR(Status.st_mode))
-    Type = file_type::directory_file;
-  else if (S_ISREG(Status.st_mode))
-    Type = file_type::regular_file;
-  else if (S_ISBLK(Status.st_mode))
-    Type = file_type::block_file;
-  else if (S_ISCHR(Status.st_mode))
-    Type = file_type::character_file;
-  else if (S_ISFIFO(Status.st_mode))
-    Type = file_type::fifo_file;
-  else if (S_ISSOCK(Status.st_mode))
-    Type = file_type::socket_file;
-  else if (S_ISLNK(Status.st_mode))
-    Type = file_type::symlink_file;
+  uint32_t atime_nsec, mtime_nsec;
+#if defined(__APPLE__)
+  atime_nsec = Status.st_atimespec.tv_nsec;
+  mtime_nsec = Status.st_mtimespec.tv_nsec;
+#else
+  atime_nsec = Status.st_atim.tv_nsec;
+  mtime_nsec = Status.st_mtim.tv_nsec;
+#endif
 
   perms Perms = static_cast<perms>(Status.st_mode) & all_perms;
-  Result = file_status(Type, Perms, Status.st_dev, Status.st_nlink,
-                       Status.st_ino, Status.st_atime, Status.st_mtime,
+  Result = file_status(typeForMode(Status.st_mode), Perms, Status.st_dev,
+                       Status.st_nlink, Status.st_ino,
+                       Status.st_atime, atime_nsec, Status.st_mtime, mtime_nsec,
                        Status.st_uid, Status.st_gid, Status.st_size);
 
   return std::error_code();
@@ -168,6 +199,71 @@
   return fillStatus(StatRet, Status, Result);
 }
 
+std::error_code mapped_file_region::init(int FD, uint64_t Offset,
+                                         mapmode Mode) {
+  assert(Size != 0);
+
+  int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE;
+  int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE);
+#if defined(__APPLE__)
+  //----------------------------------------------------------------------
+  // Newer versions of MacOSX have a flag that will allow us to read from
+  // binaries whose code signature is invalid without crashing by using
+  // the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media
+  // is mapped we can avoid crashing and return zeroes to any pages we try
+  // to read if the media becomes unavailable by using the
+  // MAP_RESILIENT_MEDIA flag.  These flags are only usable when mapping
+  // with PROT_READ, so take care not to specify them otherwise.
+  //----------------------------------------------------------------------
+  if (Mode == readonly) {
+#if defined(MAP_RESILIENT_CODESIGN)
+    flags |= MAP_RESILIENT_CODESIGN;
+#endif
+#if defined(MAP_RESILIENT_MEDIA)
+    flags |= MAP_RESILIENT_MEDIA;
+#endif
+  }
+#endif // #if defined (__APPLE__)
+
+  Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset);
+  if (Mapping == MAP_FAILED)
+    return std::error_code(errno, std::generic_category());
+  return std::error_code();
+}
+
+mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,
+                                       uint64_t offset, std::error_code &ec)
+    : Size(length), Mapping(), Mode(mode) {
+  (void)Mode;
+  ec = init(fd, offset, mode);
+  if (ec)
+    Mapping = nullptr;
+}
+
+mapped_file_region::~mapped_file_region() {
+  if (Mapping)
+    ::munmap(Mapping, Size);
+}
+
+size_t mapped_file_region::size() const {
+  assert(Mapping && "Mapping failed but used anyway!");
+  return Size;
+}
+
+char *mapped_file_region::data() const {
+  assert(Mapping && "Mapping failed but used anyway!");
+  return reinterpret_cast<char*>(Mapping);
+}
+
+const char *mapped_file_region::const_data() const {
+  assert(Mapping && "Mapping failed but used anyway!");
+  return reinterpret_cast<const char*>(Mapping);
+}
+
+int mapped_file_region::alignment() {
+  return ::sysconf(_SC_PAGE_SIZE);
+}
+
 std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
                                                      StringRef path,
                                                      bool follow_symlinks) {
@@ -191,19 +287,25 @@
   return std::error_code();
 }
 
-std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
+static file_type direntType(dirent* Entry) {
+  // Most platforms provide the file type in the dirent: Linux/BSD/Mac.
+  // The DTTOIF macro lets us reuse our status -> type conversion.
+  return typeForMode(DTTOIF(Entry->d_type));
+}
+
+std::error_code detail::directory_iterator_increment(detail::DirIterState &It) {
   errno = 0;
-  dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle));
-  if (cur_dir == nullptr && errno != 0) {
+  dirent *CurDir = ::readdir(reinterpret_cast<DIR *>(It.IterationHandle));
+  if (CurDir == nullptr && errno != 0) {
     return std::error_code(errno, std::generic_category());
-  } else if (cur_dir != nullptr) {
-    StringRef name(cur_dir->d_name, NAMLEN(cur_dir));
-    if ((name.size() == 1 && name[0] == '.') ||
-        (name.size() == 2 && name[0] == '.' && name[1] == '.'))
-      return directory_iterator_increment(it);
-    it.CurrentEntry.replace_filename(name);
+  } else if (CurDir != nullptr) {
+    StringRef Name(CurDir->d_name);
+    if ((Name.size() == 1 && Name[0] == '.') ||
+        (Name.size() == 2 && Name[0] == '.' && Name[1] == '.'))
+      return directory_iterator_increment(It);
+    It.CurrentEntry.replace_filename(Name, direntType(CurDir));
   } else
-    return directory_iterator_destruct(it);
+    return directory_iterator_destruct(It);
 
   return std::error_code();
 }
@@ -224,14 +326,85 @@
 }
 #endif
 
-std::error_code openFileForRead(const Twine &Name, int &ResultFD,
-                                SmallVectorImpl<char> *RealPath) {
+static int nativeOpenFlags(CreationDisposition Disp, OpenFlags Flags,
+                           FileAccess Access) {
+  int Result = 0;
+  if (Access == FA_Read)
+    Result |= O_RDONLY;
+  else if (Access == FA_Write)
+    Result |= O_WRONLY;
+  else if (Access == (FA_Read | FA_Write))
+    Result |= O_RDWR;
+
+  // This is for compatibility with old code that assumed F_Append implied
+  // would open an existing file.  See Windows/Path.inc for a longer comment.
+  if (Flags & F_Append)
+    Disp = CD_OpenAlways;
+
+  if (Disp == CD_CreateNew) {
+    Result |= O_CREAT; // Create if it doesn't exist.
+    Result |= O_EXCL;  // Fail if it does.
+  } else if (Disp == CD_CreateAlways) {
+    Result |= O_CREAT; // Create if it doesn't exist.
+    Result |= O_TRUNC; // Truncate if it does.
+  } else if (Disp == CD_OpenAlways) {
+    Result |= O_CREAT; // Create if it doesn't exist.
+  } else if (Disp == CD_OpenExisting) {
+    // Nothing special, just don't add O_CREAT and we get these semantics.
+  }
+
+  if (Flags & F_Append)
+    Result |= O_APPEND;
+
+#ifdef O_CLOEXEC
+  if (!(Flags & OF_ChildInherit))
+    Result |= O_CLOEXEC;
+#endif
+
+  return Result;
+}
+
+std::error_code openFile(const Twine &Name, int &ResultFD,
+                         CreationDisposition Disp, FileAccess Access,
+                         OpenFlags Flags, unsigned Mode) {
+  int OpenFlags = nativeOpenFlags(Disp, Flags, Access);
+
   SmallString<128> Storage;
   StringRef P = Name.toNullTerminatedStringRef(Storage);
-  while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) {
-    if (errno != EINTR)
-      return std::error_code(errno, std::generic_category());
+  // Call ::open in a lambda to avoid overload resolution in RetryAfterSignal
+  // when open is overloaded, such as in Bionic.
+  auto Open = [&]() { return ::open(P.begin(), OpenFlags, Mode); };
+  if ((ResultFD = sys::RetryAfterSignal(-1, Open)) < 0)
+    return std::error_code(errno, std::generic_category());
+#ifndef O_CLOEXEC
+  if (!(Flags & OF_ChildInherit)) {
+    int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
+    (void)r;
+    assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
   }
+#endif
+  return std::error_code();
+}
+
+Expected<int> openNativeFile(const Twine &Name, CreationDisposition Disp,
+                             FileAccess Access, OpenFlags Flags,
+                             unsigned Mode) {
+
+  int FD;
+  std::error_code EC = openFile(Name, FD, Disp, Access, Flags, Mode);
+  if (EC)
+    return errorCodeToError(EC);
+  return FD;
+}
+
+std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+                                OpenFlags Flags,
+                                SmallVectorImpl<char> *RealPath) {
+  std::error_code EC =
+      openFile(Name, ResultFD, CD_OpenExisting, FA_Read, Flags, 0666);
+  if (EC)
+    return EC;
+
   // Attempt to get the real name of the file, if the user asked
   if(!RealPath)
     return std::error_code();
@@ -251,6 +424,9 @@
     if (CharCount > 0)
       RealPath->append(Buffer, Buffer + CharCount);
   } else {
+    SmallString<128> Storage;
+    StringRef P = Name.toNullTerminatedStringRef(Storage);
+
     // Use ::realpath to get the real path name
     if (::realpath(P.begin(), Buffer) != nullptr)
       RealPath->append(Buffer, Buffer + strlen(Buffer));
@@ -259,38 +435,18 @@
   return std::error_code();
 }
 
-std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
-                                 OpenFlags Flags, unsigned Mode) {
-  // Verify that we don't have both "append" and "excl".
-  assert((!(Flags & F_Excl) || !(Flags & F_Append)) &&
-         "Cannot specify both 'excl' and 'append' file creation flags!");
+Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags,
+                                       SmallVectorImpl<char> *RealPath) {
+  file_t ResultFD;
+  std::error_code EC = openFileForRead(Name, ResultFD, Flags, RealPath);
+  if (EC)
+    return errorCodeToError(EC);
+  return ResultFD;
+}
 
-  int OpenFlags = O_CREAT;
-
-#ifdef O_CLOEXEC
-  OpenFlags |= O_CLOEXEC;
-#endif
-
-  if (Flags & F_RW)
-    OpenFlags |= O_RDWR;
-  else
-    OpenFlags |= O_WRONLY;
-
-  if (Flags & F_Append)
-    OpenFlags |= O_APPEND;
-  else if (!(Flags & F_NoTrunc))
-    OpenFlags |= O_TRUNC;
-
-  if (Flags & F_Excl)
-    OpenFlags |= O_EXCL;
-
-  SmallString<128> Storage;
-  StringRef P = Name.toNullTerminatedStringRef(Storage);
-  while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) {
-    if (errno != EINTR)
-      return std::error_code(errno, std::generic_category());
-  }
-  return std::error_code();
+void closeFile(file_t &F) {
+  ::close(F);
+  F = kInvalidFile;
 }
 
 } // end namespace fs
@@ -298,13 +454,18 @@
 namespace path {
 
 bool home_directory(SmallVectorImpl<char> &result) {
-  if (char *RequestedDir = std::getenv("HOME")) {
-    result.clear();
-    result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
-    return true;
+  char *RequestedDir = getenv("HOME");
+  if (!RequestedDir) {
+    struct passwd *pw = getpwuid(getuid());
+    if (pw && pw->pw_dir)
+      RequestedDir = pw->pw_dir;
   }
+  if (!RequestedDir)
+    return false;
 
-  return false;
+  result.clear();
+  result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+  return true;
 }
 
 static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {
@@ -332,29 +493,6 @@
   return false;
 }
 
-static bool getUserCacheDir(SmallVectorImpl<char> &Result) {
-  // First try using XDG_CACHE_HOME env variable,
-  // as specified in XDG Base Directory Specification at
-  // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
-  if (const char *XdgCacheDir = std::getenv("XDG_CACHE_HOME")) {
-    Result.clear();
-    Result.append(XdgCacheDir, XdgCacheDir + strlen(XdgCacheDir));
-    return true;
-  }
-
-  // Try Darwin configuration query
-  if (getDarwinConfDir(false, Result))
-    return true;
-
-  // Use "$HOME/.cache" if $HOME is available
-  if (home_directory(Result)) {
-    append(Result, ".cache");
-    return true;
-  }
-
-  return false;
-}
-
 static const char *getEnvTempDir() {
   // Check whether the temporary directory is specified by an environment
   // variable.
diff --git a/wpiutil/src/main/native/cpp/llvm/Windows/Path.inc b/wpiutil/src/main/native/cpp/llvm/Windows/Path.inc
index 3a170eb..e9b5280 100644
--- a/wpiutil/src/main/native/cpp/llvm/Windows/Path.inc
+++ b/wpiutil/src/main/native/cpp/llvm/Windows/Path.inc
@@ -17,6 +17,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "wpi/STLExtras.h"
+#include "wpi/ConvertUTF.h"
 #include "wpi/WindowsError.h"
 #include <fcntl.h>
 #include <io.h>
@@ -31,9 +32,17 @@
 
 #undef max
 
+// MinGW doesn't define this.
+#ifndef _ERRNO_T_DEFINED
+#define _ERRNO_T_DEFINED
+typedef int errno_t;
+#endif
+
 #ifdef _MSC_VER
 # pragma comment(lib, "shell32.lib")
 # pragma comment(lib, "ole32.lib")
+#pragma warning(push)
+#pragma warning(disable: 4244 4267 4146)
 #endif
 
 using namespace wpi;
@@ -116,6 +125,8 @@
 
 namespace fs {
 
+const file_t kInvalidFile = INVALID_HANDLE_VALUE;
+
 UniqueID file_status::getUniqueID() const {
   // The file is uniquely identified by the volume serial number along
   // with the 64-bit file identifier.
@@ -125,6 +136,24 @@
   return UniqueID(VolumeSerialNumber, FileID);
 }
 
+TimePoint<> basic_file_status::getLastAccessedTime() const {
+  FILETIME Time;
+  Time.dwLowDateTime = LastAccessedTimeLow;
+  Time.dwHighDateTime = LastAccessedTimeHigh;
+  return toTimePoint(Time);
+}
+
+TimePoint<> basic_file_status::getLastModificationTime() const {
+  FILETIME Time;
+  Time.dwLowDateTime = LastWriteTimeLow;
+  Time.dwHighDateTime = LastWriteTimeHigh;
+  return toTimePoint(Time);
+}
+
+uint32_t file_status::getLinkCount() const {
+  return NumLinks;
+}
+
 std::error_code current_path(SmallVectorImpl<char> &result) {
   SmallVector<wchar_t, MAX_PATH> cur_path;
   DWORD len = MAX_PATH;
@@ -147,6 +176,51 @@
   return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result);
 }
 
+static std::error_code realPathFromHandle(HANDLE H,
+                                          SmallVectorImpl<wchar_t> &Buffer) {
+  DWORD CountChars = ::GetFinalPathNameByHandleW(
+      H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED);
+  if (CountChars > Buffer.capacity()) {
+    // The buffer wasn't big enough, try again.  In this case the return value
+    // *does* indicate the size of the null terminator.
+    Buffer.reserve(CountChars);
+    CountChars = ::GetFinalPathNameByHandleW(
+        H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED);
+  }
+  if (CountChars == 0)
+    return mapWindowsError(GetLastError());
+  Buffer.set_size(CountChars);
+  return std::error_code();
+}
+
+static std::error_code realPathFromHandle(HANDLE H,
+                                          SmallVectorImpl<char> &RealPath) {
+  RealPath.clear();
+  SmallVector<wchar_t, MAX_PATH> Buffer;
+  if (std::error_code EC = realPathFromHandle(H, Buffer))
+    return EC;
+
+  const wchar_t *Data = Buffer.data();
+  DWORD CountChars = Buffer.size();
+  if (CountChars >= 4) {
+    if (0 == ::memcmp(Data, L"\\\\?\\", 8)) {
+      CountChars -= 4;
+      Data += 4;
+    }
+  }
+
+  // Convert the result from UTF-16 to UTF-8.
+  return UTF16ToUTF8(Data, CountChars, RealPath);
+}
+
+static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) {
+  FILE_DISPOSITION_INFO Disposition;
+  Disposition.DeleteFile = Delete;
+  if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &Disposition,
+                                  sizeof(Disposition)))
+    return mapWindowsError(::GetLastError());
+  return std::error_code();
+}
 
 std::error_code access(const Twine &Path, AccessMode Mode) {
   SmallVector<wchar_t, 128> PathUtf16;
@@ -162,11 +236,11 @@
     if (LastError != ERROR_FILE_NOT_FOUND &&
         LastError != ERROR_PATH_NOT_FOUND)
       return mapWindowsError(LastError);
-    return std::make_error_code(std::errc::no_such_file_or_directory);
+    return errc::no_such_file_or_directory;
   }
 
   if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY))
-    return std::make_error_code(std::errc::permission_denied);
+    return errc::permission_denied;
 
   return std::error_code();
 }
@@ -315,6 +389,143 @@
   return getStatus(FileHandle, Result);
 }
 
+std::error_code mapped_file_region::init(int FD, uint64_t Offset,
+                                         mapmode Mode) {
+  this->Mode = Mode;
+  HANDLE OrigFileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+  if (OrigFileHandle == INVALID_HANDLE_VALUE)
+    return make_error_code(errc::bad_file_descriptor);
+
+  DWORD flprotect;
+  switch (Mode) {
+  case readonly:  flprotect = PAGE_READONLY; break;
+  case readwrite: flprotect = PAGE_READWRITE; break;
+  case priv:      flprotect = PAGE_WRITECOPY; break;
+  }
+
+  HANDLE FileMappingHandle =
+      ::CreateFileMappingW(OrigFileHandle, 0, flprotect,
+                           Hi_32(Size),
+                           Lo_32(Size),
+                           0);
+  if (FileMappingHandle == NULL) {
+    std::error_code ec = mapWindowsError(GetLastError());
+    return ec;
+  }
+
+  DWORD dwDesiredAccess;
+  switch (Mode) {
+  case readonly:  dwDesiredAccess = FILE_MAP_READ; break;
+  case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break;
+  case priv:      dwDesiredAccess = FILE_MAP_COPY; break;
+  }
+  Mapping = ::MapViewOfFile(FileMappingHandle,
+                            dwDesiredAccess,
+                            Offset >> 32,
+                            Offset & 0xffffffff,
+                            Size);
+  if (Mapping == NULL) {
+    std::error_code ec = mapWindowsError(GetLastError());
+    ::CloseHandle(FileMappingHandle);
+    return ec;
+  }
+
+  if (Size == 0) {
+    MEMORY_BASIC_INFORMATION mbi;
+    SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi));
+    if (Result == 0) {
+      std::error_code ec = mapWindowsError(GetLastError());
+      ::UnmapViewOfFile(Mapping);
+      ::CloseHandle(FileMappingHandle);
+      return ec;
+    }
+    Size = mbi.RegionSize;
+  }
+
+  // Close the file mapping handle, as it's kept alive by the file mapping. But
+  // neither the file mapping nor the file mapping handle keep the file handle
+  // alive, so we need to keep a reference to the file in case all other handles
+  // are closed and the file is deleted, which may cause invalid data to be read
+  // from the file.
+  ::CloseHandle(FileMappingHandle);
+  if (!::DuplicateHandle(::GetCurrentProcess(), OrigFileHandle,
+                         ::GetCurrentProcess(), &FileHandle, 0, 0,
+                         DUPLICATE_SAME_ACCESS)) {
+    std::error_code ec = mapWindowsError(GetLastError());
+    ::UnmapViewOfFile(Mapping);
+    return ec;
+  }
+
+  return std::error_code();
+}
+
+mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,
+                                       uint64_t offset, std::error_code &ec)
+    : Size(length), Mapping() {
+  ec = init(fd, offset, mode);
+  if (ec)
+    Mapping = 0;
+}
+
+static bool hasFlushBufferKernelBug() {
+  static bool Ret{GetWindowsOSVersion() < wpi::VersionTuple(10, 0, 0, 17763)};
+  return Ret;
+}
+
+static bool isEXE(StringRef Magic) {
+  static const char PEMagic[] = {'P', 'E', '\0', '\0'};
+  if (Magic.startswith(StringRef("MZ")) && Magic.size() >= 0x3c + 4) {
+    uint32_t off = read32le(Magic.data() + 0x3c);
+    // PE/COFF file, either EXE or DLL.
+    if (Magic.substr(off).startswith(StringRef(PEMagic, sizeof(PEMagic))))
+      return true;
+  }
+  return false;
+}
+
+mapped_file_region::~mapped_file_region() {
+  if (Mapping) {
+
+    bool Exe = isEXE(StringRef((char *)Mapping, Size));
+
+    ::UnmapViewOfFile(Mapping);
+
+    if (Mode == mapmode::readwrite && Exe && hasFlushBufferKernelBug()) {
+      // There is a Windows kernel bug, the exact trigger conditions of which
+      // are not well understood.  When triggered, dirty pages are not properly
+      // flushed and subsequent process's attempts to read a file can return
+      // invalid data.  Calling FlushFileBuffers on the write handle is
+      // sufficient to ensure that this bug is not triggered.
+      // The bug only occurs when writing an executable and executing it right
+      // after, under high I/O pressure.
+      ::FlushFileBuffers(FileHandle);
+    }
+
+    ::CloseHandle(FileHandle);
+  }
+}
+
+size_t mapped_file_region::size() const {
+  assert(Mapping && "Mapping failed but used anyway!");
+  return Size;
+}
+
+char *mapped_file_region::data() const {
+  assert(Mapping && "Mapping failed but used anyway!");
+  return reinterpret_cast<char*>(Mapping);
+}
+
+const char *mapped_file_region::const_data() const {
+  assert(Mapping && "Mapping failed but used anyway!");
+  return reinterpret_cast<const char*>(Mapping);
+}
+
+int mapped_file_region::alignment() {
+  SYSTEM_INFO SysInfo;
+  ::GetSystemInfo(&SysInfo);
+  return SysInfo.dwAllocationGranularity;
+}
+
 static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) {
   return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes),
                            perms_from_attrs(FindData->dwFileAttributes),
@@ -325,28 +536,28 @@
                            FindData->nFileSizeHigh, FindData->nFileSizeLow);
 }
 
-std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
-                                                     StringRef path,
-                                                     bool follow_symlinks) {
-  SmallVector<wchar_t, 128> path_utf16;
+std::error_code detail::directory_iterator_construct(detail::DirIterState &IT,
+                                                     StringRef Path,
+                                                     bool FollowSymlinks) {
+  SmallVector<wchar_t, 128> PathUTF16;
 
-  if (std::error_code ec = widenPath(path, path_utf16))
-    return ec;
+  if (std::error_code EC = widenPath(Path, PathUTF16))
+    return EC;
 
   // Convert path to the format that Windows is happy with.
-  if (path_utf16.size() > 0 &&
-      !is_separator(path_utf16[path.size() - 1]) &&
-      path_utf16[path.size() - 1] != L':') {
-    path_utf16.push_back(L'\\');
-    path_utf16.push_back(L'*');
+  if (PathUTF16.size() > 0 &&
+      !is_separator(PathUTF16[Path.size() - 1]) &&
+      PathUTF16[Path.size() - 1] != L':') {
+    PathUTF16.push_back(L'\\');
+    PathUTF16.push_back(L'*');
   } else {
-    path_utf16.push_back(L'*');
+    PathUTF16.push_back(L'*');
   }
 
   //  Get the first directory entry.
   WIN32_FIND_DATAW FirstFind;
   ScopedFindHandle FindHandle(::FindFirstFileExW(
-      c_str(path_utf16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch,
+      c_str(PathUTF16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch,
       NULL, FIND_FIRST_EX_LARGE_FETCH));
   if (!FindHandle)
     return mapWindowsError(::GetLastError());
@@ -359,43 +570,45 @@
       DWORD LastError = ::GetLastError();
       // Check for end.
       if (LastError == ERROR_NO_MORE_FILES)
-        return detail::directory_iterator_destruct(it);
+        return detail::directory_iterator_destruct(IT);
       return mapWindowsError(LastError);
     } else
       FilenameLen = ::wcslen(FirstFind.cFileName);
 
   // Construct the current directory entry.
-  SmallString<128> directory_entry_name_utf8;
-  if (std::error_code ec =
+  SmallString<128> DirectoryEntryNameUTF8;
+  if (std::error_code EC =
           UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName),
-                      directory_entry_name_utf8))
-    return ec;
+                      DirectoryEntryNameUTF8))
+    return EC;
 
-  it.IterationHandle = intptr_t(FindHandle.take());
-  SmallString<128> directory_entry_path(path);
-  path::append(directory_entry_path, directory_entry_name_utf8);
-  it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks,
-                                    status_from_find_data(&FirstFind));
+  IT.IterationHandle = intptr_t(FindHandle.take());
+  SmallString<128> DirectoryEntryPath(Path);
+  path::append(DirectoryEntryPath, DirectoryEntryNameUTF8);
+  IT.CurrentEntry =
+      directory_entry(DirectoryEntryPath, FollowSymlinks,
+                      file_type_from_attrs(FirstFind.dwFileAttributes),
+                      status_from_find_data(&FirstFind));
 
   return std::error_code();
 }
 
-std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
-  if (it.IterationHandle != 0)
+std::error_code detail::directory_iterator_destruct(detail::DirIterState &IT) {
+  if (IT.IterationHandle != 0)
     // Closes the handle if it's valid.
-    ScopedFindHandle close(HANDLE(it.IterationHandle));
-  it.IterationHandle = 0;
-  it.CurrentEntry = directory_entry();
+    ScopedFindHandle close(HANDLE(IT.IterationHandle));
+  IT.IterationHandle = 0;
+  IT.CurrentEntry = directory_entry();
   return std::error_code();
 }
 
-std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
+std::error_code detail::directory_iterator_increment(detail::DirIterState &IT) {
   WIN32_FIND_DATAW FindData;
-  if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
+  if (!::FindNextFileW(HANDLE(IT.IterationHandle), &FindData)) {
     DWORD LastError = ::GetLastError();
     // Check for end.
     if (LastError == ERROR_NO_MORE_FILES)
-      return detail::directory_iterator_destruct(it);
+      return detail::directory_iterator_destruct(IT);
     return mapWindowsError(LastError);
   }
 
@@ -403,16 +616,18 @@
   if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') ||
       (FilenameLen == 2 && FindData.cFileName[0] == L'.' &&
                            FindData.cFileName[1] == L'.'))
-    return directory_iterator_increment(it);
+    return directory_iterator_increment(IT);
 
-  SmallString<128> directory_entry_path_utf8;
-  if (std::error_code ec =
+  SmallString<128> DirectoryEntryPathUTF8;
+  if (std::error_code EC =
           UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName),
-                      directory_entry_path_utf8))
-    return ec;
+                      DirectoryEntryPathUTF8))
+    return EC;
 
-  it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8),
-                                   status_from_find_data(&FindData));
+  IT.CurrentEntry.replace_filename(
+      Twine(DirectoryEntryPathUTF8),
+      file_type_from_attrs(FindData.dwFileAttributes),
+      status_from_find_data(&FindData));
   return std::error_code();
 }
 
@@ -420,18 +635,82 @@
   return Status;
 }
 
-std::error_code openFileForRead(const Twine &Name, int &ResultFD,
-                                SmallVectorImpl<char> *RealPath) {
-  ResultFD = -1;
-  SmallVector<wchar_t, 128> PathUTF16;
+static std::error_code nativeFileToFd(Expected<HANDLE> H, int &ResultFD,
+                                      OpenFlags Flags) {
+  int CrtOpenFlags = 0;
+  if (Flags & OF_Append)
+    CrtOpenFlags |= _O_APPEND;
 
+  if (Flags & OF_Text)
+    CrtOpenFlags |= _O_TEXT;
+
+  ResultFD = -1;
+  if (!H)
+    return errorToErrorCode(H.takeError());
+
+  ResultFD = ::_open_osfhandle(intptr_t(*H), CrtOpenFlags);
+  if (ResultFD == -1) {
+    ::CloseHandle(*H);
+    return mapWindowsError(ERROR_INVALID_HANDLE);
+  }
+  return std::error_code();
+}
+
+static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) {
+  // This is a compatibility hack.  Really we should respect the creation
+  // disposition, but a lot of old code relied on the implicit assumption that
+  // OF_Append implied it would open an existing file.  Since the disposition is
+  // now explicit and defaults to CD_CreateAlways, this assumption would cause
+  // any usage of OF_Append to append to a new file, even if the file already
+  // existed.  A better solution might have two new creation dispositions:
+  // CD_AppendAlways and CD_AppendNew.  This would also address the problem of
+  // OF_Append being used on a read-only descriptor, which doesn't make sense.
+  if (Flags & OF_Append)
+    return OPEN_ALWAYS;
+
+  switch (Disp) {
+  case CD_CreateAlways:
+    return CREATE_ALWAYS;
+  case CD_CreateNew:
+    return CREATE_NEW;
+  case CD_OpenAlways:
+    return OPEN_ALWAYS;
+  case CD_OpenExisting:
+    return OPEN_EXISTING;
+  }
+  wpi_unreachable("unreachable!");
+}
+
+static DWORD nativeAccess(FileAccess Access, OpenFlags Flags) {
+  DWORD Result = 0;
+  if (Access & FA_Read)
+    Result |= GENERIC_READ;
+  if (Access & FA_Write)
+    Result |= GENERIC_WRITE;
+  if (Flags & OF_Delete)
+    Result |= DELETE;
+  if (Flags & OF_UpdateAtime)
+    Result |= FILE_WRITE_ATTRIBUTES;
+  return Result;
+}
+
+static std::error_code openNativeFileInternal(const Twine &Name,
+                                              file_t &ResultFile, DWORD Disp,
+                                              DWORD Access, DWORD Flags,
+                                              bool Inherit = false) {
+  SmallVector<wchar_t, 128> PathUTF16;
   if (std::error_code EC = widenPath(Name, PathUTF16))
     return EC;
 
+  SECURITY_ATTRIBUTES SA;
+  SA.nLength = sizeof(SA);
+  SA.lpSecurityDescriptor = nullptr;
+  SA.bInheritHandle = Inherit;
+
   HANDLE H =
-      ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
-                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+      ::CreateFileW(PathUTF16.begin(), Access,
+                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SA,
+                    Disp, Flags, NULL);
   if (H == INVALID_HANDLE_VALUE) {
     DWORD LastError = ::GetLastError();
     std::error_code EC = mapWindowsError(LastError);
@@ -441,98 +720,102 @@
     if (LastError != ERROR_ACCESS_DENIED)
       return EC;
     if (is_directory(Name))
-      return std::make_error_code(std::errc::is_a_directory);
+      return make_error_code(errc::is_a_directory);
     return EC;
   }
+  ResultFile = H;
+  return std::error_code();
+}
 
-  ResultFD = ::_open_osfhandle(intptr_t(H), 0);
-  if (ResultFD == -1) {
-    ::CloseHandle(H);
-    return mapWindowsError(ERROR_INVALID_HANDLE);
-  }
+Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp,
+                                FileAccess Access, OpenFlags Flags,
+                                unsigned Mode) {
+  // Verify that we don't have both "append" and "excl".
+  assert((!(Disp == CD_CreateNew) || !(Flags & OF_Append)) &&
+         "Cannot specify both 'CreateNew' and 'Append' file creation flags!");
 
-  // Fetch the real name of the file, if the user asked
-  if (RealPath) {
-    RealPath->clear();
-    wchar_t RealPathUTF16[MAX_PATH];
-    DWORD CountChars =
-      ::GetFinalPathNameByHandleW(H, RealPathUTF16, MAX_PATH,
-                                  FILE_NAME_NORMALIZED);
-    if (CountChars > 0 && CountChars < MAX_PATH) {
-      // Convert the result from UTF-16 to UTF-8.
-      SmallString<MAX_PATH> RealPathUTF8;
-      if (!UTF16ToUTF8(RealPathUTF16, CountChars, RealPathUTF8))
-        RealPath->append(RealPathUTF8.data(),
-                         RealPathUTF8.data() + strlen(RealPathUTF8.data()));
+  DWORD NativeDisp = nativeDisposition(Disp, Flags);
+  DWORD NativeAccess = nativeAccess(Access, Flags);
+
+  bool Inherit = false;
+  if (Flags & OF_ChildInherit)
+    Inherit = true;
+
+  file_t Result;
+  std::error_code EC = openNativeFileInternal(
+      Name, Result, NativeDisp, NativeAccess, FILE_ATTRIBUTE_NORMAL, Inherit);
+  if (EC)
+    return errorCodeToError(EC);
+
+  if (Flags & OF_UpdateAtime) {
+    FILETIME FileTime;
+    SYSTEMTIME SystemTime;
+    GetSystemTime(&SystemTime);
+    if (SystemTimeToFileTime(&SystemTime, &FileTime) == 0 ||
+        SetFileTime(Result, NULL, &FileTime, NULL) == 0) {
+      DWORD LastError = ::GetLastError();
+      ::CloseHandle(Result);
+      return errorCodeToError(mapWindowsError(LastError));
     }
   }
 
-  return std::error_code();
+  if (Flags & OF_Delete) {
+    if ((EC = setDeleteDisposition(Result, true))) {
+      ::CloseHandle(Result);
+      return errorCodeToError(EC);
+    }
+  }
+  return Result;
 }
 
-std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
-                                 OpenFlags Flags, unsigned Mode) {
-  // Verify that we don't have both "append" and "excl".
-  assert((!(Flags & F_Excl) || !(Flags & F_Append)) &&
-         "Cannot specify both 'excl' and 'append' file creation flags!");
+std::error_code openFile(const Twine &Name, int &ResultFD,
+                         CreationDisposition Disp, FileAccess Access,
+                         OpenFlags Flags, unsigned int Mode) {
+  Expected<file_t> Result = openNativeFile(Name, Disp, Access, Flags);
+  if (!Result)
+    return errorToErrorCode(Result.takeError());
 
-  ResultFD = -1;
-  SmallVector<wchar_t, 128> PathUTF16;
-
-  if (std::error_code EC = widenPath(Name, PathUTF16))
-    return EC;
-
-  DWORD CreationDisposition;
-  if (Flags & F_Excl)
-    CreationDisposition = CREATE_NEW;
-  else if ((Flags & F_Append) || (Flags & F_NoTrunc))
-    CreationDisposition = OPEN_ALWAYS;
-  else
-    CreationDisposition = CREATE_ALWAYS;
-
-  DWORD Access = GENERIC_WRITE;
-  DWORD Attributes = FILE_ATTRIBUTE_NORMAL;
-  if (Flags & F_RW)
-    Access |= GENERIC_READ;
-  if (Flags & F_Delete) {
-    Access |= DELETE;
-    Attributes |= FILE_FLAG_DELETE_ON_CLOSE;
-  }
-
-  HANDLE H =
-      ::CreateFileW(PathUTF16.data(), Access,
-                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                    NULL, CreationDisposition, Attributes, NULL);
-
-  if (H == INVALID_HANDLE_VALUE) {
-    DWORD LastError = ::GetLastError();
-    std::error_code EC = mapWindowsError(LastError);
-    // Provide a better error message when trying to open directories.
-    // This only runs if we failed to open the file, so there is probably
-    // no performances issues.
-    if (LastError != ERROR_ACCESS_DENIED)
-      return EC;
-    if (is_directory(Name))
-      return std::make_error_code(std::errc::is_a_directory);
-    return EC;
-  }
-
-  int OpenFlags = 0;
-  if (Flags & F_Append)
-    OpenFlags |= _O_APPEND;
-
-  if (Flags & F_Text)
-    OpenFlags |= _O_TEXT;
-
-  ResultFD = ::_open_osfhandle(intptr_t(H), OpenFlags);
-  if (ResultFD == -1) {
-    ::CloseHandle(H);
-    return mapWindowsError(ERROR_INVALID_HANDLE);
-  }
-
-  return std::error_code();
+  return nativeFileToFd(*Result, ResultFD, Flags);
 }
 
+static std::error_code directoryRealPath(const Twine &Name,
+                                         SmallVectorImpl<char> &RealPath) {
+  file_t File;
+  std::error_code EC = openNativeFileInternal(
+      Name, File, OPEN_EXISTING, GENERIC_READ, FILE_FLAG_BACKUP_SEMANTICS);
+  if (EC)
+    return EC;
+
+  EC = realPathFromHandle(File, RealPath);
+  ::CloseHandle(File);
+  return EC;
+}
+
+std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+                                OpenFlags Flags,
+                                SmallVectorImpl<char> *RealPath) {
+  Expected<HANDLE> NativeFile = openNativeFileForRead(Name, Flags, RealPath);
+  return nativeFileToFd(std::move(NativeFile), ResultFD, OF_None);
+}
+
+Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags,
+                                       SmallVectorImpl<char> *RealPath) {
+  Expected<file_t> Result =
+      openNativeFile(Name, CD_OpenExisting, FA_Read, Flags);
+
+  // Fetch the real name of the file, if the user asked
+  if (Result && RealPath)
+    realPathFromHandle(*Result, *RealPath);
+
+  return Result;
+}
+
+void closeFile(file_t &F) {
+  ::CloseHandle(F);
+  F = kInvalidFile;
+}
+
+
 } // end namespace fs
 
 namespace path {
@@ -547,10 +830,6 @@
   return ok;
 }
 
-bool getUserCacheDir(SmallVectorImpl<char> &Result) {
-  return getKnownFolderPath(FOLDERID_LocalAppData, Result);
-}
-
 bool home_directory(SmallVectorImpl<char> &result) {
   return getKnownFolderPath(FOLDERID_Profile, result);
 }
@@ -686,3 +965,7 @@
 } // end namespace windows
 } // end namespace sys
 } // end namespace wpi
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
diff --git a/wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h b/wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h
index 2f78a4e..d830e33 100644
--- a/wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h
+++ b/wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h
@@ -38,11 +38,40 @@
 #include "wpi/StringExtras.h"
 #include "wpi/StringRef.h"
 #include "wpi/Twine.h"
+#include "wpi/Chrono.h"
 #include "wpi/Compiler.h"
+#include "wpi/VersionTuple.h"
 #include <cassert>
 #include <string>
 #include <system_error>
+#define WIN32_NO_STATUS
 #include <windows.h>
+#undef WIN32_NO_STATUS
+#include <winternl.h>
+#include <ntstatus.h>
+
+namespace wpi {
+
+/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
+/// RtlGetVersion or GetVersionEx under the hood depending on what is available.
+/// GetVersionEx is deprecated, but this API exposes the build number which can
+/// be useful for working around certain kernel bugs.
+inline wpi::VersionTuple GetWindowsOSVersion() {
+  typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
+  HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
+  if (hMod) {
+    auto getVer = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
+    if (getVer) {
+      RTL_OSVERSIONINFOEXW info{};
+      info.dwOSVersionInfoSize = sizeof(info);
+      if (getVer((PRTL_OSVERSIONINFOW)&info) == ((NTSTATUS)0x00000000L)) {
+        return wpi::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0,
+                                  info.dwBuildNumber);
+      }
+    }
+  }
+  return wpi::VersionTuple(0, 0, 0, 0);
+}
 
 /// Determines if the program is running on Windows 8 or newer. This
 /// reimplements one of the helpers in the Windows 8.1 SDK, which are intended
@@ -50,20 +79,7 @@
 /// yet have VersionHelpers.h, so we have our own helper.
 inline bool RunningWindows8OrGreater() {
   // Windows 8 is version 6.2, service pack 0.
-  OSVERSIONINFOEXW osvi = {};
-  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-  osvi.dwMajorVersion = 6;
-  osvi.dwMinorVersion = 2;
-  osvi.wServicePackMajor = 0;
-
-  DWORDLONG Mask = 0;
-  Mask = VerSetConditionMask(Mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
-  Mask = VerSetConditionMask(Mask, VER_MINORVERSION, VER_GREATER_EQUAL);
-  Mask = VerSetConditionMask(Mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
-
-  return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION |
-                                       VER_SERVICEPACKMAJOR,
-                            Mask) != FALSE;
+  return GetWindowsOSVersion() >= wpi::VersionTuple(6, 2, 0, 0);
 }
 
 inline bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) {
@@ -90,8 +106,8 @@
   typedef typename HandleTraits::handle_type handle_type;
   handle_type Handle;
 
-  ScopedHandle(const ScopedHandle &other); // = delete;
-  void operator=(const ScopedHandle &other); // = delete;
+  ScopedHandle(const ScopedHandle &other) = delete;
+  void operator=(const ScopedHandle &other) = delete;
 public:
   ScopedHandle()
     : Handle(HandleTraits::GetInvalid()) {}
@@ -179,7 +195,6 @@
 typedef ScopedHandle<FindHandleTraits>   ScopedFindHandle;
 typedef ScopedHandle<JobHandleTraits>    ScopedJobHandle;
 
-namespace wpi {
 template <class T>
 class SmallVectorImpl;
 
@@ -192,21 +207,39 @@
 }
 
 namespace sys {
-namespace path {
-std::error_code widenPath(const Twine &Path8,
-                          SmallVectorImpl<wchar_t> &Path16);
-} // end namespace path
 
-namespace windows {
-std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
-/// Convert to UTF16 from the current code page used in the system
-std::error_code CurCPToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
-std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
-                            SmallVectorImpl<char> &utf8);
-/// Convert from UTF16 to the current code page used in the system
-std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
-                             SmallVectorImpl<char> &utf8);
-} // end namespace windows
+inline std::chrono::nanoseconds toDuration(FILETIME Time) {
+  ULARGE_INTEGER TimeInteger;
+  TimeInteger.LowPart = Time.dwLowDateTime;
+  TimeInteger.HighPart = Time.dwHighDateTime;
+
+  // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
+  return std::chrono::nanoseconds(100 * TimeInteger.QuadPart);
+}
+
+inline TimePoint<> toTimePoint(FILETIME Time) {
+  ULARGE_INTEGER TimeInteger;
+  TimeInteger.LowPart = Time.dwLowDateTime;
+  TimeInteger.HighPart = Time.dwHighDateTime;
+
+  // Adjust for different epoch
+  TimeInteger.QuadPart -= 11644473600ll * 10000000;
+
+  // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
+  return TimePoint<>(std::chrono::nanoseconds(100 * TimeInteger.QuadPart));
+}
+
+inline FILETIME toFILETIME(TimePoint<> TP) {
+  ULARGE_INTEGER TimeInteger;
+  TimeInteger.QuadPart = TP.time_since_epoch().count() / 100;
+  TimeInteger.QuadPart += 11644473600ll * 10000000;
+
+  FILETIME Time;
+  Time.dwLowDateTime = TimeInteger.LowPart;
+  Time.dwHighDateTime = TimeInteger.HighPart;
+  return Time;
+}
+
 } // end namespace sys
 } // end namespace wpi.
 
diff --git a/wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp b/wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp
index 04bae65..9f2942c 100644
--- a/wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp
@@ -11,12 +11,17 @@
 //
 //===----------------------------------------------------------------------===//
 
+#ifdef _WIN32
+#define _CRT_NONSTDC_NO_WARNINGS
+#endif
+
 #include "wpi/raw_ostream.h"
 #include "wpi/STLExtras.h"
 #include "wpi/SmallString.h"
 #include "wpi/SmallVector.h"
 #include "wpi/StringExtras.h"
 #include "wpi/Compiler.h"
+#include "wpi/ErrorHandling.h"
 #include "wpi/FileSystem.h"
 #include "wpi/Format.h"
 #include "wpi/MathExtras.h"
@@ -56,6 +61,7 @@
 #endif
 
 #ifdef _WIN32
+#include "wpi/ConvertUTF.h"
 #include "Windows/WindowsSupport.h"
 #endif
 
@@ -149,7 +155,7 @@
       *this << '\\' << '"';
       break;
     default:
-      if (std::isprint(c)) {
+      if (isPrint(c)) {
         *this << c;
         break;
       }
@@ -335,7 +341,7 @@
     break;
   }
   default:
-    assert(false && "Bad Justification");
+    wpi_unreachable("Bad Justification");
   }
   return *this;
 }
@@ -419,7 +425,7 @@
 
       // Print the ASCII char values for each byte on this line
       for (uint8_t Byte : Line) {
-        if (isprint(Byte))
+        if (isPrint(Byte))
           *this << static_cast<char>(Byte);
         else
           *this << '.';
@@ -481,14 +487,18 @@
 //===----------------------------------------------------------------------===//
 
 static int getFD(StringRef Filename, std::error_code &EC,
+                 sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access,
                  sys::fs::OpenFlags Flags) {
+  assert((Access & sys::fs::FA_Write) &&
+         "Cannot make a raw_ostream from a read-only descriptor!");
+
   // Handle "-" as stdout. Note that when we do this, we consider ourself
   // the owner of stdout and may set the "binary" flag globally based on Flags.
   if (Filename == "-") {
     EC = std::error_code();
     // If user requested binary then put stdout into binary mode if
     // possible.
-    if (!(Flags & sys::fs::F_Text)) {
+    if (!(Flags & sys::fs::OF_Text)) {
 #if defined(_WIN32)
       _setmode(_fileno(stdout), _O_BINARY);
 #endif
@@ -497,16 +507,39 @@
   }
 
   int FD;
-  EC = sys::fs::openFileForWrite(Filename, FD, Flags);
+  if (Access & sys::fs::FA_Read)
+    EC = sys::fs::openFileForReadWrite(Filename, FD, Disp, Flags);
+  else
+    EC = sys::fs::openFileForWrite(Filename, FD, Disp, Flags);
   if (EC)
     return -1;
 
   return FD;
 }
 
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC)
+    : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write,
+                     sys::fs::OF_None) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                               sys::fs::CreationDisposition Disp)
+    : raw_fd_ostream(Filename, EC, Disp, sys::fs::FA_Write, sys::fs::OF_None) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                               sys::fs::FileAccess Access)
+    : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, Access,
+                     sys::fs::OF_None) {}
+
 raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
                                sys::fs::OpenFlags Flags)
-    : raw_fd_ostream(getFD(Filename, EC, Flags), true) {}
+    : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write,
+                     Flags) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                               sys::fs::CreationDisposition Disp,
+                               sys::fs::FileAccess Access,
+                               sys::fs::OpenFlags Flags)
+    : raw_fd_ostream(getFD(Filename, EC, Disp, Access, Flags), true) {}
 
 /// FD is the file descriptor that this writes to.  If ShouldClose is true, this
 /// closes the file when the stream is destroyed.
@@ -526,6 +559,12 @@
   if (FD <= STDERR_FILENO)
     ShouldClose = false;
 
+#ifdef _WIN32
+  // Check if this is a console device. This is not equivalent to isatty.
+  IsWindowsConsole =
+      ::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
+#endif
+
   // Get the starting position.
   off_t loc = ::lseek(FD, 0, SEEK_CUR);
 #ifdef _WIN32
@@ -554,27 +593,87 @@
   // on FD == 2.
   if (FD == 2) return;
 #endif
+
+  // If there are any pending errors, report them now. Clients wishing
+  // to avoid report_fatal_error calls should check for errors with
+  // has_error() and clear the error flag with clear_error() before
+  // destructing raw_ostream objects which may have errors.
+  if (has_error())
+    report_fatal_error("IO failure on output stream: " + error().message(),
+                       /*GenCrashDiag=*/false);
 }
 
+#if defined(_WIN32)
+// The most reliable way to print unicode in a Windows console is with
+// WriteConsoleW. To use that, first transcode from UTF-8 to UTF-16. This
+// assumes that LLVM programs always print valid UTF-8 to the console. The data
+// might not be UTF-8 for two major reasons:
+// 1. The program is printing binary (-filetype=obj -o -), in which case it
+// would have been gibberish anyway.
+// 2. The program is printing text in a semi-ascii compatible codepage like
+// shift-jis or cp1252.
+//
+// Most LLVM programs don't produce non-ascii text unless they are quoting
+// user source input. A well-behaved LLVM program should either validate that
+// the input is UTF-8 or transcode from the local codepage to UTF-8 before
+// quoting it. If they don't, this may mess up the encoding, but this is still
+// probably the best compromise we can make.
+static bool write_console_impl(int FD, StringRef Data) {
+  SmallVector<wchar_t, 256> WideText;
+
+  // Fall back to ::write if it wasn't valid UTF-8.
+  if (auto EC = sys::windows::UTF8ToUTF16(Data, WideText))
+    return false;
+
+  // On Windows 7 and earlier, WriteConsoleW has a low maximum amount of data
+  // that can be written to the console at a time.
+  size_t MaxWriteSize = WideText.size();
+  if (!RunningWindows8OrGreater())
+    MaxWriteSize = 32767;
+
+  size_t WCharsWritten = 0;
+  do {
+    size_t WCharsToWrite =
+        std::min(MaxWriteSize, WideText.size() - WCharsWritten);
+    DWORD ActuallyWritten;
+    bool Success =
+        ::WriteConsoleW((HANDLE)::_get_osfhandle(FD), &WideText[WCharsWritten],
+                        WCharsToWrite, &ActuallyWritten,
+                        /*Reserved=*/nullptr);
+
+    // The most likely reason for WriteConsoleW to fail is that FD no longer
+    // points to a console. Fall back to ::write. If this isn't the first loop
+    // iteration, something is truly wrong.
+    if (!Success)
+      return false;
+
+    WCharsWritten += ActuallyWritten;
+  } while (WCharsWritten != WideText.size());
+  return true;
+}
+#endif
+
 void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
   assert(FD >= 0 && "File already closed.");
   pos += Size;
 
-  // The maximum write size is limited to SSIZE_MAX because a write
-  // greater than SSIZE_MAX is implementation-defined in POSIX.
-  // Since SSIZE_MAX is not portable, we use SIZE_MAX >> 1 instead.
-  size_t MaxWriteSize = SIZE_MAX >> 1;
+#if defined(_WIN32)
+  // If this is a Windows console device, try re-encoding from UTF-8 to UTF-16
+  // and using WriteConsoleW. If that fails, fall back to plain write().
+  if (IsWindowsConsole)
+    if (write_console_impl(FD, StringRef(Ptr, Size)))
+      return;
+#endif
+
+  // The maximum write size is limited to INT32_MAX. A write
+  // greater than SSIZE_MAX is implementation-defined in POSIX,
+  // and Windows _write requires 32 bit input.
+  size_t MaxWriteSize = INT32_MAX;
 
 #if defined(__linux__)
   // It is observed that Linux returns EINVAL for a very large write (>2G).
   // Make it a reasonably small value.
   MaxWriteSize = 1024 * 1024 * 1024;
-#elif defined(_WIN32)
-  // Writing a large size of output to Windows console returns ENOMEM. It seems
-  // that, prior to Windows 8, WriteFile() is redirecting to WriteConsole(), and
-  // the latter has a size limit (66000 bytes or less, depending on heap usage).
-  if (::_isatty(FD) && !RunningWindows8OrGreater())
-    MaxWriteSize = 32767;
 #endif
 
   do {
@@ -645,8 +744,17 @@
 }
 
 size_t raw_fd_ostream::preferred_buffer_size() const {
-#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__minix)
-  // Windows and Minix have no st_blksize.
+#if defined(_WIN32)
+  // Disable buffering for console devices. Console output is re-encoded from
+  // UTF-8 to UTF-16 on Windows, and buffering it would require us to split the
+  // buffer on a valid UTF-8 codepoint boundary. Terminal buffering is disabled
+  // below on most other OSs, so do the same thing on Windows and avoid that
+  // complexity.
+  if (IsWindowsConsole)
+    return 0;
+  return raw_ostream::preferred_buffer_size();
+#elif !defined(__minix)
+  // Minix has no st_blksize.
   assert(FD >= 0 && "File not yet open!");
   struct stat statbuf;
   if (fstat(FD, &statbuf) != 0)
@@ -791,3 +899,5 @@
                                    uint64_t /*Offset*/) {}
 
 void raw_pwrite_stream::anchor() {}
+
+void buffer_ostream::anchor() {}
diff --git a/wpiutil/src/main/native/cpp/memory.cpp b/wpiutil/src/main/native/cpp/memory.cpp
deleted file mode 100644
index 54e55c9..0000000
--- a/wpiutil/src/main/native/cpp/memory.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "wpi/memory.h"
-
-#include <exception>
-
-#include "wpi/raw_ostream.h"
-
-namespace wpi {
-
-void* CheckedCalloc(size_t num, size_t size) {
-  void* p = std::calloc(num, size);
-  if (!p) {
-    errs() << "FATAL: failed to allocate " << (num * size) << " bytes\n";
-    std::terminate();
-  }
-  return p;
-}
-
-void* CheckedMalloc(size_t size) {
-  void* p = std::malloc(size == 0 ? 1 : size);
-  if (!p) {
-    errs() << "FATAL: failed to allocate " << size << " bytes\n";
-    std::terminate();
-  }
-  return p;
-}
-
-void* CheckedRealloc(void* ptr, size_t size) {
-  void* p = std::realloc(ptr, size == 0 ? 1 : size);
-  if (!p) {
-    errs() << "FATAL: failed to allocate " << size << " bytes\n";
-    std::terminate();
-  }
-  return p;
-}
-
-}  // namespace wpi
diff --git a/wpiutil/src/main/native/cpp/raw_istream.cpp b/wpiutil/src/main/native/cpp/raw_istream.cpp
index bdfb2bb..f63c217 100644
--- a/wpiutil/src/main/native/cpp/raw_istream.cpp
+++ b/wpiutil/src/main/native/cpp/raw_istream.cpp
@@ -1,10 +1,12 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2018 FIRST. All Rights Reserved.                        */
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
 /*----------------------------------------------------------------------------*/
 
+#define _CRT_NONSTDC_NO_WARNINGS
+
 #include "wpi/raw_istream.h"
 
 #ifdef _WIN32
diff --git a/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp b/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp
index 317de41..8fc103d 100644
--- a/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp
+++ b/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -23,7 +23,7 @@
       assert(m_left != 0);
     }
 
-    size_t amt = std::min(m_left, len);
+    size_t amt = (std::min)(m_left, len);
     auto& buf = m_bufs.back();
     std::memcpy(buf.base + buf.len, data, amt);
     data += amt;
diff --git a/wpiutil/src/main/native/cpp/uv/Pipe.cpp b/wpiutil/src/main/native/cpp/uv/Pipe.cpp
index 8d4ee76..9db879a 100644
--- a/wpiutil/src/main/native/cpp/uv/Pipe.cpp
+++ b/wpiutil/src/main/native/cpp/uv/Pipe.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
diff --git a/wpiutil/src/main/native/cpp/uv/Timer.cpp b/wpiutil/src/main/native/cpp/uv/Timer.cpp
index 4825ea3..749d9a8 100644
--- a/wpiutil/src/main/native/cpp/uv/Timer.cpp
+++ b/wpiutil/src/main/native/cpp/uv/Timer.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -26,7 +26,7 @@
 void Timer::SingleShot(Loop& loop, Time timeout, std::function<void()> func) {
   auto h = Create(loop);
   if (!h) return;
-  h->timeout.connect([ theTimer = h.get(), func ]() {
+  h->timeout.connect([theTimer = h.get(), func]() {
     func();
     theTimer->Close();
   });
diff --git a/wpiutil/src/main/native/cpp/uv/Udp.cpp b/wpiutil/src/main/native/cpp/uv/Udp.cpp
index cc7208d..2c0d29f 100644
--- a/wpiutil/src/main/native/cpp/uv/Udp.cpp
+++ b/wpiutil/src/main/native/cpp/uv/Udp.cpp
@@ -1,5 +1,5 @@
 /*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
 /* Open Source Software - may be modified and shared by FRC teams. The code   */
 /* must be accompanied by the FIRST BSD license file in the root directory of */
 /* the project.                                                               */
@@ -69,6 +69,33 @@
     Bind(reinterpret_cast<const sockaddr&>(addr), flags);
 }
 
+void Udp::Connect(const Twine& ip, unsigned int port) {
+  sockaddr_in addr;
+  int err = NameToAddr(ip, port, &addr);
+  if (err < 0)
+    ReportError(err);
+  else
+    Connect(reinterpret_cast<const sockaddr&>(addr));
+}
+
+void Udp::Connect6(const Twine& ip, unsigned int port) {
+  sockaddr_in6 addr;
+  int err = NameToAddr(ip, port, &addr);
+  if (err < 0)
+    ReportError(err);
+  else
+    Connect(reinterpret_cast<const sockaddr&>(addr));
+}
+
+sockaddr_storage Udp::GetPeer() {
+  sockaddr_storage name;
+  int len = sizeof(name);
+  if (!Invoke(&uv_udp_getpeername, GetRaw(), reinterpret_cast<sockaddr*>(&name),
+              &len))
+    std::memset(&name, 0, sizeof(name));
+  return name;
+}
+
 sockaddr_storage Udp::GetSock() {
   sockaddr_storage name;
   int len = sizeof(name);
@@ -111,6 +138,22 @@
   Send(addr, bufs, std::make_shared<CallbackUdpSendReq>(bufs, callback));
 }
 
+void Udp::Send(ArrayRef<Buffer> bufs, const std::shared_ptr<UdpSendReq>& req) {
+  if (Invoke(&uv_udp_send, req->GetRaw(), GetRaw(), bufs.data(), bufs.size(),
+             nullptr, [](uv_udp_send_t* r, int status) {
+               auto& h = *static_cast<UdpSendReq*>(r->data);
+               if (status < 0) h.ReportError(status);
+               h.complete(Error(status));
+               h.Release();  // this is always a one-shot
+             }))
+    req->Keep();
+}
+
+void Udp::Send(ArrayRef<Buffer> bufs,
+               std::function<void(MutableArrayRef<Buffer>, Error)> callback) {
+  Send(bufs, std::make_shared<CallbackUdpSendReq>(bufs, callback));
+}
+
 void Udp::StartRecv() {
   Invoke(&uv_udp_recv_start, GetRaw(), &AllocBuf,
          [](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf,