Categories: Compilers, LLVM

Building LLVM for Windows ARM64

I was trying to test using LLVM as a backend for hsdis on the Windows ARM64 platform as implemented in PR 5920. I downloaded LLVM 13 and tried to use it in the build. Unfortunately, it didn’t have all the prerequisite include files and so building your own LLVM installation was the approach suggested for Windows. This post explicitly outlines the instructions needed to build LLVM for the Windows ARM64 platform on a Windows x64 host machine.

The first requirement is an LLVM build with native llvm-nm.exe and llvm-tblgen.exe binaries. These can be downloaded (I think) or generated by building LLVM for the native x64 platform as specified in the instructions from Jorn.

git clone https://github.com/llvm/llvm-project.git
cd llvm-project
mkdir build_llvm
cd build_llvm
cmake ../llvm -D"LLVM_TARGETS_TO_BUILD:STRING=X86" -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_INSTALL_PREFIX=install_local" -A x64 -T host=x64
cmake --build . --config Release --target install

Once that build successfully completes, we can then build LLVM for the Windows ARM64 platform with the commands below. Notice that we specify paths to the native llvm-nm and llvm-tblgen binaries to prevent the build from trying to use their ARM64 equivalents (which won’t run on the host).

cd llvm-project
mkdir build_llvm_AArch64
cd build_llvm_Aarch64

cmake ../llvm -DLLVM_TARGETS_TO_BUILD:STRING=AArch64 \
 -DCMAKE_BUILD_TYPE:STRING=Release \
 -DCMAKE_INSTALL_PREFIX=install_local \
 -DCMAKE_CROSSCOMPILING=True \
 -DLLVM_TARGET_ARCH=AArch64 \
 -DLLVM_NM=C:/repos/llvm-project/build_llvm/install_local/bin/llvm-nm.exe \
 -DLLVM_TABLEGEN=C:/repos/llvm-project/build_llvm/install_local/bin/llvm-tblgen.exe \
 -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-win32-msvc \
 -A ARM64 \
 -T host=x64

date; time \
 cmake --build . --config Release --target install ; \
 date

Once the build completes, the LLVM ARM64 files will be in the build_llvm_AArch64/install_local folder in the llvm-project repo. That build should have all the necessary header files and static libraries required for LLVM projects targeting Windows on ARM64. See the general cmake options and the LLVM-specific cmake options for details on the various flags and variables.

Behind the Scenes: Cross-Compiling LLVM

I naively started out by adding AArch64 to the list of LLVM_TARGETS_TO_BUILD, then using only AArch64 in the list. Trying to use the generated build would still fail with errors about mismatched platforms so I knew some cross compilation specific flags would be needed. How do I cross-compile LLVM/Clang for AArch64 on x64 host? – Stack Overflow and How To Cross-Compile Clang/LLVM using Clang/LLVM — LLVM 15.0.0git documentation were handy references. They didn’t have anything windows specific but got me walking down the right path (e.g. the importance of the native LLVM_TABLEGEN). I tried something along these lines:

cd llvm-project
mkdir build_llvm_AArch64
cd build_llvm_AArch64

cmake ../llvm -D"LLVM_TARGETS_TO_BUILD:STRING=AArch64" \
 -D"CMAKE_BUILD_TYPE:STRING=Release" \
 -D"CMAKE_INSTALL_PREFIX=install_local_AArch64" \
 -D"CMAKE_CROSSCOMPILING=True" \
 -D"LLVM_TARGET_ARCH=AArch64" \
 -A x64 \
 -T host=x64

cmake --build . --config Release --target install

This still results in errors about conflicting machine types:

c:\...\llvm-project\build_llvm_aarch64\install_local_aarch64\\lib\llvmaarch64disassembler.lib : warning LNK4272: library machine type 'x64' conflicts with target machine type 'ARM64'

That’s when I tried adding the LLVM_TABLE_GEN from a Windows x64 LLVM build I had generated earlier. I accidentally omitted the options prefixed with a # below because I didn’t include the trailing slash after adding the llvm-tblgen.exe option.

cmake ../llvm -D"LLVM_TARGETS_TO_BUILD:STRING=AArch64" \
 -D"CMAKE_BUILD_TYPE:STRING=Release" \
 -D"CMAKE_INSTALL_PREFIX=install_local_AArch64_2" \
 -D"CMAKE_CROSSCOMPILING=True" \
 -D"LLVM_TARGET_ARCH=AArch64" \
 -D"LLVM_TABLEGEN=C:\dev\repos\llvm-project\build_llvm\install_local\bin\llvm-tblgen.exe" \
 #-D"LLVM_DEFAULT_TARGET_TRIPLE=aarch64-win32-msvc" \
 #-A x64 \
 #-T host=x64

date; time \
 cmake --build . --config Release --target install; \
 date

The build still succeeded and generated AArch64 .lib files in the LLVM installation! Interestingly, they still had the x64 machine type in the header.

$ dumpbin /headers build_llvm_AArch64_2\install_local_AArch64_2\lib\LLVMAArch64AsmParser.lib
Microsoft (R) COFF/PE Dumper Version 14.29.30133.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file build_llvm_AArch64_2\install_local_AArch64_2\lib\LLVMAArch64AsmParser.lib

File Type: LIBRARY

FILE HEADER VALUES
            8664 machine (x64)
...

I had no choice but to reexamine my understanding of what the -A flag does. It is used to specify the platform name but it’s only after digging into the CMAKE_GENERATOR_PLATFORM docs that I noticed that this was the target platform! This also made me realize that I hadn’t noticed that the x64 C++ compiler was being used all along!

-- The C compiler identification is MSVC 19.29.30133.0
-- The CXX compiler identification is MSVC 19.29.30133.0
-- The ASM compiler identification is MSVC
-- Found assembler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - works

Some references to LLVM triples led back to the clang cross-compilation docs and the llvm::Triple source code so I tried again with the triple set and with -A now set to AArch64.

cmake ../llvm -D"LLVM_TARGETS_TO_BUILD:STRING=AArch64" \
 -D"CMAKE_BUILD_TYPE:STRING=Release" \
 -D"CMAKE_INSTALL_PREFIX=install_local_AArch64_3" \
 -D"CMAKE_CROSSCOMPILING=True" \
 -D"LLVM_TARGET_ARCH=AArch64" \
 -D"LLVM_TABLEGEN=C:\dev\repos\llvm-project\build_llvm\install_local\bin\llvm-tblgen.exe" \
 -D"LLVM_DEFAULT_TARGET_TRIPLE=aarch64-win32-msvc" \
 -A AArch64 \
 -T host=x64

Setting -A to AArch64 causes MSBuild to fail with an error about an unknown platform. So -A just might be the argument I need to get ARM64 libraries built.

"C:\dev\repos\llvm-project\build_llvm_AArch64_3\CMakeFiles\3.17.3\VCTargetsPath.vcxproj" (default target) (1) ->
    (_CheckForInvalidConfigurationAndPlatform target) ->
      C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(820,5): error : The BaseOutputPath/OutputPath property is not set for project 'VCTargetsPath.vcxproj'.  Please check to make sure that you have specified a valid combination of Configuration and Platform for this project.  Configuration='Debug'  Platform='AArch64'.  You may be seeing this message because you are trying to build a project without a solution file, and have specified a non-default Configuration or Platform that doesn't exist for this project. [C:\dev\repos\llvm-project\build_llvm_AArch64_3\CMakeFiles\3.17.3\VCTargetsPath.vcxproj]

So I tried using -A ARM64 instead. I noticed that we now have the ARM64 C++ compiler selected! This is something I should have been paying attention to from the beginning, crucial for cross-compilation.

-- The C compiler identification is MSVC 19.29.30133.0
-- The CXX compiler identification is MSVC 19.29.30133.0
-- The ASM compiler identification is MSVC
-- Found assembler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/arm64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/arm64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/arm64/cl.exe - works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/arm64/cl.exe
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/arm64/cl.exe - works

Unfortunately, the build still failed with an error from gen-msvc-exports.py. Taking a look at gen-msvc-exports.py, it looks like it is trying to run llvm-nm.exe (for the target platform).

  Generating export list for LLVM-C
  Traceback (most recent call last):
    File "C:/dev/repos/llvm-project/llvm/tools/llvm-shlib/gen-msvc-exports.py", line 116, in <module>
      main()
    File "C:/dev/repos/llvm-project/llvm/tools/llvm-shlib/gen-msvc-exports.py", line 112, in main
      gen_llvm_c_export(ns.output, ns.underscore, libs, ns.nm)
    File "C:/dev/repos/llvm-project/llvm/tools/llvm-shlib/gen-msvc-exports.py", line 72, in gen_llvm_c_export
      check_call([nm, '-g', lib], stdout=dumpout_f)
    File "C:\dev\tools\Anaconda3\lib\subprocess.py", line 359, in check_call
      retcode = call(*popenargs, **kwargs)
    File "C:\dev\tools\Anaconda3\lib\subprocess.py", line 340, in call
      with Popen(*popenargs, **kwargs) as p:
    File "C:\dev\tools\Anaconda3\lib\subprocess.py", line 854, in __init__
      self._execute_child(args, executable, preexec_fn, close_fds,
    File "C:\dev\tools\Anaconda3\lib\subprocess.py", line 1307, in _execute_child
      hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
  OSError: [WinError 216] This version of %1 is not compatible with the version of Windows you're running. Check your computer's system information and then contact the software publisher
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(241,5): error MSB8066: Custom build for 'C:\dev\repos\llvm-project\build_llvm_AArch64_3\CMakeFi
les\02a88fa656bb9cf8b9ffd0e0debe57ae\libllvm-c.exports.rule;C:\dev\repos\llvm-project\build_llvm_AArch64_3\CMakeFiles\8ebc0efbf04134b25d0f37561fba0d55\LLVM-C.def.rule;C:\dev\repos\llvm-project\build_llvm_AArch64_
3\CMakeFiles\509fcb3f8bb132e9c560e15e8d25cb45\LLVM-C_exports.rule;C:\dev\repos\llvm-project\llvm\tools\llvm-shlib\CMakeLists.txt' exited with code 1. [C:\dev\repos\llvm-project\build_llvm_AArch64_3\tools\llvm-shl
ib\LLVM-C_exports.vcxproj]

A quick search for the general message (Generating export list for LLVM-C) reveals that it is from llvm-shlib/CMakeLists.txt. Looks like we just need to set LLVM_NM as per llvm-shlib/CMakeLists.txt.

date; time cmake ../llvm -D"LLVM_TARGETS_TO_BUILD:STRING=AArch64" \
 -D"CMAKE_BUILD_TYPE:STRING=Release" \
 -D"CMAKE_INSTALL_PREFIX=install_local" \
 -D"CMAKE_CROSSCOMPILING=True" \
 -D"LLVM_TARGET_ARCH=AArch64" \
 -D"LLVM_NM=C:\dev\repos\llvm-project\build_llvm\install_local\bin\llvm-nm.exe" \
 -D"LLVM_TABLEGEN=C:\dev\repos\llvm-project\build_llvm\install_local\bin\llvm-tblgen.exe" \
 -D"LLVM_DEFAULT_TARGET_TRIPLE=aarch64-win32-msvc" \
 -A ARM64 \
 -T host=x64

date; time \
 cmake --build . --config Release --target install; \
 date

These build commands work! Dumpbin shows that the generated .lib files have ARM64 headers!

$ dumpbin /headers C:\dev\repos\llvm-project\build_llvm_AArch64_3\Release\lib\LLVMAArch64Disassembler.lib
Microsoft (R) COFF/PE Dumper Version 14.29.30133.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file C:\dev\repos\llvm-project\build_llvm_AArch64_3\Release\lib\LLVMAArch64Disassembler.lib

File Type: LIBRARY

FILE HEADER VALUES
            AA64 machine (ARM64)

Unfortunately, the JDK project that got me started down this path still doesn’t build. Cygwin shows defines like -DLLVM_DEFAULT_TRIPLET='”aarch64-pc-windows-msvc”‘ being passed to the compiler, which then complains:

C:/.../src/utils/hsdis/llvm/hsdis-llvm.cpp(217): error C2015: too many characters in constant

The quotes in the commands therefore needed to be dropped. This caused build failures since the paths used back-slashes!

Building Opts.inc...
  'C:devreposllvm-projectbuild_llvminstall_localbinllvm-tblgen.exe' is not recognized as an internal or external command,
  operable program or batch file

This is now the part where I find a nice document on the LLVM site with the 3-liner for this task đŸ˜€


Categories: Assembly, Compilers

Fixing Hsdis Compile Failure in GNU binutils

The previous post on Building HSDIS in Cygwin required running this command to actually build the hsdis DLL.

make OS=Linux MINGW=x86_64-w64-mingw32 BINUTILS=~/binutils-2.37

As it turns out, this make command fails because of a bug in the GNU binutils source code. This is the error I got:

...
x86_64-w64-mingw32-gcc -c -DHAVE_CONFIG_H -O    -I. -I/home/User/binutils-2.37/libiberty/../include  -W -Wall -Wwrite-strings -Wc++-compat -Wstrict-prototypes -Wshadow=local -pedantic  -D_GNU_SOURCE  /home/User/binutils-2.37/libiberty/rust-demangle.c -o rust-demangle.o
/home/User/binutils-2.37/libiberty/rust-demangle.c:78:3: error: unknown type name ‘uint’
   78 |   uint recursion;
      |   ^~~~
/home/User/binutils-2.37/libiberty/rust-demangle.c: In function ‘demangle_path’:
/home/User/binutils-2.37/libiberty/rust-demangle.c:81:37: error: ‘uint’ undeclared (first use in this function); did you mean ‘int’?
   81 | #define RUST_NO_RECURSION_LIMIT   ((uint) -1)
      |                                     ^~~~
...
make[2]: *** [Makefile:1230: rust-demangle.o] Error 1
...

At this point, I wasn’t sure which version I used to build successfully. Searching for that error (and binutils to narrow things down) led to this bug in the sourceware.org Bugzilla that appears to be the exact bug I ran into: 28207 – error: unknown type name ‘uint’ (78 | uint recursion;) avr-gcc mingw32 Windows Build (sourceware.org). Fortunately, one Alan helpfully points out that this bug fixed on the binutils-2.37 branch with commit 999566402e3.

To figure out where the binutils git repo is, I click on the Browse button in Bugzilla then navigate to the binutils product category, which has a link to the list of bugs for the binutils component. A re-opened bug seems likely to have a link to some commits. I select 26865 – windres: –preprocessor option won’t respect space in file path (sourceware.org) and sure enough, there is a link to a commit on the binutils repo. We can now view the history of rust-demangle.c. To find the commit in question, click on any commitdiff to get the URL format then replace the hash in the URL with 999566402e3 to reveal the aforementioned fix for the unknown type name uint error.

Cloning binutils Repo

I’m used to GitHub where looking at the repo structure implies that you’re at a URL you can copy and trim to clone. In this other web view, the URL to clone is listed above the shortlog:

git clone https://sourceware.org/git/binutils-gdb.git

Tracing the Bug

At this point, it makes sense to verify that the 2.37 sources I downloaded actually contain the bug. Observe that:

  1. the tags section contains a binutils-2_37 tag described as “Official GNU Binutils 2.37 Release” and committed on Sun, 18 Jul 2021 16:46:54 +0000 (17:46 +0100).
  2. the fix for the build error shows a fix committed by Alan on Mon, 19 Jul 2021 11:32:21 +0000 (21:02 +0930)
  3. the bug fix that introduced the error was committed on Thu, 15 Jul 2021 15:51:56 +0000 (16:51 +0100)

Therefore, using binutils older than 2.37 should work just fine. However, it may still be necessary to run “rm -fr build” in the hsdis folder to enable 2.36 to be picked up when you run make (otherwise 2.37 is still baked into some of configure’s output).


Categories: Compilers

Ubuntu VM Setup for OpenJDK Development

I’m using a Windows 10 physical machine for my OpenJDK 17 development. Unfortunately, I ran into some issues getting the environment set up to build the JDK on Windows. To work around this, I created a Linux virtual machine. Although the instructions for building on Linux are on the OpenJDK site, I would like to have all the instructions in one spot, hence this post.

Creating an Ubuntu VM in Hyper-V

  1. Download an LTS Ubuntu .iso from the Ubuntu Desktop download page. I selected Ubuntu 20.04.3 LTS.
  2. Go to New > Virtual Machine in Hyper-V manager.
    1. Enter your VM name, generation, memory amount and type
    2. Select the connection type (Default Switch) and create a new virtual hard disk
    3. Select “Install an operating system from a bootable CD/DVD-ROM” then enter the path to the downloaded .iso file then click on Finish.
    4. Before starting the VM, set the number of virtual processors (it defaults to 1, which is less than ideal)!
  3. Perform a normal Ubuntu installation including erasing the disk

Let us now review the more interesting steps – those related to configuring the Ubuntu environment.

Increase the Resolution of the Ubuntu Guest OS

The default 1024×768 screen resolution of the Ubuntu guest is rather restrictive. The solution to this comes from https://askubuntu.com/questions/384602/ubuntu-hyper-v-guest-display-resolution. We need to configure the Hyper-V Synthetic Video Frame Buffer Driver by adding ” video=hyperv_fb:1680×1050” to the GRUB_CMDLINE_LINUX_DEFAULT value in the /etc/default/grub file.

sudo apt-get install linux-image-extra-virtual
sudo apt-get install vim
sudo vim /etc/default/grub
sudo update-grub
reboot

Install the development dependencies

The table below lists the JDK build dependencies and the commands to install them.

ComponentInstallation Command
autoconfsudo apt-get install autoconf
Gitsudo apt-get install git
C Compilersudo apt-get install build-essential
X11 librariessudo apt-get install libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev
cupssudo apt-get install libcups2-dev
fontconfigsudo apt-get install libfontconfig1-dev
alsasudo apt-get install libasound2-dev
JDK Build Dependencies

This single command suffices to install all these components.

sudo apt-get install autoconf git build-essential libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev libcups2-dev libfontconfig1-dev libasound2-dev

Install a code editor

Download the Visual Studio Code .deb file from https://code.visualstudio.com/Download. We can then install VS Code by running:

sudo apt install ~/Downloads/code_1.62.3-1637137107

Install a Boot JDK

I use the Microsoft OpenJDK build as the boot JDK. Here are the Ubuntu instructions for Installing the Microsoft Build of OpenJDK:

# Valid values are only '18.04' and '20.04'
# For other versions of Ubuntu, please use the tar.gz package
ubuntu_release=`lsb_release -rs`
cd ~/Downloads/
wget https://packages.microsoft.com/config/ubuntu/${ubuntu_release}/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get install apt-transport-https
sudo apt-get update
sudo apt-get install msopenjdk-17

Verify that everything is working by running “java -version”

Clone and Build the JDK

Clone the JDK. Note that cloning a fork might be much slower than cloning the upstream Github repo! I was averaging about 60KiB/s on my rork whereas cloning the upstream OpenJDK was averaging 6 MiB/s when receiving objects!

mkdir ~/repos
cd ~/repos
git clone https://github.com/openjdk/jdk

The JDK repo can now be configured and built

cd jdk
bash configure
make images

The configure command should display any missing dependencies that it needs and a suggestion for how to install them.

To try out your new build, switch to the bin folder and check the Java version:

cd ~/repos/jdk/build/linux-x86_64-server-release/jdk/bin
./java -version

To browse through the contents of the build folder in a file manager:

xdg-open ./build


Categories: Compilers

Entering the Compiler Space

Last week was my first week in the Java engineering group. It has been about 11 years since I took a compiler course (while in the CS MS program at BYU). A quick review of the history of Java was in order. Turns out I last used Java in 2012 in grad school. That must have been Java SE 7 from 2011 and Java SE 6 before that. Since I have not been in the compiler space since then, I have a steep learning curve ahead. That is the exciting thing about technology though – there is always more to learn!

I am currently a programmer in the developer division at Microsoft so it was helpful going through some of the Java development with Microsoft documentation for a high level overview of all our offerings. Also informative given my long absence from Java-land were the docs on how to Transition from Java 7 to Java 8 and from Java 8 to Java 11. It hadn’t yet dawned on me by the time I read through these that the reason references to 8, 11, and 17 keep coming up is because they are LTS releases.

As a newbie to the Java development world, I started by watching this 2019 OpenJDK Development talk on how to become an OpenJDK contributor. It is a great overview of concepts like project roles (author, committer, reviewer, etc), the contributor agreement, and (perhaps most importantly to me), how to find an issue to work on and build the OpenJDK. The breakdown of commonly used terminology and abbreviations was great to have as well.

For an introduction to the hotspot compiler, I started going through “A Simple Graph-Based Intermediate Representation“. I ended up watching Cliff Click’s talk on The Sea of Nodes and the HotSpot JIT before I got that far along in the paper. It was fascinating seeing details such as the CPU L1/L2 cache size playing into the design! Some of the concepts that I need to review after that talk include:

The sea of nodes talk also revealed to me how little I know about companies in the Java space. I don’t think I had heard of Azul before, for example. In fact, it’s not just companies but also technologies! I was going through some build documentation when I ran into mentions of AdoptOpenJDK and Adoptium, both of which were foreign to me. I was glad though to see my old friend Eclipse doing well.

One of the most enjoyable things about being a programmer is working with very skilled people, especially watching them in action! I always learn a lot! My colleagues David and Mat were kind enough to pull me into their triage and reporting of [JDK-8277299] STACK_OVERFLOW in Java_sun_awt_shell_Win32ShellFolder2_getIconBits – Java Bug System so I could get my feet wet with how things are done in OpenJDK development.

The OpenJDK process is certainly different from the other open source communities I’ve been a part of (.NET and Mozilla Firefox). My manager and I poked around the bug DB to see what compiler starter bugs are out there. I picked bug [JDK-7077093] labelOper::label() should return Label& but since I must start out as an author, issues cannot be assigned to me. Unusual to me but the logic appears sound. Here is the query for C2 starter bugs.

Other highlights of the week were setting up my dev box to build the OpenJDK source code (unsuccessfully), discovering that compiler explorer is a thing (and an open source one at that), learning from my teammates how to investigate a failure of a fairly complex test on MacOS (they were using LLDB). I hope to write follow-up entries on these at some point.