From 6b785a6c4829e14f3c79ec5db68eb05d6886d408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:34:16 +0100 Subject: [PATCH 01/72] Add mvfst and usdt dependencies --- .gitmodules | 3 + third-party/CMakeLists.txt | 2 + .../mvfst/patches/fizz-lower-case.patch | 26 + third-party/mvfst/src | 1 + third-party/proxygen/CMakeLists.txt | 3 +- .../proxygen/patches/mvfst-exception.patch | 12 + third-party/usdt/CMakeLists.txt | 1 + third-party/usdt/usdt.h | 534 ++++++++++++++++++ 8 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 third-party/mvfst/patches/fizz-lower-case.patch create mode 160000 third-party/mvfst/src create mode 100644 third-party/proxygen/patches/mvfst-exception.patch create mode 100644 third-party/usdt/CMakeLists.txt create mode 100644 third-party/usdt/usdt.h diff --git a/.gitmodules b/.gitmodules index 2a7e687583373a..0cca4da87f0068 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "xed-xed"] path = third-party/xed/xed url = https://github.com/intelxed/xed.git +[submodule "third-party/mvfst/src"] + path = third-party/mvfst/src + url = https://github.com/facebook/mvfst.git diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 5642df2630c843..fc98acfd148b8f 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -140,3 +140,5 @@ endif() ##### --- new style, but only depends on old style --- ##### add_subdirectory(watchman) + +add_subdirectory(usdt) diff --git a/third-party/mvfst/patches/fizz-lower-case.patch b/third-party/mvfst/patches/fizz-lower-case.patch new file mode 100644 index 00000000000000..c711a71abc4021 --- /dev/null +++ b/third-party/mvfst/patches/fizz-lower-case.patch @@ -0,0 +1,26 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index a878c7c47..17784f783 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -51,7 +51,7 @@ find_package(Boost 1.62 + ) + find_package(fmt REQUIRED) + find_package(folly REQUIRED) +-find_package(Fizz REQUIRED) ++find_package(fizz REQUIRED) + find_package(Glog REQUIRED) + find_package(Threads) + +diff --git a/cmake/mvfst-config.cmake.in b/cmake/mvfst-config.cmake.in +index d2f89b48e..773f21188 100644 +--- a/cmake/mvfst-config.cmake.in ++++ b/cmake/mvfst-config.cmake.in +@@ -18,7 +18,7 @@ + + include(CMakeFindDependencyMacro) + find_dependency(folly) +-find_dependency(Fizz) ++find_dependency(fizz) + find_dependency(Threads) + find_dependency(Boost COMPONENTS iostreams system thread filesystem regex context) + diff --git a/third-party/mvfst/src b/third-party/mvfst/src new file mode 160000 index 00000000000000..57bf5ac97e9a9c --- /dev/null +++ b/third-party/mvfst/src @@ -0,0 +1 @@ +Subproject commit 57bf5ac97e9a9c347a781912b468909f600188d7 diff --git a/third-party/proxygen/CMakeLists.txt b/third-party/proxygen/CMakeLists.txt index 3d91b633e0caa8..eaf0900816b006 100644 --- a/third-party/proxygen/CMakeLists.txt +++ b/third-party/proxygen/CMakeLists.txt @@ -23,7 +23,8 @@ ExternalProject_Add( PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/CMake/FindBoost.cmake" - /wangle/cmake/FindBoost.cmake + /wangle/cmake/FindBoost.cmake && + patch -p1 --force < "${CMAKE_CURRENT_SOURCE_DIR}/patches/mvfst-exception.patch" CMAKE_ARGS "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" -DCMAKE_MODULE_PATH=${CMAKE_SOURCE_DIR}/CMake diff --git a/third-party/proxygen/patches/mvfst-exception.patch b/third-party/proxygen/patches/mvfst-exception.patch new file mode 100644 index 00000000000000..2d40ecb229f107 --- /dev/null +++ b/third-party/proxygen/patches/mvfst-exception.patch @@ -0,0 +1,12 @@ +diff --git a/proxygen/lib/CMakeLists.txt b/proxygen/lib/CMakeLists.txt +index 74a028454..fb69ab1e6 100644 +--- a/proxygen/lib/CMakeLists.txt ++++ b/proxygen/lib/CMakeLists.txt +@@ -100,6 +100,7 @@ set( + mvfst::mvfst_server + mvfst::mvfst_codec_types + mvfst::mvfst_state_machine ++ mvfst::mvfst_exception + ) + + add_library( diff --git a/third-party/usdt/CMakeLists.txt b/third-party/usdt/CMakeLists.txt new file mode 100644 index 00000000000000..c0272c2f88275d --- /dev/null +++ b/third-party/usdt/CMakeLists.txt @@ -0,0 +1 @@ +add_library(usdt INTERFACE) diff --git a/third-party/usdt/usdt.h b/third-party/usdt/usdt.h new file mode 100644 index 00000000000000..2ce6d70fe80265 --- /dev/null +++ b/third-party/usdt/usdt.h @@ -0,0 +1,534 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * This single-header library defines a collection of variadic macros for + * defining and triggering USDTs (User Statically-Defined Tracepoints): + * + * - For USDTs without associated semaphore: + * USDT(group, name, args...) + * + * - For USDTs with implicit (transparent to the user) semaphore: + * USDT_WITH_SEMA(group, name, args...) + * USDT_IS_ACTIVE(group, name) + * + * - For USDTs with explicit (user-defined and provided) semaphore: + * USDT_WITH_EXPLICIT_SEMA(sema, group, name, args...) + * USDT_SEMA_IS_ACTIVE(sema) + * + * all of which emit a NOP instruction into the instruction stream, and so + * have *zero* overhead for the surrounding code. USDTs are identified by + * a combination of `group` and `name` identifiers, which is used by external + * tracing tooling (tracers) for identifying exact USDTs of interest. + * + * USDTs can have an associated (2-byte) activity counter (USDT semaphore), + * automatically maintained by Linux kernel whenever any correctly written + * BPF-based tracer is attached to the USDT. This USDT semaphore can be used + * to check whether there is a need to do any extra data collection and + * processing for a given USDT (if necessary), and otherwise avoid extra work + * for a common case of USDT not being traced ("active"). + * + * See documentation for USDT_WITH_SEMA()/USDT_IS_ACTIVE() or + * USDT_WITH_EXPLICIT_SEMA()/USDT_SEMA_IS_ACTIVE() APIs below for details on + * working with USDTs with implicitly or explicitly associated + * USDT semaphores, respectively. + * + * There is also some additional data recorded into an auxiliary note + * section. The data in the note section describes the operands, in terms of + * size and location, used by tracing tooling to know where to find USDT + * arguments. Each location is encoded as an assembler operand string. + * Tracing tools (bpftrace and BPF-based tracers, systemtap, etc) insert + * breakpoints on top of the nop, and decode the location operand-strings, + * like an assembler, to find the values being passed. + * + * The operand strings are selected by the compiler for each operand. + * They are constrained by inline-assembler codes.The default is: + * + * #define USDT_ARG_CONSTRAINT nor + * + * This is a good default if the operands tend to be integral and + * moderate in number (smaller than number of registers). In other + * cases, the compiler may report "'asm' requires impossible reload" or + * similar. In this case, consider simplifying the macro call (fewer + * and simpler operands), reduce optimization, or override the default + * constraints string via: + * + * #define USDT_ARG_CONSTRAINT g + * #include + * + * For some historical description of USDT v3 format (the one used by this + * library and generally recognized and assumed by BPF-based tracing tools) + * see [0]. The more formal specification can be found at [1]. Additional + * argument constraints information can be found at [2]. + * + * Original SystemTap's sys/sdt.h implementation ([3]) was used as a base for + * this USDT library implementation. Current implementation differs *a lot* in + * terms of exposed user API and general usability, which was the main goal + * and focus of the reimplementation work. Nevertheless, underlying recorded + * USDT definitions are fully binary compatible and any USDT-based tooling + * should work equally well with USDTs defined by either SystemTap's or this + * library's USDT implementation. + * + * [0] https://ecos.sourceware.org/ml/systemtap/2010-q3/msg00145.html + * [1] https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation + * [2] https://gcc.gnu.org/onlinedocs/gcc/Constraints.html + * [3] https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h + */ +#ifndef __USDT_H +#define __USDT_H + +/* + * Changelog: + * + * 0.1.0 + * ----- + * - Initial release + */ +#define USDT_MAJOR_VERSION 0 +#define USDT_MINOR_VERSION 1 +#define USDT_PATCH_VERSION 0 + +/* C++20 and C23 added __VA_OPT__ as a standard replacement for non-standard `##__VA_ARGS__` extension */ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L) || (defined(__cplusplus) && __cplusplus > 201703L) +#define __usdt_va_opt 1 +#define __usdt_va_args(...) __VA_OPT__(,) __VA_ARGS__ +#else +#define __usdt_va_args(...) , ##__VA_ARGS__ +#endif + +/* + * Trigger USDT with `group`:`name` identifier and pass through `args` as its + * arguments. Zero arguments are acceptable as well. No USDT semaphore is + * associated with this USDT. + * + * Such "semaphoreless" USDTs are commonly used when there is no extra data + * collection or processing needed to collect and prepare USDT arguments and + * they are just available in the surrounding code. USDT() macro will just + * record their locations in CPU registers or in memory for tracing tooling to + * be able to access them, if necessary. + */ +#ifdef __usdt_va_opt +#define USDT(group, name, ...) \ + __usdt_probe(group, name, __usdt_sema_none, 0 __VA_OPT__(,) __VA_ARGS__) +#else +#define USDT(group, name, ...) \ + __usdt_probe(group, name, __usdt_sema_none, 0, ##__VA_ARGS__) +#endif + +/* + * Trigger USDT with `group`:`name` identifier and pass through `args` as its + * arguments. Zero arguments are acceptable as well. USDT also get an + * implicitly-defined associated USDT semaphore, which will be "activated" by + * tracing tooling and can be used to check whether USDT is being actively + * observed. + * + * USDTs with semaphore are commonly used when there is a need to perform + * additional data collection and processing to prepare USDT arguments, which + * otherwise might not be necessary for the rest of application logic. In such + * case, USDT semaphore can be used to avoid unnecessary extra work. If USDT + * is not traced (which is presumed to be a common situation), the associated + * USDT semaphore is "inactive", and so there is no need to waste resources to + * prepare USDT arguments. Use USDT_IS_ACTIVE(group, name) to check whether + * USDT is "active". + * + * N.B. There is an inherent (albeit short) gap between checking whether USDT + * is active and triggering corresponding USDT, in which external tracer can + * be attached to an USDT and activate USDT semaphore after the activity check. + * If such a race occurs, tracers might miss one USDT execution. Tracers are + * expected to accommodate such possibility and this is expected to not be + * a problem for applications and tracers. + * + * N.B. Implicit USDT semaphore defined by USDT_WITH_SEMA() is contained + * within a single executable or shared library and is not shared outside + * them. I.e., if you use USDT_WITH_SEMA() with the same USDT group and name + * identifier across executable and shared library, it will work and won't + * conflict, per se, but will define independent USDT semaphores, one for each + * shared library/executable in which USDT_WITH_SEMA(group, name) is used. + * That is, if you attach to this USDT in one shared library (or executable), + * then only USDT semaphore within that shared library (or executable) will be + * updated by the kernel, while other libraries (or executable) will not see + * activated USDT semaphore. In short, it's best to use unique USDT group:name + * identifiers across different shared libraries (and, equivalently, between + * executable and shared library). This is advanced consideration and is + * rarely (if ever) seen in practice, but just to avoid surprises this is + * called out here. (Static libraries become a part of final executable, once + * linked by linker, so the above considerations don't apply to them.) + */ +#ifdef __usdt_va_opt +#define USDT_WITH_SEMA(group, name, ...) \ + __usdt_probe(group, name, \ + __usdt_sema_implicit, __usdt_sema_name(group, name) \ + __VA_OPT__(,) __VA_ARGS__) +#else +#define USDT_WITH_SEMA(group, name, ...) \ + __usdt_probe(group, name, \ + __usdt_sema_implicit, __usdt_sema_name(group, name), \ + ##__VA_ARGS__) +#endif + +struct usdt_sema { volatile unsigned short active; }; + +/* + * Check if USDT with `group`:`name` identifier is "active" (i.e., whether it + * is attached to by external tracing tooling and is actively observed). + * + * This macro can be used to decide whether any additional and potentially + * expensive data collection or processing should be done to pass extra + * information into the given USDT. It is assumed that USDT is triggered with + * USDT_WITH_SEMA() macro which will implicitly define associated USDT + * semaphore. (If one needs more control over USDT semaphore, see + * USDT_DEFINE_SEMA() and USDT_WITH_EXPLICIT_SEMA() macros below.) + * + * N.B. Such checks are necessarily racy and speculative. Between checking + * whether USDT is active and triggering the USDT itself, tracer can be + * detached with no notification. This race should be extremely rare and worst + * case should result in one-time wasted extra data collection and processing. + */ +#define USDT_IS_ACTIVE(group, name) ({ \ + extern struct usdt_sema __usdt_sema_name(group, name) \ + __usdt_asm_name(__usdt_sema_name(group, name)); \ + __usdt_sema_implicit(__usdt_sema_name(group, name)); \ + __usdt_sema_name(group, name).active > 0; \ +}) + +/* + * APIs for working with user-defined explicit USDT semaphores. + * + * This is a less commonly used advanced API for use cases in which user needs + * an explicit control over (potentially shared across multiple USDTs) USDT + * semaphore instance. This can be used when there is a group of logically + * related USDTs that all need extra data collection and processing whenever + * any of a family of related USDTs are "activated" (i.e., traced). In such + * a case, all such related USDTs will be associated with the same shared USDT + * semaphore defined with USDT_DEFINE_SEMA() and the USDTs themselves will be + * triggered with USDT_WITH_EXPLICIT_SEMA() macros, taking an explicit extra + * USDT semaphore identifier as an extra parameter. + */ + +/** + * Underlying C global variable name for user-defined USDT semaphore with + * `sema` identifier. Could be useful for debugging, but normally shouldn't be + * used explicitly. + */ +#define USDT_SEMA(sema) __usdt_sema_##sema + +/* + * Define storage for user-defined USDT semaphore `sema`. + * + * Should be used only once in non-header source file to let compiler allocate + * space for the semaphore variable. Just like with any other global variable. + * + * This macro can be used anywhere where global variable declaration is + * allowed. Just like with global variable definitions, there should be only + * one definition of user-defined USDT semaphore with given `sema` identifier, + * otherwise compiler or linker will complain about duplicate variable + * definition. + * + * For C++, it is allowed to use USDT_DEFINE_SEMA() both in global namespace + * and inside namespaces (including nested namespaces). Just make sure that + * USDT_DECLARE_SEMA() is placed within the namespace where this semaphore is + * referenced, or any of its parent namespaces, so the C++ language-level + * identifier is visible to the code that needs to reference the semaphore. + * At the lowest layer, USDT semaphores have global naming and visibility + * (they have a corresponding `__usdt_sema_` symbol, which can be linked + * against from C or C++ code, if necessary). To keep it simple, putting + * USDT_DECLARE_SEMA() declarations into global namespaces is the simplest + * no-brainer solution. All these aspects are irrelevant for plain C, because + * C doesn't have namespaces and everything is always in the global namespace. + * + * N.B. Due to USDT metadata being recorded in non-allocatable ELF note + * section, it has limitations when it comes to relocations, which, in + * practice, means that it's not possible to correctly share USDT semaphores + * between main executable and shared libraries, or even between multiple + * shared libraries. USDT semaphore has to be contained to individual shared + * library or executable to avoid unpleasant surprises with half-working USDT + * semaphores. We enforce this by marking semaphore ELF symbols as having + * a hidden visibility. This is quite an advanced use case and consideration + * and for most users this should have no consequences whatsoever. + */ +#define USDT_DEFINE_SEMA(sema) \ + struct usdt_sema __usdt_sema_sec USDT_SEMA(sema) \ + __usdt_asm_name(USDT_SEMA(sema)) \ + __attribute__((visibility("hidden"))) = { 0 } + +/* + * Declare extern reference to user-defined USDT semaphore `sema`. + * + * Refers to a variable defined in another compilation unit by + * USDT_DEFINE_SEMA() and allows to use the same USDT semaphore across + * multiple compilation units (i.e., .c and .cpp files). + * + * See USDT_DEFINE_SEMA() notes above for C++ language usage peculiarities. + */ +#define USDT_DECLARE_SEMA(sema) \ + extern struct usdt_sema USDT_SEMA(sema) __usdt_asm_name(USDT_SEMA(sema)) + +/* + * Check if user-defined USDT semaphore `sema` is "active" (i.e., whether it + * is attached to by external tracing tooling and is actively observed). + * + * This macro can be used to decide whether any additional and potentially + * expensive data collection or processing should be done to pass extra + * information into USDT(s) associated with USDT semaphore `sema`. + * + * N.B. Such checks are necessarily racy. Between checking the state of USDT + * semaphore and triggering associated USDT(s), the active tracer might attach + * or detach. This race should be extremely rare and worst case should result + * in one-time missed USDT event or wasted extra data collection and + * processing. USDT-using tracers should be written with this in mind and is + * not a concern of the application defining USDTs with associated semaphore. + */ +#define USDT_SEMA_IS_ACTIVE(sema) (USDT_SEMA(sema).active > 0) + +/* + * Invoke USDT specified by `group` and `name` identifiers and associate + * explicitly user-defined semaphore `sema` with it. Pass through `args` as + * USDT arguments. `args` are optional and zero arguments are acceptable. + * + * Semaphore is defined with the help of USDT_DEFINE_SEMA() macro and can be + * checked whether active with USDT_SEMA_IS_ACTIVE(). + */ +#ifdef __usdt_va_opt +#define USDT_WITH_EXPLICIT_SEMA(sema, group, name, ...) \ + __usdt_probe(group, name, __usdt_sema_explicit, USDT_SEMA(sema), ##__VA_ARGS__) +#else +#define USDT_WITH_EXPLICIT_SEMA(sema, group, name, ...) \ + __usdt_probe(group, name, __usdt_sema_explicit, USDT_SEMA(sema) __VA_OPT__(,) __VA_ARGS__) +#endif + +/* + * Adjustable implementation aspects + */ +#ifndef USDT_ARG_CONSTRAINT +#if defined __powerpc__ +#define USDT_ARG_CONSTRAINT nZr +#elif defined __arm__ +#define USDT_ARG_CONSTRAINT g +#else +#define USDT_ARG_CONSTRAINT nor +#endif +#endif /* USDT_ARG_CONSTRAINT */ + +#ifndef USDT_NOP +#if defined(__ia64__) || defined(__s390__) || defined(__s390x__) +#define USDT_NOP nop 0 +#else +#define USDT_NOP nop +#endif +#endif /* USDT_NOP */ + +/* + * Implementation details + */ +/* USDT name for implicitly-defined USDT semaphore, derived from group:name */ +#define __usdt_sema_name(group, name) __usdt_sema_##group##__##name +/* ELF section into which USDT semaphores are put */ +#define __usdt_sema_sec __attribute__((section(".probes"))) + +#define __usdt_concat(a, b) a ## b +#define __usdt_apply(fn, n) __usdt_concat(fn, n) + +#ifndef __usdt_nth +#define __usdt_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N +#endif + +#ifndef __usdt_narg +#ifdef __usdt_va_opt +#define __usdt_narg(...) __usdt_nth(_ __VA_OPT__(,) __VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#else +#define __usdt_narg(...) __usdt_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#endif +#endif /* __usdt_narg */ + +#define __usdt_hash # +#define __usdt_str_(x) #x +#define __usdt_str(x) __usdt_str_(x) + +#ifndef __usdt_asm_name +#define __usdt_asm_name(name) __asm__(__usdt_str(name)) +#endif + +#define __usdt_asm1(a) __usdt_str(a) "\n" +#define __usdt_asm2(a,b) __usdt_str(a) "," __usdt_str(b) "\n" +#define __usdt_asm3(a,b,c) __usdt_str(a) "," __usdt_str(b) "," __usdt_str(c) "\n" +#define __usdt_asm5(a,b,c,d,e) __usdt_str(a) "," __usdt_str(b) "," __usdt_str(c) "," \ + __usdt_str(d) "," __usdt_str(e) "\n" + +#ifdef __LP64__ +#define __usdt_asm_addr .8byte +#else +#define __usdt_asm_addr .4byte +#endif + +#define __usdt_asm_strz_(x) __usdt_asm1(.asciz #x) +#define __usdt_asm_strz(x) __usdt_asm_strz_(x) +#define __usdt_asm_str_(x) __usdt_asm1(.ascii #x) +#define __usdt_asm_str(x) __usdt_asm_str_(x) + +/* "semaphoreless" USDT case */ +#ifndef __usdt_sema_none +#define __usdt_sema_none(sema) +#endif + +/* implicitly defined __usdt_sema__group__name semaphore (using weak symbols) */ +#ifndef __usdt_sema_implicit +#define __usdt_sema_implicit(sema) \ + __asm__ __volatile__ ( \ + __usdt_asm1(.ifndef sema) \ + __usdt_asm3( .pushsection .probes, "aw", "progbits") \ + __usdt_asm1( .weak sema) \ + __usdt_asm1( .hidden sema) \ + __usdt_asm1( .align 2) \ + __usdt_asm1(sema:) \ + __usdt_asm1( .zero 2) \ + __usdt_asm2( .type sema, @object) \ + __usdt_asm2( .size sema, 2) \ + __usdt_asm1( .popsection) \ + __usdt_asm1(.endif) \ + ); +#endif + +/* externally defined semaphore using USDT_DEFINE_SEMA() and passed explicitly by user */ +#ifndef __usdt_sema_explicit +#define __usdt_sema_explicit(sema) \ + __asm__ __volatile__ ("" :: "m" (sema)); +#endif + +/* main USDT definition (nop and .note.stapsdt metadata) */ +#define __usdt_probe(group, name, sema_def, sema, ...) do { \ + sema_def(sema) \ + __asm__ __volatile__ ( \ + __usdt_asm1(990: USDT_NOP) \ + __usdt_asm3( .pushsection .note.stapsdt, "", "note") \ + __usdt_asm1( .balign 4) \ + __usdt_asm3( .4byte 992f-991f,994f-993f,3) \ + __usdt_asm1(991: .asciz "stapsdt") \ + __usdt_asm1(992: .balign 4) \ + __usdt_asm1(993: __usdt_asm_addr 990b) \ + __usdt_asm1( __usdt_asm_addr _.stapsdt.base) \ + __usdt_asm1( __usdt_asm_addr sema) \ + __usdt_asm_strz(group) \ + __usdt_asm_strz(name) \ + __usdt_asm_args(__VA_ARGS__) \ + __usdt_asm1( .ascii "\0") \ + __usdt_asm1(994: .balign 4) \ + __usdt_asm1( .popsection) \ + __usdt_asm1(.ifndef _.stapsdt.base) \ + __usdt_asm5( .pushsection .stapsdt.base,"aG","progbits",.stapsdt.base,comdat)\ + __usdt_asm1( .weak _.stapsdt.base) \ + __usdt_asm1( .hidden _.stapsdt.base) \ + __usdt_asm1(_.stapsdt.base:) \ + __usdt_asm1( .space 1) \ + __usdt_asm2( .size _.stapsdt.base, 1) \ + __usdt_asm1( .popsection) \ + __usdt_asm1(.endif) \ + :: __usdt_asm_ops(__VA_ARGS__) \ + ); \ +} while (0) + +/* + * NB: gdb PR24541 highlighted an unspecified corner of the sdt.h + * operand note format. + * + * The named register may be a longer or shorter (!) alias for the + * storage where the value in question is found. For example, on + * i386, 64-bit value may be put in register pairs, and a register + * name stored would identify just one of them. Previously, gcc was + * asked to emit the %w[id] (16-bit alias of some registers holding + * operands), even when a wider 32-bit value was used. + * + * Bottom line: the byte-width given before the @ sign governs. If + * there is a mismatch between that width and that of the named + * register, then a sys/sdt.h note consumer may need to employ + * architecture-specific heuristics to figure out where the compiler + * has actually put the complete value. + */ +#if defined(__powerpc__) || defined(__powerpc64__) +#define __usdt_argref(id) %I[id]%[id] +#elif defined(__i386__) +#define __usdt_argref(id) %k[id] /* gcc.gnu.org/PR80115 sourceware.org/PR24541 */ +#else +#define __usdt_argref(id) %[id] +#endif + +#define __usdt_asm_arg(n) __usdt_asm_str(%c[__usdt_asz##n]) \ + __usdt_asm1(.ascii "@") \ + __usdt_asm_str(__usdt_argref(__usdt_aval##n)) + +#define __usdt_asm_args0 /* no arguments */ +#define __usdt_asm_args1 __usdt_asm_arg(1) +#define __usdt_asm_args2 __usdt_asm_args1 __usdt_asm1(.ascii " ") __usdt_asm_arg(2) +#define __usdt_asm_args3 __usdt_asm_args2 __usdt_asm1(.ascii " ") __usdt_asm_arg(3) +#define __usdt_asm_args4 __usdt_asm_args3 __usdt_asm1(.ascii " ") __usdt_asm_arg(4) +#define __usdt_asm_args5 __usdt_asm_args4 __usdt_asm1(.ascii " ") __usdt_asm_arg(5) +#define __usdt_asm_args6 __usdt_asm_args5 __usdt_asm1(.ascii " ") __usdt_asm_arg(6) +#define __usdt_asm_args7 __usdt_asm_args6 __usdt_asm1(.ascii " ") __usdt_asm_arg(7) +#define __usdt_asm_args8 __usdt_asm_args7 __usdt_asm1(.ascii " ") __usdt_asm_arg(8) +#define __usdt_asm_args9 __usdt_asm_args8 __usdt_asm1(.ascii " ") __usdt_asm_arg(9) +#define __usdt_asm_args10 __usdt_asm_args9 __usdt_asm1(.ascii " ") __usdt_asm_arg(10) +#define __usdt_asm_args11 __usdt_asm_args10 __usdt_asm1(.ascii " ") __usdt_asm_arg(11) +#define __usdt_asm_args12 __usdt_asm_args11 __usdt_asm1(.ascii " ") __usdt_asm_arg(12) +#define __usdt_asm_args(...) __usdt_apply(__usdt_asm_args, __usdt_narg(__VA_ARGS__)) + +#define __usdt_is_arr(x) (__builtin_classify_type(x) == 14 || __builtin_classify_type(x) == 5) +#define __usdt_arg_size(x) (__usdt_is_arr(x) ? sizeof(void *) : sizeof(x)) + +/* + * We can't use __builtin_choose_expr() in C++, so fall back to table-based + * signedness determination for known types, utilizing templates magic. + */ +#ifdef __cplusplus + +#define __usdt_is_signed(x) (!__usdt_is_arr(x) && __usdt_t<__typeof(x)>::is_signed) + +#include + +template struct __usdt_t { static const bool is_signed = false; }; +template struct __usdt_t : public __usdt_t {}; +template struct __usdt_t : public __usdt_t {}; + +#define __usdt_def_signed(T) \ +template<> struct __usdt_t { static const bool is_signed = true; }; \ +template<> struct __usdt_t { static const bool is_signed = true; }; \ +template<> struct __usdt_t { static const bool is_signed = true; }; \ +template<> struct __usdt_t { static const bool is_signed = true; } +#define __usdt_maybe_signed(T) \ +template<> struct __usdt_t { static const bool is_signed = (T)-1 < (T)1; }; \ +template<> struct __usdt_t { static const bool is_signed = (T)-1 < (T)1; }; \ +template<> struct __usdt_t { static const bool is_signed = (T)-1 < (T)1; }; \ +template<> struct __usdt_t { static const bool is_signed = (T)-1 < (T)1; } + +__usdt_def_signed(signed char); +__usdt_def_signed(short); +__usdt_def_signed(int); +__usdt_def_signed(long); +__usdt_def_signed(long long); +__usdt_maybe_signed(char); +__usdt_maybe_signed(wchar_t); + +#else /* !__cplusplus */ + +#define __usdt_is_inttype(x) (__builtin_classify_type(x) >= 1 && __builtin_classify_type(x) <= 4) +#define __usdt_inttype(x) __typeof(__builtin_choose_expr(__usdt_is_inttype(x), (x), 0U)) +#define __usdt_is_signed(x) ((__usdt_inttype(x))-1 < (__usdt_inttype(x))1) + +#endif /* __cplusplus */ + +#define __usdt_asm_op(n, x) \ + [__usdt_asz##n] "n" ((__usdt_is_signed(x) ? (int)-1 : 1) * (int)__usdt_arg_size(x)), \ + [__usdt_aval##n] __usdt_str(USDT_ARG_CONSTRAINT)(x) + +#define __usdt_asm_ops0() [__usdt_dummy] "g" (0) +#define __usdt_asm_ops1(x) __usdt_asm_op(1, x) +#define __usdt_asm_ops2(a,x) __usdt_asm_ops1(a), __usdt_asm_op(2, x) +#define __usdt_asm_ops3(a,b,x) __usdt_asm_ops2(a,b), __usdt_asm_op(3, x) +#define __usdt_asm_ops4(a,b,c,x) __usdt_asm_ops3(a,b,c), __usdt_asm_op(4, x) +#define __usdt_asm_ops5(a,b,c,d,x) __usdt_asm_ops4(a,b,c,d), __usdt_asm_op(5, x) +#define __usdt_asm_ops6(a,b,c,d,e,x) __usdt_asm_ops5(a,b,c,d,e), __usdt_asm_op(6, x) +#define __usdt_asm_ops7(a,b,c,d,e,f,x) __usdt_asm_ops6(a,b,c,d,e,f), __usdt_asm_op(7, x) +#define __usdt_asm_ops8(a,b,c,d,e,f,g,x) __usdt_asm_ops7(a,b,c,d,e,f,g), __usdt_asm_op(8, x) +#define __usdt_asm_ops9(a,b,c,d,e,f,g,h,x) __usdt_asm_ops8(a,b,c,d,e,f,g,h), __usdt_asm_op(9, x) +#define __usdt_asm_ops10(a,b,c,d,e,f,g,h,i,x) __usdt_asm_ops9(a,b,c,d,e,f,g,h,i), __usdt_asm_op(10, x) +#define __usdt_asm_ops11(a,b,c,d,e,f,g,h,i,j,x) __usdt_asm_ops10(a,b,c,d,e,f,g,h,i,j), __usdt_asm_op(11, x) +#define __usdt_asm_ops12(a,b,c,d,e,f,g,h,i,j,k,x) __usdt_asm_ops11(a,b,c,d,e,f,g,h,i,j,k), __usdt_asm_op(12, x) +#define __usdt_asm_ops(...) __usdt_apply(__usdt_asm_ops, __usdt_narg(__VA_ARGS__))(__VA_ARGS__) + +#endif /* __USDT_H */ From eee13b6ae22780f6b1f745c2fa9a97a707dcef54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:38:51 +0100 Subject: [PATCH 02/72] Fix thrift build --- third-party/thrift/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/third-party/thrift/CMakeLists.txt b/third-party/thrift/CMakeLists.txt index 381b0243610564..bd5aff7a5281ea 100644 --- a/third-party/thrift/CMakeLists.txt +++ b/third-party/thrift/CMakeLists.txt @@ -22,7 +22,6 @@ find_package(FLEX REQUIRED) # Thrift uses `%code`, which isn't in 2.x find_package(BISON 3.0 REQUIRED) - ExternalProject_Add( bundled_thrift SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/ @@ -57,9 +56,12 @@ ExternalProject_Add( "-Dfmt_DIR=${fmt_DIR}" "-Dfolly_DIR=${FOLLY_INSTALL_DIR}/lib/cmake/folly" "-Dwangle_DIR=${WANGLE_INSTALL_DIR}/lib/cmake/wangle" + "-Dmvfst_DIR=${MVFST_INSTALL_DIR}/lib/cmake/mvfst" "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}" "-DCMAKE_CXX_FLAGS=-I${JEMALLOC_INCLUDE_DIR} ${CMAKE_CXX_FLAGS}" + + -Denable_tests=OFF ) ExternalProject_Get_property(bundled_thrift INSTALL_DIR) @@ -68,6 +70,7 @@ set( fizz fmt folly + mvfst proxygen wangle zstd From 6f1088d5979696af806d7fd5d9a6b1f9d7d39023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:41:29 +0100 Subject: [PATCH 03/72] Fix phph/hhbbc/index.cpp compilation --- hphp/hhbbc/index.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hphp/hhbbc/index.cpp b/hphp/hhbbc/index.cpp index a8fdc7ec6d5d60..b7a58cae69e6ef 100644 --- a/hphp/hhbbc/index.cpp +++ b/hphp/hhbbc/index.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -17303,7 +17304,7 @@ void make_class_infos_local( } ); capacities.clear(); - capacities.shrink_to_fit(); + //capacities.shrink_to_fit(); // Different threads can touch the same FuncInfo when adding to the // func family list, so use sharded locking scheme. From d228e48aac4bbf7124451d65dcb4f85e87e5fd58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:42:06 +0100 Subject: [PATCH 04/72] IWYU: fix boost include in hphp/compiler/systemlib.cpp --- hphp/compiler/compiler-systemlib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hphp/compiler/compiler-systemlib.cpp b/hphp/compiler/compiler-systemlib.cpp index 4285d9d5088027..80377a5494d279 100644 --- a/hphp/compiler/compiler-systemlib.cpp +++ b/hphp/compiler/compiler-systemlib.cpp @@ -35,7 +35,7 @@ #include "hphp/util/rds-local.h" #include "hphp/util/timer.h" -#include +#include #include #include #include From 32b06bec871c070ec68ec5ec69feb28964e8ee22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:48:58 +0100 Subject: [PATCH 05/72] Update OCaml stubs --- hphp/hack/src/client/dune | 1 + .../hackc/compile/cargo/options/Cargo.toml | 2 ++ hphp/hack/src/stubs/declarationsRewriter.ml | 1 + hphp/hack/src/stubs/dune | 27 +++++++------- hphp/hack/src/stubs/hh_distc_ffi.ml | 23 ++++++++++++ hphp/hack/src/stubs/linttool.ml | 2 ++ .../hack/src/stubs/logging/hackEventLogger.ml | 8 ++++- hphp/hack/src/stubs/remote_old_decls_ffi.ml | 10 ++++++ hphp/hack/src/stubs/sandcastle.ml | 1 + hphp/hack/src/stubs/sandcastle/dune | 35 +++++++++++++++++++ hphp/hack/src/stubs/saved_state_loader.ml | 25 ++++++++----- hphp/hack/src/watchman/dune | 2 +- 12 files changed, 115 insertions(+), 22 deletions(-) create mode 100644 hphp/hack/src/stubs/declarationsRewriter.ml create mode 100644 hphp/hack/src/stubs/hh_distc_ffi.ml create mode 100644 hphp/hack/src/stubs/linttool.ml create mode 100644 hphp/hack/src/stubs/remote_old_decls_ffi.ml create mode 100644 hphp/hack/src/stubs/sandcastle.ml create mode 100644 hphp/hack/src/stubs/sandcastle/dune diff --git a/hphp/hack/src/client/dune b/hphp/hack/src/client/dune index c33725fd2581f7..6ff4fdb375cbd1 100644 --- a/hphp/hack/src/client/dune +++ b/hphp/hack/src/client/dune @@ -29,6 +29,7 @@ pos rage redeclarations + sandcastle server server_command_types server_monitor diff --git a/hphp/hack/src/hackc/compile/cargo/options/Cargo.toml b/hphp/hack/src/hackc/compile/cargo/options/Cargo.toml index 280cadc53404c4..071e3b9498c33d 100644 --- a/hphp/hack/src/hackc/compile/cargo/options/Cargo.toml +++ b/hphp/hack/src/hackc/compile/cargo/options/Cargo.toml @@ -19,5 +19,7 @@ oxidized = { version = "0.0.0", path = "../../../../oxidized" } serde = { version = "1.0.185", features = ["derive", "rc"] } [build-dependencies] +generate_configs_lib = { version = "0.0.0", path = "../../../../../../tools/configs" } nom = "8" nom-language = "0.1" +nom = "7.1" diff --git a/hphp/hack/src/stubs/declarationsRewriter.ml b/hphp/hack/src/stubs/declarationsRewriter.ml new file mode 100644 index 00000000000000..526c4ce5902a5e --- /dev/null +++ b/hphp/hack/src/stubs/declarationsRewriter.ml @@ -0,0 +1 @@ +let start _ = () diff --git a/hphp/hack/src/stubs/dune b/hphp/hack/src/stubs/dune index 95775f3be72d5f..c3c5923aad7137 100644 --- a/hphp/hack/src/stubs/dune +++ b/hphp/hack/src/stubs/dune @@ -59,12 +59,6 @@ (preprocess (pps lwt_ppx ppx_deriving.std))) - ; this stub file is used by both buck2 and dune -(rule - (target remote_old_decls_ffi.ml) - (action - (copy# ../facebook/remote_old_decls/stubs/remote_old_decls_ffi.ml remote_old_decls_ffi.ml))) - (library (name remote_old_decls_ffi) (wrapped false) @@ -74,12 +68,6 @@ (preprocess (pps lwt_ppx ppx_deriving.std))) -; this stub file is used by both buck2 and dune -(rule - (target hh_distc_ffi.ml) - (action - (copy# ../facebook/hh_distc/check_ffi/stubs/hh_distc_ffi.ml hh_distc_ffi.ml))) - (library (name hh_distc_ffi) (wrapped false) @@ -159,6 +147,21 @@ (preprocess (pps lwt_ppx ppx_deriving.std))) +(library + (name redeclarations) + (wrapped false) + (modules declarationsRewriter)) + +(library + (name linttool) + (wrapped false) + (modules linttool)) + + (library + (name sandcastle_stubs) + (wrapped false) + (modules sandcastle)) + (library (name startup_initializer_stubs) (wrapped false) diff --git a/hphp/hack/src/stubs/hh_distc_ffi.ml b/hphp/hack/src/stubs/hh_distc_ffi.ml new file mode 100644 index 00000000000000..37ff10aa451257 --- /dev/null +++ b/hphp/hack/src/stubs/hh_distc_ffi.ml @@ -0,0 +1,23 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the "hack" directory of this source tree. + * + *) + +type handle + +let spawn ~root:_ ~ss_dir:_ ~hhdg_path:_ _ = failwith "start not implemented" + +let join _ = failwith "join_handle not implemented" + +let cancel _ = failwith "cancel not implemented" + +let is_finished _ = failwith "is_finished not implemented" + +let get_fd _ = failwith "get_fd not implemented" + +let get_re_session_id _ = failwith "get_re_session_id not implemented" + +let recv _ = failwith "recv not implemented" diff --git a/hphp/hack/src/stubs/linttool.ml b/hphp/hack/src/stubs/linttool.ml new file mode 100644 index 00000000000000..70d0128ddee24f --- /dev/null +++ b/hphp/hack/src/stubs/linttool.ml @@ -0,0 +1,2 @@ + +let run _ ~severity:_ = () diff --git a/hphp/hack/src/stubs/logging/hackEventLogger.ml b/hphp/hack/src/stubs/logging/hackEventLogger.ml index 64ddcabb051247..de23b013fa7388 100644 --- a/hphp/hack/src/stubs/logging/hackEventLogger.ml +++ b/hphp/hack/src/stubs/logging/hackEventLogger.ml @@ -27,6 +27,8 @@ let set_changed_mergebase _ = () let set_hhconfig_version _ = () +let set_mergebase_globalrev _ = () + let set_rollout_group _ = () let set_rollout_flags _ = () @@ -107,7 +109,7 @@ let type_check_dirty ~start_t:_ ~dirty_count:_ ~recheck_count:_ = () let lock_stolen _ = () -let client_init ~init_id:_ ~from:_ ~custom_columns:_ _ = () +let client_init ~init_id:_ ~from:_ ~is_interactive:_ ~custom_columns:_ _ = () let serverless_ide_init ~init_id:_ = () @@ -581,3 +583,7 @@ module Fanouts = struct let log ~changes_cardinal:_ ~fanout_cardinal:_ ~max_class_fanout_cardinal:_ = () end + +module TypingErrors = struct + let log_errors ~type_check_end_id:_ ~data:_ = () +end diff --git a/hphp/hack/src/stubs/remote_old_decls_ffi.ml b/hphp/hack/src/stubs/remote_old_decls_ffi.ml new file mode 100644 index 00000000000000..d45c6cc989573d --- /dev/null +++ b/hphp/hack/src/stubs/remote_old_decls_ffi.ml @@ -0,0 +1,10 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the "hack" directory of this source tree. + * + *) + +let get_decls_via_file_hashes _ _ = + failwith "get_decls_via_file_hashes not implemented" diff --git a/hphp/hack/src/stubs/sandcastle.ml b/hphp/hack/src/stubs/sandcastle.ml new file mode 100644 index 00000000000000..75c448d076d60f --- /dev/null +++ b/hphp/hack/src/stubs/sandcastle.ml @@ -0,0 +1 @@ +let is_sandcastle(): bool = false diff --git a/hphp/hack/src/stubs/sandcastle/dune b/hphp/hack/src/stubs/sandcastle/dune new file mode 100644 index 00000000000000..51d791c38eec74 --- /dev/null +++ b/hphp/hack/src/stubs/sandcastle/dune @@ -0,0 +1,35 @@ +(* -*- tuareg -*- *) + +let library_entry name suffix = + Printf.sprintf +"(library + (name %s) + (wrapped false) + (modules) + (libraries %s_%s))" name name suffix + +let fb_entry name = + library_entry name "fb" + +let stubs_entry name = + library_entry name "stubs" + +let entry is_fb name = + if is_fb then + fb_entry name + else + stubs_entry name + +let () = + (* test presence of fb subfolder *) + let current_dir = Sys.getcwd () in + (* we are in src/stubs/xxx, locate src/utils/facebook *) + let src_dir = Filename.dirname @@ Filename.dirname current_dir in + let utils_dir = Filename.concat src_dir "utils" in + let fb_utils_dir = Filename.concat utils_dir "facebook" in + (* locate src/utils/facebook/dune *) + let fb_dune = Filename.concat fb_utils_dir "dune" in + let is_fb = Sys.file_exists fb_dune in + let lib_name = entry is_fb "sandcastle" in + Jbuild_plugin.V1.send lib_name + diff --git a/hphp/hack/src/stubs/saved_state_loader.ml b/hphp/hack/src/stubs/saved_state_loader.ml index 46cc932b66d3b6..bf35d95efd17b1 100644 --- a/hphp/hack/src/stubs/saved_state_loader.ml +++ b/hphp/hack/src/stubs/saved_state_loader.ml @@ -35,7 +35,9 @@ module Naming_and_dep_table_info = struct naming_table_path: Path.t; naming_sqlite_table_path: Path.t; dep_table_path: Path.t; + compressed_dep_table_path: Path.t; errors_path: Path.t; + warning_hashes_path: Path.t; } type dirty_files = { @@ -44,11 +46,15 @@ module Naming_and_dep_table_info = struct } type additional_info = { - mergebase_global_rev: Hg.global_rev option; + (**mergebase_global_rev: Hg.global_rev option;*) dirty_files_promise: dirty_files Future.t; - saved_state_distance: int option; - saved_state_age: int option; + (** saved_state_distance: int option; + saved_state_age: int option;*) + saved_state_revs_info: ServerEnv.saved_state_revs_info; } + + let additional_info_of_yojson _ : additional_info = failwith "Not implemented" + let yojson_of_additional_info _ = failwith "Not implemented" end module Naming_table_info = struct @@ -80,13 +86,16 @@ include files other than Hack files, so the caller should filter the given list as necessary. *) type changed_files = Relative_path.t list -type ('main_artifacts, 'additional_info) load_result = { - main_artifacts: 'main_artifacts; - additional_info: 'additional_info; +let changed_files_of_yojson _ = failwith "Not implemented" +let yojson_of_changed_files _ = failwith "Not implemented" + +type load_result = { + main_artifacts: Naming_and_dep_table_info.main_artifacts; + additional_info: Naming_and_dep_table_info.additional_info; manifold_path: string; changed_files_according_to_watchman: changed_files; - corresponding_rev: Hg.Rev.t; - mergebase_rev: Hg.Rev.t; +(** corresponding_rev: Hg.Rev.t; + mergebase_rev: Hg.Rev.t;*) is_cached: bool; } diff --git a/hphp/hack/src/watchman/dune b/hphp/hack/src/watchman/dune index 3d95cba15dd2ea..a73f37d773c352 100644 --- a/hphp/hack/src/watchman/dune +++ b/hphp/hack/src/watchman/dune @@ -20,7 +20,7 @@ (name watchman_utils) (wrapped false) (modules watchman_utils) - (libraries hh_json logging utils_core) + (libraries hg hh_json logging utils_core) (preprocess (pps lwt_ppx ppx_deriving.std))) From 53aa4cb11eea79eb548124d5a48c3b0db0185b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:50:02 +0100 Subject: [PATCH 06/72] Remove nonexistent actions runner label --- .github/workflows/ubuntu.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 530a29f24190d4..744b4df397b1e6 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -26,7 +26,7 @@ env: jobs: build_ubuntu_focal_nightly: - runs-on: 16-core + runs-on: ubuntu-24.04 container: image: ubuntu:focal env: @@ -53,7 +53,7 @@ jobs: then update-alternatives --remove-all c++ fi - + update-alternatives --install /usr/bin/cc cc /usr/bin/clang++-${CLANG_VERSION} 500 update-alternatives --set cc /usr/bin/clang++-${CLANG_VERSION} update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${CLANG_VERSION} 500 From 006a6e025bb18bb2f8cdfb1a33b375d7df24087b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:50:36 +0100 Subject: [PATCH 07/72] Require the ldap package --- CMake/HPHPFindLibs.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMake/HPHPFindLibs.cmake b/CMake/HPHPFindLibs.cmake index 6baf472077f693..6549a56b70299e 100644 --- a/CMake/HPHPFindLibs.cmake +++ b/CMake/HPHPFindLibs.cmake @@ -83,6 +83,9 @@ if (FASTLZ_INCLUDE_DIR) include_directories(${FASTLZ_INCLUDE_DIR}) endif() +# ldap +find_package(Ldap) + # ICU find_package(ICU REQUIRED) if (ICU_FOUND) From 48333f1a89361bdf46c657e35672764ba5fa9478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:52:07 +0100 Subject: [PATCH 08/72] Provide OCaml env vars for ocamlrep crate --- hphp/hack/dev_env_rust_only.sh.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hphp/hack/dev_env_rust_only.sh.in b/hphp/hack/dev_env_rust_only.sh.in index 1bc915f88eb104..6d432d5802c1d3 100644 --- a/hphp/hack/dev_env_rust_only.sh.in +++ b/hphp/hack/dev_env_rust_only.sh.in @@ -11,4 +11,6 @@ # . $BUILD_DIR/hphp/hack/dev_env_rust_only.sh . "@CMAKE_CURRENT_BINARY_DIR@/dev_env_common.sh" -# Nothing else to do for rust :) + +# Export OCaml variables, needed by ocamlrep +eval $(opam env) From bc0d3c7a80af8f26c5ee5b35eab2fd9b0be6b2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:53:01 +0100 Subject: [PATCH 09/72] Update folly patches --- .../folly/patches/do-not-export-unbuilt-targets.patch | 6 +++--- third-party/folly/patches/folly-install-component.patch | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/third-party/folly/patches/do-not-export-unbuilt-targets.patch b/third-party/folly/patches/do-not-export-unbuilt-targets.patch index ce13f6a46572b1..a07fa830ae158f 100644 --- a/third-party/folly/patches/do-not-export-unbuilt-targets.patch +++ b/third-party/folly/patches/do-not-export-unbuilt-targets.patch @@ -10,10 +10,10 @@ Index: folly/folly/CMakeLists.txt RUNTIME DESTINATION ${BIN_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} -Index: folly/folly/experimental/exception_tracer/CMakeLists.txt +Index: folly/folly/debugging/exception_tracer/CMakeLists.txt =================================================================== ---- folly.orig/folly/experimental/exception_tracer/CMakeLists.txt -+++ folly/folly/experimental/exception_tracer/CMakeLists.txt +--- folly.orig/folly/debugging/exception_tracer/CMakeLists.txt ++++ folly/folly/debugging/exception_tracer/CMakeLists.txt @@ -63,7 +63,6 @@ if (FOLLY_HAVE_ELF AND FOLLY_HAVE_DWARF) folly_exception_tracer_base folly_exception_tracer diff --git a/third-party/folly/patches/folly-install-component.patch b/third-party/folly/patches/folly-install-component.patch index 773b84cd1c3a0c..35ccc928fc9add 100644 --- a/third-party/folly/patches/folly-install-component.patch +++ b/third-party/folly/patches/folly-install-component.patch @@ -2,7 +2,7 @@ Index: folly/CMakeLists.txt =================================================================== --- folly.orig/CMakeLists.txt +++ folly/CMakeLists.txt -@@ -385,8 +385,6 @@ target_compile_definitions(folly_base +@@ -460,8 +460,6 @@ target_compile_definitions(folly_base $ ) @@ -11,7 +11,7 @@ Index: folly/CMakeLists.txt option(PYTHON_EXTENSIONS "Build Python Bindings for Folly, requires Cython and (BUILD_SHARED_LIBS=ON)" OFF -@@ -414,21 +412,31 @@ target_link_libraries(folly_test_util +@@ -492,21 +490,31 @@ target_link_libraries(folly_test_util ${LIBGMOCK_LIBRARIES} ) apply_folly_compile_options_to_target(folly_test_util) From 266676e2ff8614f5e777bb6b88ee9614a7aeeef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Mon, 14 Apr 2025 23:57:46 +0200 Subject: [PATCH 10/72] Fix hhbc-unit.h generation --- hphp/hack/CMakeLists.txt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/hphp/hack/CMakeLists.txt b/hphp/hack/CMakeLists.txt index f8e1c8c24e69f8..6739ae7fc8020d 100644 --- a/hphp/hack/CMakeLists.txt +++ b/hphp/hack/CMakeLists.txt @@ -162,9 +162,12 @@ set(NAMING_SPECIAL_NAMES_SRCS "${NAMING_SPECIAL_NAMES_PREFIX}/naming_special_names_ffi_cbindgen.rs" ) -set(FFI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/src/utils/ffi") + +set(FFI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/src/hackc/ffi") set(FFI_SRCS - "${FFI_PREFIX}/ffi.rs" +# "${FFI_PREFIX}/ffi.rs" + "${FFI_PREFIX}/maybe.rs" + "${FFI_PREFIX}/vector.rs" "${FFI_PREFIX}/ffi_ffi_cbindgen.rs" ) @@ -185,9 +188,10 @@ set(FFI_HEADER "${RUST_FFI_BUILD_ROOT}/hphp/hack/src/utils/ffi.h") set(NAMING_SPECIAL_NAMES_HEADER "${RUST_FFI_BUILD_ROOT}/hphp/hack/src/naming/naming-special-names.h") set(TYPE_CONSTRAINT_HEADER "${CMAKE_SOURCE_DIR}/hphp/runtime/vm/type-constraint-flags.h") set(FCALL_HEADER "${CMAKE_SOURCE_DIR}/hphp/runtime/vm/fcall-args-flags.h") +set(ITER_ARGS_HEADER "${CMAKE_SOURCE_DIR}/hphp/runtime/vm/iter-args-flags.h") set(HHBC_HEADER "${CMAKE_SOURCE_DIR}/hphp/runtime/vm/hhbc-shared.h") set(ATTR_HEADER "${CMAKE_SOURCE_DIR}/hphp/runtime/base/attr.h") -set(FFI_EXTRA_HEADER "${CMAKE_SOURCE_DIR}/hphp/hack/src/utils/ffi/ffi_extra.h") +set(FFI_EXTRA_HEADER "${CMAKE_SOURCE_DIR}/hphp/hack/src/hackc/ffi/ffi_extra.h") add_custom_command( OUTPUT ${HHBC_AST_HEADER} @@ -203,7 +207,7 @@ add_custom_command( ${NAMING_SPECIAL_NAMES_SRCS} && ${INVOKE_CARGO} ffi_cbindgen ffi_cbindgen --bin ffi_cbindgen --header "${HHBC_AST_HEADER}" --namespaces "HPHP,hackc,hhbc" - --includes "${FFI_HEADER},${NAMING_SPECIAL_NAMES_HEADER},${TYPE_CONSTRAINT_HEADER},${ATTR_HEADER},${FCALL_HEADER},${HHBC_HEADER}" + --includes "${FFI_HEADER},${NAMING_SPECIAL_NAMES_HEADER},${TYPE_CONSTRAINT_HEADER},${ATTR_HEADER},${FCALL_HEADER},${ITER_ARGS_HEADER},${HHBC_HEADER}" ${HHBC_AST_SRCS} DEPENDS rustc cargo "${RUST_OPCODES}" COMMENT "Generating hhbc-unit.h" @@ -242,7 +246,7 @@ HHVM_RENDER_CONFIG_SPECIFICATION( # `lib` are extra link libraries to include in the bridge. # function(build_cxx_bridge NAME) - cmake_parse_arguments(CXX_BRIDGE "" "DIR" "EXTRA_SRCS;LINK_LIBS" ${ARGN}) + cmake_parse_arguments(CXX_BRIDGE "" "DIR" "EXTRA_SRCS;LINK_LIBS;DEPENDS" ${ARGN}) if ("${CXX_BRIDGE_DIR}" STREQUAL "") message(FATAL_ERROR "Missing DIR parameter") @@ -280,6 +284,10 @@ function(build_cxx_bridge NAME) DEPENDS ${RUST_PART_LIB} ) add_library("${NAME}" STATIC ${RUST_PART_CXX} ${CXX_BRIDGE_EXTRA_SRCS} ) + if (NOT "${CXX_BRIDGE_DEPENDS}" STREQUAL "") + add_dependencies("${NAME}" "${CXX_BRIDGE_DEPENDS}") + endif() + add_dependencies(hack_rust_ffi_bridge_targets "${NAME}") add_library("${NAME}_rust_part" STATIC IMPORTED) add_dependencies("${NAME}_rust_part" "${NAME}_cxx") @@ -316,6 +324,7 @@ build_cxx_bridge( DIR "src/hackc/ffi_bridge" EXTRA_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/src/hackc/ffi_bridge/external_decl_provider.cpp" LINK_LIBS hdf + DEPENDS hackc_options ) build_cxx_bridge( hdf From 4beeb7de671083e4c1b54700c54f949113116233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 15:38:08 +0100 Subject: [PATCH 11/72] Use system libraries for xxhash, lz4 and double-conversion --- ci/ubuntu-20.04-focal/debian/control | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/ubuntu-20.04-focal/debian/control b/ci/ubuntu-20.04-focal/debian/control index 238f2ad69f1a74..82d31deabfdb67 100644 --- a/ci/ubuntu-20.04-focal/debian/control +++ b/ci/ubuntu-20.04-focal/debian/control @@ -24,6 +24,7 @@ Build-Depends: libc-client2007e-dev, libcap-dev, libcurl4-openssl-dev, + libdouble-conversion-dev, libdwarf-dev, libedit-dev, libelf-dev, @@ -40,6 +41,7 @@ Build-Depends: libjemalloc-dev, libkrb5-dev, libldap2-dev, + liblz4-dev, libmagickwand-dev, libmcrypt-dev, libmemcached-dev, @@ -56,6 +58,7 @@ Build-Depends: libtool, libxml2-dev, libxslt1-dev, + libxxhash-dev, libyaml-dev, python3, re2c, From 3e8312331f58fbc97bc421ed93ccceda3f630aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 15:51:30 +0100 Subject: [PATCH 12/72] Use vendored fast_float library for folly --- third-party/CMakeLists.txt | 1 + third-party/fast_float/CMakeLists.txt | 2 + .../fast_float/fast_float/fast_float.h | 4025 +++++++++++++++++ third-party/folly/CMakeLists.txt | 3 + 4 files changed, 4031 insertions(+) create mode 100644 third-party/fast_float/CMakeLists.txt create mode 100644 third-party/fast_float/fast_float/fast_float.h diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index fc98acfd148b8f..24e479868f52df 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -50,6 +50,7 @@ list(APPEND THIRD_PARTY_MODULES timelib) # Required by folly add_subdirectory(double-conversion) add_subdirectory(boost) +add_subdirectory(fast_float) add_subdirectory(fmt) add_subdirectory(jemalloc) add_subdirectory(libsodium) diff --git a/third-party/fast_float/CMakeLists.txt b/third-party/fast_float/CMakeLists.txt new file mode 100644 index 00000000000000..88bc2f9b330ed8 --- /dev/null +++ b/third-party/fast_float/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(fast_float INTERFACE) +target_include_directories(fast_float INTERFACE "${CMAKE_CURRENT_LIST_DIR}") diff --git a/third-party/fast_float/fast_float/fast_float.h b/third-party/fast_float/fast_float/fast_float.h new file mode 100644 index 00000000000000..f1712168b59b7d --- /dev/null +++ b/third-party/fast_float/fast_float/fast_float.h @@ -0,0 +1,4025 @@ +// fast_float by Daniel Lemire +// fast_float by João Paulo Magalhaes +// +// +// with contributions from Eugene Golushkov +// with contributions from Maksim Kita +// with contributions from Marcin Wojdyr +// with contributions from Neal Richardson +// with contributions from Tim Paine +// with contributions from Fabio Pellacini +// with contributions from Lénárd Szolnoki +// with contributions from Jan Pharago +// with contributions from Maya Warrier +// with contributions from Taha Khokhar +// with contributions from Anders Dalvander +// +// +// Licensed under the Apache License, Version 2.0, or the +// MIT License or the Boost License. This file may not be copied, +// modified, or distributed except according to those terms. +// +// MIT License Notice +// +// MIT License +// +// Copyright (c) 2021 The fast_float authors +// +// Permission is hereby granted, free of charge, to any +// person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the +// Software without restriction, including without +// limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice +// shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// Apache License (Version 2.0) Notice +// +// Copyright 2021 The fast_float authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// +// BOOST License Notice +// +// Boost Software License - Version 1.0 - August 17th, 2003 +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +#ifndef FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H +#define FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H + +#ifdef __has_include +#if __has_include() +#include +#endif +#endif + +// Testing for https://wg21.link/N3652, adopted in C++14 +#if __cpp_constexpr >= 201304 +#define FASTFLOAT_CONSTEXPR14 constexpr +#else +#define FASTFLOAT_CONSTEXPR14 +#endif + +#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L +#define FASTFLOAT_HAS_BIT_CAST 1 +#else +#define FASTFLOAT_HAS_BIT_CAST 0 +#endif + +#if defined(__cpp_lib_is_constant_evaluated) && \ + __cpp_lib_is_constant_evaluated >= 201811L +#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1 +#else +#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0 +#endif + +// Testing for relevant C++20 constexpr library features +#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST && \ + __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/ +#define FASTFLOAT_CONSTEXPR20 constexpr +#define FASTFLOAT_IS_CONSTEXPR 1 +#else +#define FASTFLOAT_CONSTEXPR20 +#define FASTFLOAT_IS_CONSTEXPR 0 +#endif + +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 0 +#else +#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 1 +#endif + +#endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H + +#ifndef FASTFLOAT_FLOAT_COMMON_H +#define FASTFLOAT_FLOAT_COMMON_H + +#include +#include +#include +#include +#include +#include +#ifdef __has_include +#if __has_include() && (__cplusplus > 202002L || _MSVC_LANG > 202002L) +#include +#endif +#endif + +namespace fast_float { + +enum class chars_format : uint64_t; + +namespace detail { +constexpr chars_format basic_json_fmt = chars_format(1 << 5); +constexpr chars_format basic_fortran_fmt = chars_format(1 << 6); +} // namespace detail + +enum class chars_format : uint64_t { + scientific = 1 << 0, + fixed = 1 << 2, + hex = 1 << 3, + no_infnan = 1 << 4, + // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6 + json = uint64_t(detail::basic_json_fmt) | fixed | scientific | no_infnan, + // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed. + json_or_infnan = uint64_t(detail::basic_json_fmt) | fixed | scientific, + fortran = uint64_t(detail::basic_fortran_fmt) | fixed | scientific, + general = fixed | scientific, + allow_leading_plus = 1 << 7, + skip_white_space = 1 << 8, +}; + +template struct from_chars_result_t { + UC const *ptr; + std::errc ec; +}; +using from_chars_result = from_chars_result_t; + +template struct parse_options_t { + constexpr explicit parse_options_t(chars_format fmt = chars_format::general, + UC dot = UC('.'), int b = 10) + : format(fmt), decimal_point(dot), base(b) {} + + /** Which number formats are accepted */ + chars_format format; + /** The character used as decimal point */ + UC decimal_point; + /** The base used for integers */ + int base; +}; +using parse_options = parse_options_t; + +} // namespace fast_float + +#if FASTFLOAT_HAS_BIT_CAST +#include +#endif + +#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) || \ + defined(__MINGW64__) || defined(__s390x__) || \ + (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \ + defined(__PPC64LE__)) || \ + defined(__loongarch64)) +#define FASTFLOAT_64BIT 1 +#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__arm__) || defined(_M_ARM) || defined(__ppc__) || \ + defined(__MINGW32__) || defined(__EMSCRIPTEN__)) +#define FASTFLOAT_32BIT 1 +#else + // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow. +// We can never tell the register width, but the SIZE_MAX is a good +// approximation. UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max +// portability. +#if SIZE_MAX == 0xffff +#error Unknown platform (16-bit, unsupported) +#elif SIZE_MAX == 0xffffffff +#define FASTFLOAT_32BIT 1 +#elif SIZE_MAX == 0xffffffffffffffff +#define FASTFLOAT_64BIT 1 +#else +#error Unknown platform (not 32-bit, not 64-bit?) +#endif +#endif + +#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__)) || \ + (defined(_M_ARM64) && !defined(__MINGW32__)) +#include +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#define FASTFLOAT_VISUAL_STUDIO 1 +#endif + +#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ +#define FASTFLOAT_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#elif defined _WIN32 +#define FASTFLOAT_IS_BIG_ENDIAN 0 +#else +#if defined(__APPLE__) || defined(__FreeBSD__) +#include +#elif defined(sun) || defined(__sun) +#include +#elif defined(__MVS__) +#include +#else +#ifdef __has_include +#if __has_include() +#include +#endif //__has_include() +#endif //__has_include +#endif +# +#ifndef __BYTE_ORDER__ +// safe choice +#define FASTFLOAT_IS_BIG_ENDIAN 0 +#endif +# +#ifndef __ORDER_LITTLE_ENDIAN__ +// safe choice +#define FASTFLOAT_IS_BIG_ENDIAN 0 +#endif +# +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define FASTFLOAT_IS_BIG_ENDIAN 0 +#else +#define FASTFLOAT_IS_BIG_ENDIAN 1 +#endif +#endif + +#if defined(__SSE2__) || (defined(FASTFLOAT_VISUAL_STUDIO) && \ + (defined(_M_AMD64) || defined(_M_X64) || \ + (defined(_M_IX86_FP) && _M_IX86_FP == 2))) +#define FASTFLOAT_SSE2 1 +#endif + +#if defined(__aarch64__) || defined(_M_ARM64) +#define FASTFLOAT_NEON 1 +#endif + +#if defined(FASTFLOAT_SSE2) || defined(FASTFLOAT_NEON) +#define FASTFLOAT_HAS_SIMD 1 +#endif + +#if defined(__GNUC__) +// disable -Wcast-align=strict (GCC only) +#define FASTFLOAT_SIMD_DISABLE_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wcast-align\"") +#else +#define FASTFLOAT_SIMD_DISABLE_WARNINGS +#endif + +#if defined(__GNUC__) +#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") +#else +#define FASTFLOAT_SIMD_RESTORE_WARNINGS +#endif + +#ifdef FASTFLOAT_VISUAL_STUDIO +#define fastfloat_really_inline __forceinline +#else +#define fastfloat_really_inline inline __attribute__((always_inline)) +#endif + +#ifndef FASTFLOAT_ASSERT +#define FASTFLOAT_ASSERT(x) \ + { ((void)(x)); } +#endif + +#ifndef FASTFLOAT_DEBUG_ASSERT +#define FASTFLOAT_DEBUG_ASSERT(x) \ + { ((void)(x)); } +#endif + +// rust style `try!()` macro, or `?` operator +#define FASTFLOAT_TRY(x) \ + { \ + if (!(x)) \ + return false; \ + } + +#define FASTFLOAT_ENABLE_IF(...) \ + typename std::enable_if<(__VA_ARGS__), int>::type + +namespace fast_float { + +fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() { +#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED + return std::is_constant_evaluated(); +#else + return false; +#endif +} + +template +fastfloat_really_inline constexpr bool is_supported_float_type() { + return std::is_same::value || std::is_same::value +#if __STDCPP_FLOAT32_T__ + || std::is_same::value +#endif +#if __STDCPP_FLOAT64_T__ + || std::is_same::value +#endif + ; +} + +template +fastfloat_really_inline constexpr bool is_supported_char_type() { + return std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value; +} + +// Compares two ASCII strings in a case insensitive manner. +template +inline FASTFLOAT_CONSTEXPR14 bool +fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, + size_t length) { + for (size_t i = 0; i < length; ++i) { + UC const actual = actual_mixedcase[i]; + if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) { + return false; + } + } + return true; +} + +#ifndef FLT_EVAL_METHOD +#error "FLT_EVAL_METHOD should be defined, please include cfloat." +#endif + +// a pointer and a length to a contiguous block of memory +template struct span { + const T *ptr; + size_t length; + constexpr span(const T *_ptr, size_t _length) : ptr(_ptr), length(_length) {} + constexpr span() : ptr(nullptr), length(0) {} + + constexpr size_t len() const noexcept { return length; } + + FASTFLOAT_CONSTEXPR14 const T &operator[](size_t index) const noexcept { + FASTFLOAT_DEBUG_ASSERT(index < length); + return ptr[index]; + } +}; + +struct value128 { + uint64_t low; + uint64_t high; + constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {} + constexpr value128() : low(0), high(0) {} +}; + +/* Helper C++14 constexpr generic implementation of leading_zeroes */ +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int +leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { + if (input_num & uint64_t(0xffffffff00000000)) { + input_num >>= 32; + last_bit |= 32; + } + if (input_num & uint64_t(0xffff0000)) { + input_num >>= 16; + last_bit |= 16; + } + if (input_num & uint64_t(0xff00)) { + input_num >>= 8; + last_bit |= 8; + } + if (input_num & uint64_t(0xf0)) { + input_num >>= 4; + last_bit |= 4; + } + if (input_num & uint64_t(0xc)) { + input_num >>= 2; + last_bit |= 2; + } + if (input_num & uint64_t(0x2)) { /* input_num >>= 1; */ + last_bit |= 1; + } + return 63 - last_bit; +} + +/* result might be undefined when input_num is zero */ +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int +leading_zeroes(uint64_t input_num) { + assert(input_num > 0); + if (cpp20_and_in_constexpr()) { + return leading_zeroes_generic(input_num); + } +#ifdef FASTFLOAT_VISUAL_STUDIO +#if defined(_M_X64) || defined(_M_ARM64) + unsigned long leading_zero = 0; + // Search the mask data from most significant bit (MSB) + // to least significant bit (LSB) for a set bit (1). + _BitScanReverse64(&leading_zero, input_num); + return (int)(63 - leading_zero); +#else + return leading_zeroes_generic(input_num); +#endif +#else + return __builtin_clzll(input_num); +#endif +} + +// slow emulation routine for 32-bit +fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) { + return x * (uint64_t)y; +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t +umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) { + uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd); + uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd); + uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32)); + uint64_t adbc_carry = (uint64_t)(adbc < ad); + uint64_t lo = bd + (adbc << 32); + *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) + + (adbc_carry << 32) + (uint64_t)(lo < bd); + return lo; +} + +#ifdef FASTFLOAT_32BIT + +// slow emulation routine for 32-bit +#if !defined(__MINGW64__) +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab, + uint64_t cd, + uint64_t *hi) { + return umul128_generic(ab, cd, hi); +} +#endif // !__MINGW64__ + +#endif // FASTFLOAT_32BIT + +// compute 64-bit a*b +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 +full_multiplication(uint64_t a, uint64_t b) { + if (cpp20_and_in_constexpr()) { + value128 answer; + answer.low = umul128_generic(a, b, &answer.high); + return answer; + } + value128 answer; +#if defined(_M_ARM64) && !defined(__MINGW32__) + // ARM64 has native support for 64-bit multiplications, no need to emulate + // But MinGW on ARM64 doesn't have native support for 64-bit multiplications + answer.high = __umulh(a, b); + answer.low = a * b; +#elif defined(FASTFLOAT_32BIT) || \ + (defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64)) + answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64 +#elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__) + __uint128_t r = ((__uint128_t)a) * b; + answer.low = uint64_t(r); + answer.high = uint64_t(r >> 64); +#else + answer.low = umul128_generic(a, b, &answer.high); +#endif + return answer; +} + +struct adjusted_mantissa { + uint64_t mantissa{0}; + int32_t power2{0}; // a negative value indicates an invalid result + adjusted_mantissa() = default; + constexpr bool operator==(const adjusted_mantissa &o) const { + return mantissa == o.mantissa && power2 == o.power2; + } + constexpr bool operator!=(const adjusted_mantissa &o) const { + return mantissa != o.mantissa || power2 != o.power2; + } +}; + +// Bias so we can get the real exponent with an invalid adjusted_mantissa. +constexpr static int32_t invalid_am_bias = -0x8000; + +// used for binary_format_lookup_tables::max_mantissa +constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5; + +template struct binary_format_lookup_tables; + +template struct binary_format : binary_format_lookup_tables { + using equiv_uint = + typename std::conditional::type; + + static inline constexpr int mantissa_explicit_bits(); + static inline constexpr int minimum_exponent(); + static inline constexpr int infinite_power(); + static inline constexpr int sign_index(); + static inline constexpr int + min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST + static inline constexpr int max_exponent_fast_path(); + static inline constexpr int max_exponent_round_to_even(); + static inline constexpr int min_exponent_round_to_even(); + static inline constexpr uint64_t max_mantissa_fast_path(int64_t power); + static inline constexpr uint64_t + max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST + static inline constexpr int largest_power_of_ten(); + static inline constexpr int smallest_power_of_ten(); + static inline constexpr T exact_power_of_ten(int64_t power); + static inline constexpr size_t max_digits(); + static inline constexpr equiv_uint exponent_mask(); + static inline constexpr equiv_uint mantissa_mask(); + static inline constexpr equiv_uint hidden_bit_mask(); +}; + +template struct binary_format_lookup_tables { + static constexpr double powers_of_ten[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, + 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; + + // Largest integer value v so that (5**index * v) <= 1<<53. + // 0x20000000000000 == 1 << 53 + static constexpr uint64_t max_mantissa[] = { + 0x20000000000000, + 0x20000000000000 / 5, + 0x20000000000000 / (5 * 5), + 0x20000000000000 / (5 * 5 * 5), + 0x20000000000000 / (5 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555), + 0x20000000000000 / (constant_55555 * 5), + 0x20000000000000 / (constant_55555 * 5 * 5), + 0x20000000000000 / (constant_55555 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555 * 5 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555), + 0x20000000000000 / (constant_55555 * constant_55555 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * 5), + 0x20000000000000 / + (constant_55555 * constant_55555 * constant_55555 * 5 * 5), + 0x20000000000000 / + (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5), + 0x20000000000000 / + (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5), + 0x20000000000000 / + (constant_55555 * constant_55555 * constant_55555 * constant_55555), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * + constant_55555 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * + constant_55555 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * + constant_55555 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * + constant_55555 * 5 * 5 * 5 * 5)}; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template +constexpr double binary_format_lookup_tables::powers_of_ten[]; + +template +constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; + +#endif + +template struct binary_format_lookup_tables { + static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, + 1e6f, 1e7f, 1e8f, 1e9f, 1e10f}; + + // Largest integer value v so that (5**index * v) <= 1<<24. + // 0x1000000 == 1<<24 + static constexpr uint64_t max_mantissa[] = { + 0x1000000, + 0x1000000 / 5, + 0x1000000 / (5 * 5), + 0x1000000 / (5 * 5 * 5), + 0x1000000 / (5 * 5 * 5 * 5), + 0x1000000 / (constant_55555), + 0x1000000 / (constant_55555 * 5), + 0x1000000 / (constant_55555 * 5 * 5), + 0x1000000 / (constant_55555 * 5 * 5 * 5), + 0x1000000 / (constant_55555 * 5 * 5 * 5 * 5), + 0x1000000 / (constant_55555 * constant_55555), + 0x1000000 / (constant_55555 * constant_55555 * 5)}; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template +constexpr float binary_format_lookup_tables::powers_of_ten[]; + +template +constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; + +#endif + +template <> +inline constexpr int binary_format::min_exponent_fast_path() { +#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) + return 0; +#else + return -22; +#endif +} + +template <> +inline constexpr int binary_format::min_exponent_fast_path() { +#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) + return 0; +#else + return -10; +#endif +} + +template <> +inline constexpr int binary_format::mantissa_explicit_bits() { + return 52; +} +template <> +inline constexpr int binary_format::mantissa_explicit_bits() { + return 23; +} + +template <> +inline constexpr int binary_format::max_exponent_round_to_even() { + return 23; +} + +template <> +inline constexpr int binary_format::max_exponent_round_to_even() { + return 10; +} + +template <> +inline constexpr int binary_format::min_exponent_round_to_even() { + return -4; +} + +template <> +inline constexpr int binary_format::min_exponent_round_to_even() { + return -17; +} + +template <> inline constexpr int binary_format::minimum_exponent() { + return -1023; +} +template <> inline constexpr int binary_format::minimum_exponent() { + return -127; +} + +template <> inline constexpr int binary_format::infinite_power() { + return 0x7FF; +} +template <> inline constexpr int binary_format::infinite_power() { + return 0xFF; +} + +template <> inline constexpr int binary_format::sign_index() { + return 63; +} +template <> inline constexpr int binary_format::sign_index() { + return 31; +} + +template <> +inline constexpr int binary_format::max_exponent_fast_path() { + return 22; +} +template <> +inline constexpr int binary_format::max_exponent_fast_path() { + return 10; +} + +template <> +inline constexpr uint64_t binary_format::max_mantissa_fast_path() { + return uint64_t(2) << mantissa_explicit_bits(); +} +template <> +inline constexpr uint64_t +binary_format::max_mantissa_fast_path(int64_t power) { + // caller is responsible to ensure that + // power >= 0 && power <= 22 + // + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)max_mantissa[0], max_mantissa[power]; +} +template <> +inline constexpr uint64_t binary_format::max_mantissa_fast_path() { + return uint64_t(2) << mantissa_explicit_bits(); +} +template <> +inline constexpr uint64_t +binary_format::max_mantissa_fast_path(int64_t power) { + // caller is responsible to ensure that + // power >= 0 && power <= 10 + // + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)max_mantissa[0], max_mantissa[power]; +} + +template <> +inline constexpr double +binary_format::exact_power_of_ten(int64_t power) { + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)powers_of_ten[0], powers_of_ten[power]; +} +template <> +inline constexpr float binary_format::exact_power_of_ten(int64_t power) { + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)powers_of_ten[0], powers_of_ten[power]; +} + +template <> inline constexpr int binary_format::largest_power_of_ten() { + return 308; +} +template <> inline constexpr int binary_format::largest_power_of_ten() { + return 38; +} + +template <> +inline constexpr int binary_format::smallest_power_of_ten() { + return -342; +} +template <> inline constexpr int binary_format::smallest_power_of_ten() { + return -64; +} + +template <> inline constexpr size_t binary_format::max_digits() { + return 769; +} +template <> inline constexpr size_t binary_format::max_digits() { + return 114; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::exponent_mask() { + return 0x7F800000; +} +template <> +inline constexpr binary_format::equiv_uint +binary_format::exponent_mask() { + return 0x7FF0000000000000; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::mantissa_mask() { + return 0x007FFFFF; +} +template <> +inline constexpr binary_format::equiv_uint +binary_format::mantissa_mask() { + return 0x000FFFFFFFFFFFFF; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::hidden_bit_mask() { + return 0x00800000; +} +template <> +inline constexpr binary_format::equiv_uint +binary_format::hidden_bit_mask() { + return 0x0010000000000000; +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +to_float(bool negative, adjusted_mantissa am, T &value) { + using fastfloat_uint = typename binary_format::equiv_uint; + fastfloat_uint word = (fastfloat_uint)am.mantissa; + word |= fastfloat_uint(am.power2) + << binary_format::mantissa_explicit_bits(); + word |= fastfloat_uint(negative) << binary_format::sign_index(); +#if FASTFLOAT_HAS_BIT_CAST + value = std::bit_cast(word); +#else + ::memcpy(&value, &word, sizeof(T)); +#endif +} + +template struct space_lut { + static constexpr bool value[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template constexpr bool space_lut::value[]; + +#endif + +template constexpr bool is_space(UC c) { + return c < 256 && space_lut<>::value[uint8_t(c)]; +} + +template static constexpr uint64_t int_cmp_zeros() { + static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), + "Unsupported character size"); + return (sizeof(UC) == 1) ? 0x3030303030303030 + : (sizeof(UC) == 2) + ? (uint64_t(UC('0')) << 48 | uint64_t(UC('0')) << 32 | + uint64_t(UC('0')) << 16 | UC('0')) + : (uint64_t(UC('0')) << 32 | UC('0')); +} +template static constexpr int int_cmp_len() { + return sizeof(uint64_t) / sizeof(UC); +} +template static constexpr UC const *str_const_nan() { + return nullptr; +} +template <> constexpr char const *str_const_nan() { return "nan"; } +template <> constexpr wchar_t const *str_const_nan() { return L"nan"; } +template <> constexpr char16_t const *str_const_nan() { + return u"nan"; +} +template <> constexpr char32_t const *str_const_nan() { + return U"nan"; +} +template static constexpr UC const *str_const_inf() { + return nullptr; +} +template <> constexpr char const *str_const_inf() { return "infinity"; } +template <> constexpr wchar_t const *str_const_inf() { + return L"infinity"; +} +template <> constexpr char16_t const *str_const_inf() { + return u"infinity"; +} +template <> constexpr char32_t const *str_const_inf() { + return U"infinity"; +} + +template struct int_luts { + static constexpr uint8_t chdigit[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255}; + + static constexpr size_t maxdigits_u64[] = { + 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, 16, 16, 16, + 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13}; + + static constexpr uint64_t min_safe_u64[] = { + 9223372036854775808ull, 12157665459056928801ull, 4611686018427387904, + 7450580596923828125, 4738381338321616896, 3909821048582988049, + 9223372036854775808ull, 12157665459056928801ull, 10000000000000000000ull, + 5559917313492231481, 2218611106740436992, 8650415919381337933, + 2177953337809371136, 6568408355712890625, 1152921504606846976, + 2862423051509815793, 6746640616477458432, 15181127029874798299ull, + 1638400000000000000, 3243919932521508681, 6221821273427820544, + 11592836324538749809ull, 876488338465357824, 1490116119384765625, + 2481152873203736576, 4052555153018976267, 6502111422497947648, + 10260628712958602189ull, 15943230000000000000ull, 787662783788549761, + 1152921504606846976, 1667889514952984961, 2386420683693101056, + 3379220508056640625, 4738381338321616896}; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template constexpr uint8_t int_luts::chdigit[]; + +template constexpr size_t int_luts::maxdigits_u64[]; + +template constexpr uint64_t int_luts::min_safe_u64[]; + +#endif + +template +fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { + return int_luts<>::chdigit[static_cast(c)]; +} + +fastfloat_really_inline constexpr size_t max_digits_u64(int base) { + return int_luts<>::maxdigits_u64[base - 2]; +} + +// If a u64 is exactly max_digits_u64() in length, this is +// the value below which it has definitely overflowed. +fastfloat_really_inline constexpr uint64_t min_safe_u64(int base) { + return int_luts<>::min_safe_u64[base - 2]; +} + +constexpr chars_format operator~(chars_format rhs) noexcept { + using int_type = std::underlying_type::type; + return static_cast(~static_cast(rhs)); +} + +constexpr chars_format operator&(chars_format lhs, chars_format rhs) noexcept { + using int_type = std::underlying_type::type; + return static_cast(static_cast(lhs) & + static_cast(rhs)); +} + +constexpr chars_format operator|(chars_format lhs, chars_format rhs) noexcept { + using int_type = std::underlying_type::type; + return static_cast(static_cast(lhs) | + static_cast(rhs)); +} + +constexpr chars_format operator^(chars_format lhs, chars_format rhs) noexcept { + using int_type = std::underlying_type::type; + return static_cast(static_cast(lhs) ^ + static_cast(rhs)); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & +operator&=(chars_format &lhs, chars_format rhs) noexcept { + return lhs = (lhs & rhs); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & +operator|=(chars_format &lhs, chars_format rhs) noexcept { + return lhs = (lhs | rhs); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & +operator^=(chars_format &lhs, chars_format rhs) noexcept { + return lhs = (lhs ^ rhs); +} + +namespace detail { +// adjust for deprecated feature macros +constexpr chars_format adjust_for_feature_macros(chars_format fmt) { + return fmt +#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS + | chars_format::allow_leading_plus +#endif +#ifdef FASTFLOAT_SKIP_WHITE_SPACE + | chars_format::skip_white_space +#endif + ; +} +} // namespace detail + +} // namespace fast_float + +#endif + + +#ifndef FASTFLOAT_FAST_FLOAT_H +#define FASTFLOAT_FAST_FLOAT_H + + +namespace fast_float { +/** + * This function parses the character sequence [first,last) for a number. It + * parses floating-point numbers expecting a locale-indepent format equivalent + * to what is used by std::strtod in the default ("C") locale. The resulting + * floating-point value is the closest floating-point values (using either float + * or double), using the "round to even" convention for values that would + * otherwise fall right in-between two values. That is, we provide exact parsing + * according to the IEEE standard. + * + * Given a successful parse, the pointer (`ptr`) in the returned value is set to + * point right after the parsed number, and the `value` referenced is set to the + * parsed value. In case of error, the returned `ec` contains a representative + * error, otherwise the default (`std::errc()`) value is stored. + * + * The implementation does not throw and does not allocate memory (e.g., with + * `new` or `malloc`). + * + * Like the C++17 standard, the `fast_float::from_chars` functions take an + * optional last argument of the type `fast_float::chars_format`. It is a bitset + * value: we check whether `fmt & fast_float::chars_format::fixed` and `fmt & + * fast_float::chars_format::scientific` are set to determine whether we allow + * the fixed point and scientific notation respectively. The default is + * `fast_float::chars_format::general` which allows both `fixed` and + * `scientific`. + */ +template ())> +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars(UC const *first, UC const *last, T &value, + chars_format fmt = chars_format::general) noexcept; + +/** + * Like from_chars, but accepts an `options` argument to govern number parsing. + * Both for floating-point types and integer types. + */ +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_advanced(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept; + +/** + * from_chars for integer types. + */ +template ())> +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars(UC const *first, UC const *last, T &value, int base = 10) noexcept; + +} // namespace fast_float +#endif // FASTFLOAT_FAST_FLOAT_H + +#ifndef FASTFLOAT_ASCII_NUMBER_H +#define FASTFLOAT_ASCII_NUMBER_H + +#include +#include +#include +#include +#include +#include + + +#ifdef FASTFLOAT_SSE2 +#include +#endif + +#ifdef FASTFLOAT_NEON +#include +#endif + +namespace fast_float { + +template fastfloat_really_inline constexpr bool has_simd_opt() { +#ifdef FASTFLOAT_HAS_SIMD + return std::is_same::value; +#else + return false; +#endif +} + +// Next function can be micro-optimized, but compilers are entirely +// able to optimize it well. +template +fastfloat_really_inline constexpr bool is_integer(UC c) noexcept { + return !(c > UC('9') || c < UC('0')); +} + +fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) { + return (val & 0xFF00000000000000) >> 56 | (val & 0x00FF000000000000) >> 40 | + (val & 0x0000FF0000000000) >> 24 | (val & 0x000000FF00000000) >> 8 | + (val & 0x00000000FF000000) << 8 | (val & 0x0000000000FF0000) << 24 | + (val & 0x000000000000FF00) << 40 | (val & 0x00000000000000FF) << 56; +} + +// Read 8 UC into a u64. Truncates UC if not char. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +read8_to_u64(const UC *chars) { + if (cpp20_and_in_constexpr() || !std::is_same::value) { + uint64_t val = 0; + for (int i = 0; i < 8; ++i) { + val |= uint64_t(uint8_t(*chars)) << (i * 8); + ++chars; + } + return val; + } + uint64_t val; + ::memcpy(&val, chars, sizeof(uint64_t)); +#if FASTFLOAT_IS_BIG_ENDIAN == 1 + // Need to read as-if the number was in little-endian order. + val = byteswap(val); +#endif + return val; +} + +#ifdef FASTFLOAT_SSE2 + +fastfloat_really_inline uint64_t simd_read8_to_u64(const __m128i data) { + FASTFLOAT_SIMD_DISABLE_WARNINGS + const __m128i packed = _mm_packus_epi16(data, data); +#ifdef FASTFLOAT_64BIT + return uint64_t(_mm_cvtsi128_si64(packed)); +#else + uint64_t value; + // Visual Studio + older versions of GCC don't support _mm_storeu_si64 + _mm_storel_epi64(reinterpret_cast<__m128i *>(&value), packed); + return value; +#endif + FASTFLOAT_SIMD_RESTORE_WARNINGS +} + +fastfloat_really_inline uint64_t simd_read8_to_u64(const char16_t *chars) { + FASTFLOAT_SIMD_DISABLE_WARNINGS + return simd_read8_to_u64( + _mm_loadu_si128(reinterpret_cast(chars))); + FASTFLOAT_SIMD_RESTORE_WARNINGS +} + +#elif defined(FASTFLOAT_NEON) + +fastfloat_really_inline uint64_t simd_read8_to_u64(const uint16x8_t data) { + FASTFLOAT_SIMD_DISABLE_WARNINGS + uint8x8_t utf8_packed = vmovn_u16(data); + return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0); + FASTFLOAT_SIMD_RESTORE_WARNINGS +} + +fastfloat_really_inline uint64_t simd_read8_to_u64(const char16_t *chars) { + FASTFLOAT_SIMD_DISABLE_WARNINGS + return simd_read8_to_u64( + vld1q_u16(reinterpret_cast(chars))); + FASTFLOAT_SIMD_RESTORE_WARNINGS +} + +#endif // FASTFLOAT_SSE2 + +// MSVC SFINAE is broken pre-VS2017 +#if defined(_MSC_VER) && _MSC_VER <= 1900 +template +#else +template ()) = 0> +#endif +// dummy for compile +uint64_t simd_read8_to_u64(UC const *) { + return 0; +} + +// credit @aqrit +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t +parse_eight_digits_unrolled(uint64_t val) { + const uint64_t mask = 0x000000FF000000FF; + const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) + const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) + val -= 0x3030303030303030; + val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8; + val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32; + return uint32_t(val); +} + +// Call this if chars are definitely 8 digits. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t +parse_eight_digits_unrolled(UC const *chars) noexcept { + if (cpp20_and_in_constexpr() || !has_simd_opt()) { + return parse_eight_digits_unrolled(read8_to_u64(chars)); // truncation okay + } + return parse_eight_digits_unrolled(simd_read8_to_u64(chars)); +} + +// credit @aqrit +fastfloat_really_inline constexpr bool +is_made_of_eight_digits_fast(uint64_t val) noexcept { + return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) & + 0x8080808080808080)); +} + +#ifdef FASTFLOAT_HAS_SIMD + +// Call this if chars might not be 8 digits. +// Using this style (instead of is_made_of_eight_digits_fast() then +// parse_eight_digits_unrolled()) ensures we don't load SIMD registers twice. +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +simd_parse_if_eight_digits_unrolled(const char16_t *chars, + uint64_t &i) noexcept { + if (cpp20_and_in_constexpr()) { + return false; + } +#ifdef FASTFLOAT_SSE2 + FASTFLOAT_SIMD_DISABLE_WARNINGS + const __m128i data = + _mm_loadu_si128(reinterpret_cast(chars)); + + // (x - '0') <= 9 + // http://0x80.pl/articles/simd-parsing-int-sequences.html + const __m128i t0 = _mm_add_epi16(data, _mm_set1_epi16(32720)); + const __m128i t1 = _mm_cmpgt_epi16(t0, _mm_set1_epi16(-32759)); + + if (_mm_movemask_epi8(t1) == 0) { + i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); + return true; + } else + return false; + FASTFLOAT_SIMD_RESTORE_WARNINGS +#elif defined(FASTFLOAT_NEON) + FASTFLOAT_SIMD_DISABLE_WARNINGS + const uint16x8_t data = vld1q_u16(reinterpret_cast(chars)); + + // (x - '0') <= 9 + // http://0x80.pl/articles/simd-parsing-int-sequences.html + const uint16x8_t t0 = vsubq_u16(data, vmovq_n_u16('0')); + const uint16x8_t mask = vcltq_u16(t0, vmovq_n_u16('9' - '0' + 1)); + + if (vminvq_u16(mask) == 0xFFFF) { + i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); + return true; + } else + return false; + FASTFLOAT_SIMD_RESTORE_WARNINGS +#else + (void)chars; + (void)i; + return false; +#endif // FASTFLOAT_SSE2 +} + +#endif // FASTFLOAT_HAS_SIMD + +// MSVC SFINAE is broken pre-VS2017 +#if defined(_MSC_VER) && _MSC_VER <= 1900 +template +#else +template ()) = 0> +#endif +// dummy for compile +bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) { + return 0; +} + +template ::value) = 0> +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +loop_parse_if_eight_digits(const UC *&p, const UC *const pend, uint64_t &i) { + if (!has_simd_opt()) { + return; + } + while ((std::distance(p, pend) >= 8) && + simd_parse_if_eight_digits_unrolled( + p, i)) { // in rare cases, this will overflow, but that's ok + p += 8; + } +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +loop_parse_if_eight_digits(const char *&p, const char *const pend, + uint64_t &i) { + // optimizes better than parse_if_eight_digits_unrolled() for UC = char. + while ((std::distance(p, pend) >= 8) && + is_made_of_eight_digits_fast(read8_to_u64(p))) { + i = i * 100000000 + + parse_eight_digits_unrolled(read8_to_u64( + p)); // in rare cases, this will overflow, but that's ok + p += 8; + } +} + +enum class parse_error { + no_error, + // [JSON-only] The minus sign must be followed by an integer. + missing_integer_after_sign, + // A sign must be followed by an integer or dot. + missing_integer_or_dot_after_sign, + // [JSON-only] The integer part must not have leading zeros. + leading_zeros_in_integer_part, + // [JSON-only] The integer part must have at least one digit. + no_digits_in_integer_part, + // [JSON-only] If there is a decimal point, there must be digits in the + // fractional part. + no_digits_in_fractional_part, + // The mantissa must have at least one digit. + no_digits_in_mantissa, + // Scientific notation requires an exponential part. + missing_exponential_part, +}; + +template struct parsed_number_string_t { + int64_t exponent{0}; + uint64_t mantissa{0}; + UC const *lastmatch{nullptr}; + bool negative{false}; + bool valid{false}; + bool too_many_digits{false}; + // contains the range of the significant digits + span integer{}; // non-nullable + span fraction{}; // nullable + parse_error error{parse_error::no_error}; +}; + +using byte_span = span; +using parsed_number_string = parsed_number_string_t; + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t +report_parse_error(UC const *p, parse_error error) { + parsed_number_string_t answer; + answer.valid = false; + answer.lastmatch = p; + answer.error = error; + return answer; +} + +// Assuming that you use no more than 19 digits, this will +// parse an ASCII string. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t +parse_number_string(UC const *p, UC const *pend, + parse_options_t options) noexcept { + chars_format const fmt = detail::adjust_for_feature_macros(options.format); + UC const decimal_point = options.decimal_point; + + parsed_number_string_t answer; + answer.valid = false; + answer.too_many_digits = false; + // assume p < pend, so dereference without checks; + answer.negative = (*p == UC('-')); + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here + if ((*p == UC('-')) || + (uint64_t(fmt & chars_format::allow_leading_plus) && + !uint64_t(fmt & detail::basic_json_fmt) && *p == UC('+'))) { + ++p; + if (p == pend) { + return report_parse_error( + p, parse_error::missing_integer_or_dot_after_sign); + } + if (uint64_t(fmt & detail::basic_json_fmt)) { + if (!is_integer(*p)) { // a sign must be followed by an integer + return report_parse_error(p, + parse_error::missing_integer_after_sign); + } + } else { + if (!is_integer(*p) && + (*p != + decimal_point)) { // a sign must be followed by an integer or the dot + return report_parse_error( + p, parse_error::missing_integer_or_dot_after_sign); + } + } + } + UC const *const start_digits = p; + + uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad) + + while ((p != pend) && is_integer(*p)) { + // a multiplication by 10 is cheaper than an arbitrary integer + // multiplication + i = 10 * i + + uint64_t(*p - + UC('0')); // might overflow, we will handle the overflow later + ++p; + } + UC const *const end_of_integer_part = p; + int64_t digit_count = int64_t(end_of_integer_part - start_digits); + answer.integer = span(start_digits, size_t(digit_count)); + if (uint64_t(fmt & detail::basic_json_fmt)) { + // at least 1 digit in integer part, without leading zeros + if (digit_count == 0) { + return report_parse_error(p, parse_error::no_digits_in_integer_part); + } + if ((start_digits[0] == UC('0') && digit_count > 1)) { + return report_parse_error(start_digits, + parse_error::leading_zeros_in_integer_part); + } + } + + int64_t exponent = 0; + const bool has_decimal_point = (p != pend) && (*p == decimal_point); + if (has_decimal_point) { + ++p; + UC const *before = p; + // can occur at most twice without overflowing, but let it occur more, since + // for integers with many digits, digit parsing is the primary bottleneck. + loop_parse_if_eight_digits(p, pend, i); + + while ((p != pend) && is_integer(*p)) { + uint8_t digit = uint8_t(*p - UC('0')); + ++p; + i = i * 10 + digit; // in rare cases, this will overflow, but that's ok + } + exponent = before - p; + answer.fraction = span(before, size_t(p - before)); + digit_count -= exponent; + } + if (uint64_t(fmt & detail::basic_json_fmt)) { + // at least 1 digit in fractional part + if (has_decimal_point && exponent == 0) { + return report_parse_error(p, + parse_error::no_digits_in_fractional_part); + } + } else if (digit_count == + 0) { // we must have encountered at least one integer! + return report_parse_error(p, parse_error::no_digits_in_mantissa); + } + int64_t exp_number = 0; // explicit exponential part + if ((uint64_t(fmt & chars_format::scientific) && (p != pend) && + ((UC('e') == *p) || (UC('E') == *p))) || + (uint64_t(fmt & detail::basic_fortran_fmt) && (p != pend) && + ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || + (UC('D') == *p)))) { + UC const *location_of_e = p; + if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || + (UC('D') == *p)) { + ++p; + } + bool neg_exp = false; + if ((p != pend) && (UC('-') == *p)) { + neg_exp = true; + ++p; + } else if ((p != pend) && + (UC('+') == + *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) + ++p; + } + if ((p == pend) || !is_integer(*p)) { + if (!uint64_t(fmt & chars_format::fixed)) { + // The exponential part is invalid for scientific notation, so it must + // be a trailing token for fixed notation. However, fixed notation is + // disabled, so report a scientific notation error. + return report_parse_error(p, parse_error::missing_exponential_part); + } + // Otherwise, we will be ignoring the 'e'. + p = location_of_e; + } else { + while ((p != pend) && is_integer(*p)) { + uint8_t digit = uint8_t(*p - UC('0')); + if (exp_number < 0x10000000) { + exp_number = 10 * exp_number + digit; + } + ++p; + } + if (neg_exp) { + exp_number = -exp_number; + } + exponent += exp_number; + } + } else { + // If it scientific and not fixed, we have to bail out. + if (uint64_t(fmt & chars_format::scientific) && + !uint64_t(fmt & chars_format::fixed)) { + return report_parse_error(p, parse_error::missing_exponential_part); + } + } + answer.lastmatch = p; + answer.valid = true; + + // If we frequently had to deal with long strings of digits, + // we could extend our code by using a 128-bit integer instead + // of a 64-bit integer. However, this is uncommon. + // + // We can deal with up to 19 digits. + if (digit_count > 19) { // this is uncommon + // It is possible that the integer had an overflow. + // We have to handle the case where we have 0.0000somenumber. + // We need to be mindful of the case where we only have zeroes... + // E.g., 0.000000000...000. + UC const *start = start_digits; + while ((start != pend) && (*start == UC('0') || *start == decimal_point)) { + if (*start == UC('0')) { + digit_count--; + } + start++; + } + + if (digit_count > 19) { + answer.too_many_digits = true; + // Let us start again, this time, avoiding overflows. + // We don't need to check if is_integer, since we use the + // pre-tokenized spans from above. + i = 0; + p = answer.integer.ptr; + UC const *int_end = p + answer.integer.len(); + const uint64_t minimal_nineteen_digit_integer{1000000000000000000}; + while ((i < minimal_nineteen_digit_integer) && (p != int_end)) { + i = i * 10 + uint64_t(*p - UC('0')); + ++p; + } + if (i >= minimal_nineteen_digit_integer) { // We have a big integers + exponent = end_of_integer_part - p + exp_number; + } else { // We have a value with a fractional component. + p = answer.fraction.ptr; + UC const *frac_end = p + answer.fraction.len(); + while ((i < minimal_nineteen_digit_integer) && (p != frac_end)) { + i = i * 10 + uint64_t(*p - UC('0')); + ++p; + } + exponent = answer.fraction.ptr - p + exp_number; + } + // We have now corrected both exponent and i, to a truncated value + } + } + answer.exponent = exponent; + answer.mantissa = i; + return answer; +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t +parse_int_string(UC const *p, UC const *pend, T &value, + parse_options_t options) { + chars_format const fmt = detail::adjust_for_feature_macros(options.format); + int const base = options.base; + + from_chars_result_t answer; + + UC const *const first = p; + + bool const negative = (*p == UC('-')); + if (!std::is_signed::value && negative) { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } + if ((*p == UC('-')) || + (uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) { + ++p; + } + + UC const *const start_num = p; + + while (p != pend && *p == UC('0')) { + ++p; + } + + const bool has_leading_zeros = p > start_num; + + UC const *const start_digits = p; + + uint64_t i = 0; + if (base == 10) { + loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible + } + while (p != pend) { + uint8_t digit = ch_to_digit(*p); + if (digit >= base) { + break; + } + i = uint64_t(base) * i + digit; // might overflow, check this later + p++; + } + + size_t digit_count = size_t(p - start_digits); + + if (digit_count == 0) { + if (has_leading_zeros) { + value = 0; + answer.ec = std::errc(); + answer.ptr = p; + } else { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + } + return answer; + } + + answer.ptr = p; + + // check u64 overflow + size_t max_digits = max_digits_u64(base); + if (digit_count > max_digits) { + answer.ec = std::errc::result_out_of_range; + return answer; + } + // this check can be eliminated for all other types, but they will all require + // a max_digits(base) equivalent + if (digit_count == max_digits && i < min_safe_u64(base)) { + answer.ec = std::errc::result_out_of_range; + return answer; + } + + // check other types overflow + if (!std::is_same::value) { + if (i > uint64_t(std::numeric_limits::max()) + uint64_t(negative)) { + answer.ec = std::errc::result_out_of_range; + return answer; + } + } + + if (negative) { +#ifdef FASTFLOAT_VISUAL_STUDIO +#pragma warning(push) +#pragma warning(disable : 4146) +#endif + // this weird workaround is required because: + // - converting unsigned to signed when its value is greater than signed max + // is UB pre-C++23. + // - reinterpret_casting (~i + 1) would work, but it is not constexpr + // this is always optimized into a neg instruction (note: T is an integer + // type) + value = T(-std::numeric_limits::max() - + T(i - uint64_t(std::numeric_limits::max()))); +#ifdef FASTFLOAT_VISUAL_STUDIO +#pragma warning(pop) +#endif + } else { + value = T(i); + } + + answer.ec = std::errc(); + return answer; +} + +} // namespace fast_float + +#endif + +#ifndef FASTFLOAT_FAST_TABLE_H +#define FASTFLOAT_FAST_TABLE_H + +#include + +namespace fast_float { + +/** + * When mapping numbers from decimal to binary, + * we go from w * 10^q to m * 2^p but we have + * 10^q = 5^q * 2^q, so effectively + * we are trying to match + * w * 2^q * 5^q to m * 2^p. Thus the powers of two + * are not a concern since they can be represented + * exactly using the binary notation, only the powers of five + * affect the binary significand. + */ + +/** + * The smallest non-zero float (binary64) is 2^-1074. + * We take as input numbers of the form w x 10^q where w < 2^64. + * We have that w * 10^-343 < 2^(64-344) 5^-343 < 2^-1076. + * However, we have that + * (2^64-1) * 10^-342 = (2^64-1) * 2^-342 * 5^-342 > 2^-1074. + * Thus it is possible for a number of the form w * 10^-342 where + * w is a 64-bit value to be a non-zero floating-point number. + ********* + * Any number of form w * 10^309 where w>= 1 is going to be + * infinite in binary64 so we never need to worry about powers + * of 5 greater than 308. + */ +template struct powers_template { + + constexpr static int smallest_power_of_five = + binary_format::smallest_power_of_ten(); + constexpr static int largest_power_of_five = + binary_format::largest_power_of_ten(); + constexpr static int number_of_entries = + 2 * (largest_power_of_five - smallest_power_of_five + 1); + // Powers of five from 5^-342 all the way to 5^308 rounded toward one. + constexpr static uint64_t power_of_five_128[number_of_entries] = { + 0xeef453d6923bd65a, 0x113faa2906a13b3f, + 0x9558b4661b6565f8, 0x4ac7ca59a424c507, + 0xbaaee17fa23ebf76, 0x5d79bcf00d2df649, + 0xe95a99df8ace6f53, 0xf4d82c2c107973dc, + 0x91d8a02bb6c10594, 0x79071b9b8a4be869, + 0xb64ec836a47146f9, 0x9748e2826cdee284, + 0xe3e27a444d8d98b7, 0xfd1b1b2308169b25, + 0x8e6d8c6ab0787f72, 0xfe30f0f5e50e20f7, + 0xb208ef855c969f4f, 0xbdbd2d335e51a935, + 0xde8b2b66b3bc4723, 0xad2c788035e61382, + 0x8b16fb203055ac76, 0x4c3bcb5021afcc31, + 0xaddcb9e83c6b1793, 0xdf4abe242a1bbf3d, + 0xd953e8624b85dd78, 0xd71d6dad34a2af0d, + 0x87d4713d6f33aa6b, 0x8672648c40e5ad68, + 0xa9c98d8ccb009506, 0x680efdaf511f18c2, + 0xd43bf0effdc0ba48, 0x212bd1b2566def2, + 0x84a57695fe98746d, 0x14bb630f7604b57, + 0xa5ced43b7e3e9188, 0x419ea3bd35385e2d, + 0xcf42894a5dce35ea, 0x52064cac828675b9, + 0x818995ce7aa0e1b2, 0x7343efebd1940993, + 0xa1ebfb4219491a1f, 0x1014ebe6c5f90bf8, + 0xca66fa129f9b60a6, 0xd41a26e077774ef6, + 0xfd00b897478238d0, 0x8920b098955522b4, + 0x9e20735e8cb16382, 0x55b46e5f5d5535b0, + 0xc5a890362fddbc62, 0xeb2189f734aa831d, + 0xf712b443bbd52b7b, 0xa5e9ec7501d523e4, + 0x9a6bb0aa55653b2d, 0x47b233c92125366e, + 0xc1069cd4eabe89f8, 0x999ec0bb696e840a, + 0xf148440a256e2c76, 0xc00670ea43ca250d, + 0x96cd2a865764dbca, 0x380406926a5e5728, + 0xbc807527ed3e12bc, 0xc605083704f5ecf2, + 0xeba09271e88d976b, 0xf7864a44c633682e, + 0x93445b8731587ea3, 0x7ab3ee6afbe0211d, + 0xb8157268fdae9e4c, 0x5960ea05bad82964, + 0xe61acf033d1a45df, 0x6fb92487298e33bd, + 0x8fd0c16206306bab, 0xa5d3b6d479f8e056, + 0xb3c4f1ba87bc8696, 0x8f48a4899877186c, + 0xe0b62e2929aba83c, 0x331acdabfe94de87, + 0x8c71dcd9ba0b4925, 0x9ff0c08b7f1d0b14, + 0xaf8e5410288e1b6f, 0x7ecf0ae5ee44dd9, + 0xdb71e91432b1a24a, 0xc9e82cd9f69d6150, + 0x892731ac9faf056e, 0xbe311c083a225cd2, + 0xab70fe17c79ac6ca, 0x6dbd630a48aaf406, + 0xd64d3d9db981787d, 0x92cbbccdad5b108, + 0x85f0468293f0eb4e, 0x25bbf56008c58ea5, + 0xa76c582338ed2621, 0xaf2af2b80af6f24e, + 0xd1476e2c07286faa, 0x1af5af660db4aee1, + 0x82cca4db847945ca, 0x50d98d9fc890ed4d, + 0xa37fce126597973c, 0xe50ff107bab528a0, + 0xcc5fc196fefd7d0c, 0x1e53ed49a96272c8, + 0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7a, + 0x9faacf3df73609b1, 0x77b191618c54e9ac, + 0xc795830d75038c1d, 0xd59df5b9ef6a2417, + 0xf97ae3d0d2446f25, 0x4b0573286b44ad1d, + 0x9becce62836ac577, 0x4ee367f9430aec32, + 0xc2e801fb244576d5, 0x229c41f793cda73f, + 0xf3a20279ed56d48a, 0x6b43527578c1110f, + 0x9845418c345644d6, 0x830a13896b78aaa9, + 0xbe5691ef416bd60c, 0x23cc986bc656d553, + 0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa8, + 0x94b3a202eb1c3f39, 0x7bf7d71432f3d6a9, + 0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc53, + 0xe858ad248f5c22c9, 0xd1b3400f8f9cff68, + 0x91376c36d99995be, 0x23100809b9c21fa1, + 0xb58547448ffffb2d, 0xabd40a0c2832a78a, + 0xe2e69915b3fff9f9, 0x16c90c8f323f516c, + 0x8dd01fad907ffc3b, 0xae3da7d97f6792e3, + 0xb1442798f49ffb4a, 0x99cd11cfdf41779c, + 0xdd95317f31c7fa1d, 0x40405643d711d583, + 0x8a7d3eef7f1cfc52, 0x482835ea666b2572, + 0xad1c8eab5ee43b66, 0xda3243650005eecf, + 0xd863b256369d4a40, 0x90bed43e40076a82, + 0x873e4f75e2224e68, 0x5a7744a6e804a291, + 0xa90de3535aaae202, 0x711515d0a205cb36, + 0xd3515c2831559a83, 0xd5a5b44ca873e03, + 0x8412d9991ed58091, 0xe858790afe9486c2, + 0xa5178fff668ae0b6, 0x626e974dbe39a872, + 0xce5d73ff402d98e3, 0xfb0a3d212dc8128f, + 0x80fa687f881c7f8e, 0x7ce66634bc9d0b99, + 0xa139029f6a239f72, 0x1c1fffc1ebc44e80, + 0xc987434744ac874e, 0xa327ffb266b56220, + 0xfbe9141915d7a922, 0x4bf1ff9f0062baa8, + 0x9d71ac8fada6c9b5, 0x6f773fc3603db4a9, + 0xc4ce17b399107c22, 0xcb550fb4384d21d3, + 0xf6019da07f549b2b, 0x7e2a53a146606a48, + 0x99c102844f94e0fb, 0x2eda7444cbfc426d, + 0xc0314325637a1939, 0xfa911155fefb5308, + 0xf03d93eebc589f88, 0x793555ab7eba27ca, + 0x96267c7535b763b5, 0x4bc1558b2f3458de, + 0xbbb01b9283253ca2, 0x9eb1aaedfb016f16, + 0xea9c227723ee8bcb, 0x465e15a979c1cadc, + 0x92a1958a7675175f, 0xbfacd89ec191ec9, + 0xb749faed14125d36, 0xcef980ec671f667b, + 0xe51c79a85916f484, 0x82b7e12780e7401a, + 0x8f31cc0937ae58d2, 0xd1b2ecb8b0908810, + 0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa15, + 0xdfbdcece67006ac9, 0x67a791e093e1d49a, + 0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e0, + 0xaecc49914078536d, 0x58fae9f773886e18, + 0xda7f5bf590966848, 0xaf39a475506a899e, + 0x888f99797a5e012d, 0x6d8406c952429603, + 0xaab37fd7d8f58178, 0xc8e5087ba6d33b83, + 0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a64, + 0x855c3be0a17fcd26, 0x5cf2eea09a55067f, + 0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481e, + 0xd0601d8efc57b08b, 0xf13b94daf124da26, + 0x823c12795db6ce57, 0x76c53d08d6b70858, + 0xa2cb1717b52481ed, 0x54768c4b0c64ca6e, + 0xcb7ddcdda26da268, 0xa9942f5dcf7dfd09, + 0xfe5d54150b090b02, 0xd3f93b35435d7c4c, + 0x9efa548d26e5a6e1, 0xc47bc5014a1a6daf, + 0xc6b8e9b0709f109a, 0x359ab6419ca1091b, + 0xf867241c8cc6d4c0, 0xc30163d203c94b62, + 0x9b407691d7fc44f8, 0x79e0de63425dcf1d, + 0xc21094364dfb5636, 0x985915fc12f542e4, + 0xf294b943e17a2bc4, 0x3e6f5b7b17b2939d, + 0x979cf3ca6cec5b5a, 0xa705992ceecf9c42, + 0xbd8430bd08277231, 0x50c6ff782a838353, + 0xece53cec4a314ebd, 0xa4f8bf5635246428, + 0x940f4613ae5ed136, 0x871b7795e136be99, + 0xb913179899f68584, 0x28e2557b59846e3f, + 0xe757dd7ec07426e5, 0x331aeada2fe589cf, + 0x9096ea6f3848984f, 0x3ff0d2c85def7621, + 0xb4bca50b065abe63, 0xfed077a756b53a9, + 0xe1ebce4dc7f16dfb, 0xd3e8495912c62894, + 0x8d3360f09cf6e4bd, 0x64712dd7abbbd95c, + 0xb080392cc4349dec, 0xbd8d794d96aacfb3, + 0xdca04777f541c567, 0xecf0d7a0fc5583a0, + 0x89e42caaf9491b60, 0xf41686c49db57244, + 0xac5d37d5b79b6239, 0x311c2875c522ced5, + 0xd77485cb25823ac7, 0x7d633293366b828b, + 0x86a8d39ef77164bc, 0xae5dff9c02033197, + 0xa8530886b54dbdeb, 0xd9f57f830283fdfc, + 0xd267caa862a12d66, 0xd072df63c324fd7b, + 0x8380dea93da4bc60, 0x4247cb9e59f71e6d, + 0xa46116538d0deb78, 0x52d9be85f074e608, + 0xcd795be870516656, 0x67902e276c921f8b, + 0x806bd9714632dff6, 0xba1cd8a3db53b6, + 0xa086cfcd97bf97f3, 0x80e8a40eccd228a4, + 0xc8a883c0fdaf7df0, 0x6122cd128006b2cd, + 0xfad2a4b13d1b5d6c, 0x796b805720085f81, + 0x9cc3a6eec6311a63, 0xcbe3303674053bb0, + 0xc3f490aa77bd60fc, 0xbedbfc4411068a9c, + 0xf4f1b4d515acb93b, 0xee92fb5515482d44, + 0x991711052d8bf3c5, 0x751bdd152d4d1c4a, + 0xbf5cd54678eef0b6, 0xd262d45a78a0635d, + 0xef340a98172aace4, 0x86fb897116c87c34, + 0x9580869f0e7aac0e, 0xd45d35e6ae3d4da0, + 0xbae0a846d2195712, 0x8974836059cca109, + 0xe998d258869facd7, 0x2bd1a438703fc94b, + 0x91ff83775423cc06, 0x7b6306a34627ddcf, + 0xb67f6455292cbf08, 0x1a3bc84c17b1d542, + 0xe41f3d6a7377eeca, 0x20caba5f1d9e4a93, + 0x8e938662882af53e, 0x547eb47b7282ee9c, + 0xb23867fb2a35b28d, 0xe99e619a4f23aa43, + 0xdec681f9f4c31f31, 0x6405fa00e2ec94d4, + 0x8b3c113c38f9f37e, 0xde83bc408dd3dd04, + 0xae0b158b4738705e, 0x9624ab50b148d445, + 0xd98ddaee19068c76, 0x3badd624dd9b0957, + 0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d6, + 0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4c, + 0xd47487cc8470652b, 0x7647c3200069671f, + 0x84c8d4dfd2c63f3b, 0x29ecd9f40041e073, + 0xa5fb0a17c777cf09, 0xf468107100525890, + 0xcf79cc9db955c2cc, 0x7182148d4066eeb4, + 0x81ac1fe293d599bf, 0xc6f14cd848405530, + 0xa21727db38cb002f, 0xb8ada00e5a506a7c, + 0xca9cf1d206fdc03b, 0xa6d90811f0e4851c, + 0xfd442e4688bd304a, 0x908f4a166d1da663, + 0x9e4a9cec15763e2e, 0x9a598e4e043287fe, + 0xc5dd44271ad3cdba, 0x40eff1e1853f29fd, + 0xf7549530e188c128, 0xd12bee59e68ef47c, + 0x9a94dd3e8cf578b9, 0x82bb74f8301958ce, + 0xc13a148e3032d6e7, 0xe36a52363c1faf01, + 0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac1, + 0x96f5600f15a7b7e5, 0x29ab103a5ef8c0b9, + 0xbcb2b812db11a5de, 0x7415d448f6b6f0e7, + 0xebdf661791d60f56, 0x111b495b3464ad21, + 0x936b9fcebb25c995, 0xcab10dd900beec34, + 0xb84687c269ef3bfb, 0x3d5d514f40eea742, + 0xe65829b3046b0afa, 0xcb4a5a3112a5112, + 0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ab, + 0xb3f4e093db73a093, 0x59ed216765690f56, + 0xe0f218b8d25088b8, 0x306869c13ec3532c, + 0x8c974f7383725573, 0x1e414218c73a13fb, + 0xafbd2350644eeacf, 0xe5d1929ef90898fa, + 0xdbac6c247d62a583, 0xdf45f746b74abf39, + 0x894bc396ce5da772, 0x6b8bba8c328eb783, + 0xab9eb47c81f5114f, 0x66ea92f3f326564, + 0xd686619ba27255a2, 0xc80a537b0efefebd, + 0x8613fd0145877585, 0xbd06742ce95f5f36, + 0xa798fc4196e952e7, 0x2c48113823b73704, + 0xd17f3b51fca3a7a0, 0xf75a15862ca504c5, + 0x82ef85133de648c4, 0x9a984d73dbe722fb, + 0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebba, + 0xcc963fee10b7d1b3, 0x318df905079926a8, + 0xffbbcfe994e5c61f, 0xfdf17746497f7052, + 0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa633, + 0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc0, + 0xf9bd690a1b68637b, 0x3dfdce7aa3c673b0, + 0x9c1661a651213e2d, 0x6bea10ca65c084e, + 0xc31bfa0fe5698db8, 0x486e494fcff30a62, + 0xf3e2f893dec3f126, 0x5a89dba3c3efccfa, + 0x986ddb5c6b3a76b7, 0xf89629465a75e01c, + 0xbe89523386091465, 0xf6bbb397f1135823, + 0xee2ba6c0678b597f, 0x746aa07ded582e2c, + 0x94db483840b717ef, 0xa8c2a44eb4571cdc, + 0xba121a4650e4ddeb, 0x92f34d62616ce413, + 0xe896a0d7e51e1566, 0x77b020baf9c81d17, + 0x915e2486ef32cd60, 0xace1474dc1d122e, + 0xb5b5ada8aaff80b8, 0xd819992132456ba, + 0xe3231912d5bf60e6, 0x10e1fff697ed6c69, + 0x8df5efabc5979c8f, 0xca8d3ffa1ef463c1, + 0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb2, + 0xddd0467c64bce4a0, 0xac7cb3f6d05ddbde, + 0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96b, + 0xad4ab7112eb3929d, 0x86c16c98d2c953c6, + 0xd89d64d57a607744, 0xe871c7bf077ba8b7, + 0x87625f056c7c4a8b, 0x11471cd764ad4972, + 0xa93af6c6c79b5d2d, 0xd598e40d3dd89bcf, + 0xd389b47879823479, 0x4aff1d108d4ec2c3, + 0x843610cb4bf160cb, 0xcedf722a585139ba, + 0xa54394fe1eedb8fe, 0xc2974eb4ee658828, + 0xce947a3da6a9273e, 0x733d226229feea32, + 0x811ccc668829b887, 0x806357d5a3f525f, + 0xa163ff802a3426a8, 0xca07c2dcb0cf26f7, + 0xc9bcff6034c13052, 0xfc89b393dd02f0b5, + 0xfc2c3f3841f17c67, 0xbbac2078d443ace2, + 0x9d9ba7832936edc0, 0xd54b944b84aa4c0d, + 0xc5029163f384a931, 0xa9e795e65d4df11, + 0xf64335bcf065d37d, 0x4d4617b5ff4a16d5, + 0x99ea0196163fa42e, 0x504bced1bf8e4e45, + 0xc06481fb9bcf8d39, 0xe45ec2862f71e1d6, + 0xf07da27a82c37088, 0x5d767327bb4e5a4c, + 0x964e858c91ba2655, 0x3a6a07f8d510f86f, + 0xbbe226efb628afea, 0x890489f70a55368b, + 0xeadab0aba3b2dbe5, 0x2b45ac74ccea842e, + 0x92c8ae6b464fc96f, 0x3b0b8bc90012929d, + 0xb77ada0617e3bbcb, 0x9ce6ebb40173744, + 0xe55990879ddcaabd, 0xcc420a6a101d0515, + 0x8f57fa54c2a9eab6, 0x9fa946824a12232d, + 0xb32df8e9f3546564, 0x47939822dc96abf9, + 0xdff9772470297ebd, 0x59787e2b93bc56f7, + 0x8bfbea76c619ef36, 0x57eb4edb3c55b65a, + 0xaefae51477a06b03, 0xede622920b6b23f1, + 0xdab99e59958885c4, 0xe95fab368e45eced, + 0x88b402f7fd75539b, 0x11dbcb0218ebb414, + 0xaae103b5fcd2a881, 0xd652bdc29f26a119, + 0xd59944a37c0752a2, 0x4be76d3346f0495f, + 0x857fcae62d8493a5, 0x6f70a4400c562ddb, + 0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb952, + 0xd097ad07a71f26b2, 0x7e2000a41346a7a7, + 0x825ecc24c873782f, 0x8ed400668c0c28c8, + 0xa2f67f2dfa90563b, 0x728900802f0f32fa, + 0xcbb41ef979346bca, 0x4f2b40a03ad2ffb9, + 0xfea126b7d78186bc, 0xe2f610c84987bfa8, + 0x9f24b832e6b0f436, 0xdd9ca7d2df4d7c9, + 0xc6ede63fa05d3143, 0x91503d1c79720dbb, + 0xf8a95fcf88747d94, 0x75a44c6397ce912a, + 0x9b69dbe1b548ce7c, 0xc986afbe3ee11aba, + 0xc24452da229b021b, 0xfbe85badce996168, + 0xf2d56790ab41c2a2, 0xfae27299423fb9c3, + 0x97c560ba6b0919a5, 0xdccd879fc967d41a, + 0xbdb6b8e905cb600f, 0x5400e987bbc1c920, + 0xed246723473e3813, 0x290123e9aab23b68, + 0x9436c0760c86e30b, 0xf9a0b6720aaf6521, + 0xb94470938fa89bce, 0xf808e40e8d5b3e69, + 0xe7958cb87392c2c2, 0xb60b1d1230b20e04, + 0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c2, + 0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af3, + 0xe2280b6c20dd5232, 0x25c6da63c38de1b0, + 0x8d590723948a535f, 0x579c487e5a38ad0e, + 0xb0af48ec79ace837, 0x2d835a9df0c6d851, + 0xdcdb1b2798182244, 0xf8e431456cf88e65, + 0x8a08f0f8bf0f156b, 0x1b8e9ecb641b58ff, + 0xac8b2d36eed2dac5, 0xe272467e3d222f3f, + 0xd7adf884aa879177, 0x5b0ed81dcc6abb0f, + 0x86ccbb52ea94baea, 0x98e947129fc2b4e9, + 0xa87fea27a539e9a5, 0x3f2398d747b36224, + 0xd29fe4b18e88640e, 0x8eec7f0d19a03aad, + 0x83a3eeeef9153e89, 0x1953cf68300424ac, + 0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd7, + 0xcdb02555653131b6, 0x3792f412cb06794d, + 0x808e17555f3ebf11, 0xe2bbd88bbee40bd0, + 0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec4, + 0xc8de047564d20a8b, 0xf245825a5a445275, + 0xfb158592be068d2e, 0xeed6e2f0f0d56712, + 0x9ced737bb6c4183d, 0x55464dd69685606b, + 0xc428d05aa4751e4c, 0xaa97e14c3c26b886, + 0xf53304714d9265df, 0xd53dd99f4b3066a8, + 0x993fe2c6d07b7fab, 0xe546a8038efe4029, + 0xbf8fdb78849a5f96, 0xde98520472bdd033, + 0xef73d256a5c0f77c, 0x963e66858f6d4440, + 0x95a8637627989aad, 0xdde7001379a44aa8, + 0xbb127c53b17ec159, 0x5560c018580d5d52, + 0xe9d71b689dde71af, 0xaab8f01e6e10b4a6, + 0x9226712162ab070d, 0xcab3961304ca70e8, + 0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d22, + 0xe45c10c42a2b3b05, 0x8cb89a7db77c506a, + 0x8eb98a7a9a5b04e3, 0x77f3608e92adb242, + 0xb267ed1940f1c61c, 0x55f038b237591ed3, + 0xdf01e85f912e37a3, 0x6b6c46dec52f6688, + 0x8b61313bbabce2c6, 0x2323ac4b3b3da015, + 0xae397d8aa96c1b77, 0xabec975e0a0d081a, + 0xd9c7dced53c72255, 0x96e7bd358c904a21, + 0x881cea14545c7575, 0x7e50d64177da2e54, + 0xaa242499697392d2, 0xdde50bd1d5d0b9e9, + 0xd4ad2dbfc3d07787, 0x955e4ec64b44e864, + 0x84ec3c97da624ab4, 0xbd5af13bef0b113e, + 0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58e, + 0xcfb11ead453994ba, 0x67de18eda5814af2, + 0x81ceb32c4b43fcf4, 0x80eacf948770ced7, + 0xa2425ff75e14fc31, 0xa1258379a94d028d, + 0xcad2f7f5359a3b3e, 0x96ee45813a04330, + 0xfd87b5f28300ca0d, 0x8bca9d6e188853fc, + 0x9e74d1b791e07e48, 0x775ea264cf55347e, + 0xc612062576589dda, 0x95364afe032a819e, + 0xf79687aed3eec551, 0x3a83ddbd83f52205, + 0x9abe14cd44753b52, 0xc4926a9672793543, + 0xc16d9a0095928a27, 0x75b7053c0f178294, + 0xf1c90080baf72cb1, 0x5324c68b12dd6339, + 0x971da05074da7bee, 0xd3f6fc16ebca5e04, + 0xbce5086492111aea, 0x88f4bb1ca6bcf585, + 0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6, + 0x9392ee8e921d5d07, 0x3aff322e62439fd0, + 0xb877aa3236a4b449, 0x9befeb9fad487c3, + 0xe69594bec44de15b, 0x4c2ebe687989a9b4, + 0x901d7cf73ab0acd9, 0xf9d37014bf60a11, + 0xb424dc35095cd80f, 0x538484c19ef38c95, + 0xe12e13424bb40e13, 0x2865a5f206b06fba, + 0x8cbccc096f5088cb, 0xf93f87b7442e45d4, + 0xafebff0bcb24aafe, 0xf78f69a51539d749, + 0xdbe6fecebdedd5be, 0xb573440e5a884d1c, + 0x89705f4136b4a597, 0x31680a88f8953031, + 0xabcc77118461cefc, 0xfdc20d2b36ba7c3e, + 0xd6bf94d5e57a42bc, 0x3d32907604691b4d, + 0x8637bd05af6c69b5, 0xa63f9a49c2c1b110, + 0xa7c5ac471b478423, 0xfcf80dc33721d54, + 0xd1b71758e219652b, 0xd3c36113404ea4a9, + 0x83126e978d4fdf3b, 0x645a1cac083126ea, + 0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4, + 0xcccccccccccccccc, 0xcccccccccccccccd, + 0x8000000000000000, 0x0, + 0xa000000000000000, 0x0, + 0xc800000000000000, 0x0, + 0xfa00000000000000, 0x0, + 0x9c40000000000000, 0x0, + 0xc350000000000000, 0x0, + 0xf424000000000000, 0x0, + 0x9896800000000000, 0x0, + 0xbebc200000000000, 0x0, + 0xee6b280000000000, 0x0, + 0x9502f90000000000, 0x0, + 0xba43b74000000000, 0x0, + 0xe8d4a51000000000, 0x0, + 0x9184e72a00000000, 0x0, + 0xb5e620f480000000, 0x0, + 0xe35fa931a0000000, 0x0, + 0x8e1bc9bf04000000, 0x0, + 0xb1a2bc2ec5000000, 0x0, + 0xde0b6b3a76400000, 0x0, + 0x8ac7230489e80000, 0x0, + 0xad78ebc5ac620000, 0x0, + 0xd8d726b7177a8000, 0x0, + 0x878678326eac9000, 0x0, + 0xa968163f0a57b400, 0x0, + 0xd3c21bcecceda100, 0x0, + 0x84595161401484a0, 0x0, + 0xa56fa5b99019a5c8, 0x0, + 0xcecb8f27f4200f3a, 0x0, + 0x813f3978f8940984, 0x4000000000000000, + 0xa18f07d736b90be5, 0x5000000000000000, + 0xc9f2c9cd04674ede, 0xa400000000000000, + 0xfc6f7c4045812296, 0x4d00000000000000, + 0x9dc5ada82b70b59d, 0xf020000000000000, + 0xc5371912364ce305, 0x6c28000000000000, + 0xf684df56c3e01bc6, 0xc732000000000000, + 0x9a130b963a6c115c, 0x3c7f400000000000, + 0xc097ce7bc90715b3, 0x4b9f100000000000, + 0xf0bdc21abb48db20, 0x1e86d40000000000, + 0x96769950b50d88f4, 0x1314448000000000, + 0xbc143fa4e250eb31, 0x17d955a000000000, + 0xeb194f8e1ae525fd, 0x5dcfab0800000000, + 0x92efd1b8d0cf37be, 0x5aa1cae500000000, + 0xb7abc627050305ad, 0xf14a3d9e40000000, + 0xe596b7b0c643c719, 0x6d9ccd05d0000000, + 0x8f7e32ce7bea5c6f, 0xe4820023a2000000, + 0xb35dbf821ae4f38b, 0xdda2802c8a800000, + 0xe0352f62a19e306e, 0xd50b2037ad200000, + 0x8c213d9da502de45, 0x4526f422cc340000, + 0xaf298d050e4395d6, 0x9670b12b7f410000, + 0xdaf3f04651d47b4c, 0x3c0cdd765f114000, + 0x88d8762bf324cd0f, 0xa5880a69fb6ac800, + 0xab0e93b6efee0053, 0x8eea0d047a457a00, + 0xd5d238a4abe98068, 0x72a4904598d6d880, + 0x85a36366eb71f041, 0x47a6da2b7f864750, + 0xa70c3c40a64e6c51, 0x999090b65f67d924, + 0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d, + 0x82818f1281ed449f, 0xbff8f10e7a8921a4, + 0xa321f2d7226895c7, 0xaff72d52192b6a0d, + 0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490, + 0xfee50b7025c36a08, 0x2f236d04753d5b4, + 0x9f4f2726179a2245, 0x1d762422c946590, + 0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5, + 0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2, + 0x9b934c3b330c8577, 0x63cc55f49f88eb2f, + 0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb, + 0xf316271c7fc3908a, 0x8bef464e3945ef7a, + 0x97edd871cfda3a56, 0x97758bf0e3cbb5ac, + 0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317, + 0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd, + 0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a, + 0xb975d6b6ee39e436, 0xb3e2fd538e122b44, + 0xe7d34c64a9c85d44, 0x60dbbca87196b616, + 0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd, + 0xb51d13aea4a488dd, 0x6babab6398bdbe41, + 0xe264589a4dcdab14, 0xc696963c7eed2dd1, + 0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2, + 0xb0de65388cc8ada8, 0x3b25a55f43294bcb, + 0xdd15fe86affad912, 0x49ef0eb713f39ebe, + 0x8a2dbf142dfcc7ab, 0x6e3569326c784337, + 0xacb92ed9397bf996, 0x49c2c37f07965404, + 0xd7e77a8f87daf7fb, 0xdc33745ec97be906, + 0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3, + 0xa8acd7c0222311bc, 0xc40832ea0d68ce0c, + 0xd2d80db02aabd62b, 0xf50a3fa490c30190, + 0x83c7088e1aab65db, 0x792667c6da79e0fa, + 0xa4b8cab1a1563f52, 0x577001b891185938, + 0xcde6fd5e09abcf26, 0xed4c0226b55e6f86, + 0x80b05e5ac60b6178, 0x544f8158315b05b4, + 0xa0dc75f1778e39d6, 0x696361ae3db1c721, + 0xc913936dd571c84c, 0x3bc3a19cd1e38e9, + 0xfb5878494ace3a5f, 0x4ab48a04065c723, + 0x9d174b2dcec0e47b, 0x62eb0d64283f9c76, + 0xc45d1df942711d9a, 0x3ba5d0bd324f8394, + 0xf5746577930d6500, 0xca8f44ec7ee36479, + 0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb, + 0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e, + 0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e, + 0x95d04aee3b80ece5, 0xbba1f1d158724a12, + 0xbb445da9ca61281f, 0x2a8a6e45ae8edc97, + 0xea1575143cf97226, 0xf52d09d71a3293bd, + 0x924d692ca61be758, 0x593c2626705f9c56, + 0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c, + 0xe498f455c38b997a, 0xb6dfb9c0f956447, + 0x8edf98b59a373fec, 0x4724bd4189bd5eac, + 0xb2977ee300c50fe7, 0x58edec91ec2cb657, + 0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed, + 0x8b865b215899f46c, 0xbd79e0d20082ee74, + 0xae67f1e9aec07187, 0xecd8590680a3aa11, + 0xda01ee641a708de9, 0xe80e6f4820cc9495, + 0x884134fe908658b2, 0x3109058d147fdcdd, + 0xaa51823e34a7eede, 0xbd4b46f0599fd415, + 0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a, + 0x850fadc09923329e, 0x3e2cf6bc604ddb0, + 0xa6539930bf6bff45, 0x84db8346b786151c, + 0xcfe87f7cef46ff16, 0xe612641865679a63, + 0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e, + 0xa26da3999aef7749, 0xe3be5e330f38f09d, + 0xcb090c8001ab551c, 0x5cadf5bfd3072cc5, + 0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6, + 0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa, + 0xc646d63501a1511d, 0xb281e1fd541501b8, + 0xf7d88bc24209a565, 0x1f225a7ca91a4226, + 0x9ae757596946075f, 0x3375788de9b06958, + 0xc1a12d2fc3978937, 0x52d6b1641c83ae, + 0xf209787bb47d6b84, 0xc0678c5dbd23a49a, + 0x9745eb4d50ce6332, 0xf840b7ba963646e0, + 0xbd176620a501fbff, 0xb650e5a93bc3d898, + 0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe, + 0x93ba47c980e98cdf, 0xc66f336c36b10137, + 0xb8a8d9bbe123f017, 0xb80b0047445d4184, + 0xe6d3102ad96cec1d, 0xa60dc059157491e5, + 0x9043ea1ac7e41392, 0x87c89837ad68db2f, + 0xb454e4a179dd1877, 0x29babe4598c311fb, + 0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a, + 0x8ce2529e2734bb1d, 0x1899e4a65f58660c, + 0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f, + 0xdc21a1171d42645d, 0x76707543f4fa1f73, + 0x899504ae72497eba, 0x6a06494a791c53a8, + 0xabfa45da0edbde69, 0x487db9d17636892, + 0xd6f8d7509292d603, 0x45a9d2845d3c42b6, + 0x865b86925b9bc5c2, 0xb8a2392ba45a9b2, + 0xa7f26836f282b732, 0x8e6cac7768d7141e, + 0xd1ef0244af2364ff, 0x3207d795430cd926, + 0x8335616aed761f1f, 0x7f44e6bd49e807b8, + 0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6, + 0xcd036837130890a1, 0x36dba887c37a8c0f, + 0x802221226be55a64, 0xc2494954da2c9789, + 0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c, + 0xc83553c5c8965d3d, 0x6f92829494e5acc7, + 0xfa42a8b73abbf48c, 0xcb772339ba1f17f9, + 0x9c69a97284b578d7, 0xff2a760414536efb, + 0xc38413cf25e2d70d, 0xfef5138519684aba, + 0xf46518c2ef5b8cd1, 0x7eb258665fc25d69, + 0x98bf2f79d5993802, 0xef2f773ffbd97a61, + 0xbeeefb584aff8603, 0xaafb550ffacfd8fa, + 0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38, + 0x952ab45cfa97a0b2, 0xdd945a747bf26183, + 0xba756174393d88df, 0x94f971119aeef9e4, + 0xe912b9d1478ceb17, 0x7a37cd5601aab85d, + 0x91abb422ccb812ee, 0xac62e055c10ab33a, + 0xb616a12b7fe617aa, 0x577b986b314d6009, + 0xe39c49765fdf9d94, 0xed5a7e85fda0b80b, + 0x8e41ade9fbebc27d, 0x14588f13be847307, + 0xb1d219647ae6b31c, 0x596eb2d8ae258fc8, + 0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb, + 0x8aec23d680043bee, 0x25de7bb9480d5854, + 0xada72ccc20054ae9, 0xaf561aa79a10ae6a, + 0xd910f7ff28069da4, 0x1b2ba1518094da04, + 0x87aa9aff79042286, 0x90fb44d2f05d0842, + 0xa99541bf57452b28, 0x353a1607ac744a53, + 0xd3fa922f2d1675f2, 0x42889b8997915ce8, + 0x847c9b5d7c2e09b7, 0x69956135febada11, + 0xa59bc234db398c25, 0x43fab9837e699095, + 0xcf02b2c21207ef2e, 0x94f967e45e03f4bb, + 0x8161afb94b44f57d, 0x1d1be0eebac278f5, + 0xa1ba1ba79e1632dc, 0x6462d92a69731732, + 0xca28a291859bbf93, 0x7d7b8f7503cfdcfe, + 0xfcb2cb35e702af78, 0x5cda735244c3d43e, + 0x9defbf01b061adab, 0x3a0888136afa64a7, + 0xc56baec21c7a1916, 0x88aaa1845b8fdd0, + 0xf6c69a72a3989f5b, 0x8aad549e57273d45, + 0x9a3c2087a63f6399, 0x36ac54e2f678864b, + 0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd, + 0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5, + 0x969eb7c47859e743, 0x9f644ae5a4b1b325, + 0xbc4665b596706114, 0x873d5d9f0dde1fee, + 0xeb57ff22fc0c7959, 0xa90cb506d155a7ea, + 0x9316ff75dd87cbd8, 0x9a7f12442d588f2, + 0xb7dcbf5354e9bece, 0xc11ed6d538aeb2f, + 0xe5d3ef282a242e81, 0x8f1668c8a86da5fa, + 0x8fa475791a569d10, 0xf96e017d694487bc, + 0xb38d92d760ec4455, 0x37c981dcc395a9ac, + 0xe070f78d3927556a, 0x85bbe253f47b1417, + 0x8c469ab843b89562, 0x93956d7478ccec8e, + 0xaf58416654a6babb, 0x387ac8d1970027b2, + 0xdb2e51bfe9d0696a, 0x6997b05fcc0319e, + 0x88fcf317f22241e2, 0x441fece3bdf81f03, + 0xab3c2fddeeaad25a, 0xd527e81cad7626c3, + 0xd60b3bd56a5586f1, 0x8a71e223d8d3b074, + 0x85c7056562757456, 0xf6872d5667844e49, + 0xa738c6bebb12d16c, 0xb428f8ac016561db, + 0xd106f86e69d785c7, 0xe13336d701beba52, + 0x82a45b450226b39c, 0xecc0024661173473, + 0xa34d721642b06084, 0x27f002d7f95d0190, + 0xcc20ce9bd35c78a5, 0x31ec038df7b441f4, + 0xff290242c83396ce, 0x7e67047175a15271, + 0x9f79a169bd203e41, 0xf0062c6e984d386, + 0xc75809c42c684dd1, 0x52c07b78a3e60868, + 0xf92e0c3537826145, 0xa7709a56ccdf8a82, + 0x9bbcc7a142b17ccb, 0x88a66076400bb691, + 0xc2abf989935ddbfe, 0x6acff893d00ea435, + 0xf356f7ebf83552fe, 0x583f6b8c4124d43, + 0x98165af37b2153de, 0xc3727a337a8b704a, + 0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c, + 0xeda2ee1c7064130c, 0x1162def06f79df73, + 0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8, + 0xb9a74a0637ce2ee1, 0x6d953e2bd7173692, + 0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437, + 0x910ab1d4db9914a0, 0x1d9c9892400a22a2, + 0xb54d5e4a127f59c8, 0x2503beb6d00cab4b, + 0xe2a0b5dc971f303a, 0x2e44ae64840fd61d, + 0x8da471a9de737e24, 0x5ceaecfed289e5d2, + 0xb10d8e1456105dad, 0x7425a83e872c5f47, + 0xdd50f1996b947518, 0xd12f124e28f77719, + 0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f, + 0xace73cbfdc0bfb7b, 0x636cc64d1001550b, + 0xd8210befd30efa5a, 0x3c47f7e05401aa4e, + 0x8714a775e3e95c78, 0x65acfaec34810a71, + 0xa8d9d1535ce3b396, 0x7f1839a741a14d0d, + 0xd31045a8341ca07c, 0x1ede48111209a050, + 0x83ea2b892091e44d, 0x934aed0aab460432, + 0xa4e4b66b68b65d60, 0xf81da84d5617853f, + 0xce1de40642e3f4b9, 0x36251260ab9d668e, + 0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019, + 0xa1075a24e4421730, 0xb24cf65b8612f81f, + 0xc94930ae1d529cfc, 0xdee033f26797b627, + 0xfb9b7cd9a4a7443c, 0x169840ef017da3b1, + 0x9d412e0806e88aa5, 0x8e1f289560ee864e, + 0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2, + 0xf5b5d7ec8acb58a2, 0xae10af696774b1db, + 0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29, + 0xbff610b0cc6edd3f, 0x17fd090a58d32af3, + 0xeff394dcff8a948e, 0xddfc4b4cef07f5b0, + 0x95f83d0a1fb69cd9, 0x4abdaf101564f98e, + 0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1, + 0xea53df5fd18d5513, 0x84c86189216dc5ed, + 0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4, + 0xb7118682dbb66a77, 0x3fbc8c33221dc2a1, + 0xe4d5e82392a40515, 0xfabaf3feaa5334a, + 0x8f05b1163ba6832d, 0x29cb4d87f2a7400e, + 0xb2c71d5bca9023f8, 0x743e20e9ef511012, + 0xdf78e4b2bd342cf6, 0x914da9246b255416, + 0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e, + 0xae9672aba3d0c320, 0xa184ac2473b529b1, + 0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e, + 0x8865899617fb1871, 0x7e2fa67c7a658892, + 0xaa7eebfb9df9de8d, 0xddbb901b98feeab7, + 0xd51ea6fa85785631, 0x552a74227f3ea565, + 0x8533285c936b35de, 0xd53a88958f87275f, + 0xa67ff273b8460356, 0x8a892abaf368f137, + 0xd01fef10a657842c, 0x2d2b7569b0432d85, + 0x8213f56a67f6b29b, 0x9c3b29620e29fc73, + 0xa298f2c501f45f42, 0x8349f3ba91b47b8f, + 0xcb3f2f7642717713, 0x241c70a936219a73, + 0xfe0efb53d30dd4d7, 0xed238cd383aa0110, + 0x9ec95d1463e8a506, 0xf4363804324a40aa, + 0xc67bb4597ce2ce48, 0xb143c6053edcd0d5, + 0xf81aa16fdc1b81da, 0xdd94b7868e94050a, + 0x9b10a4e5e9913128, 0xca7cf2b4191c8326, + 0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0, + 0xf24a01a73cf2dccf, 0xbc633b39673c8cec, + 0x976e41088617ca01, 0xd5be0503e085d813, + 0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18, + 0xec9c459d51852ba2, 0xddf8e7d60ed1219e, + 0x93e1ab8252f33b45, 0xcabb90e5c942b503, + 0xb8da1662e7b00a17, 0x3d6a751f3b936243, + 0xe7109bfba19c0c9d, 0xcc512670a783ad4, + 0x906a617d450187e2, 0x27fb2b80668b24c5, + 0xb484f9dc9641e9da, 0xb1f9f660802dedf6, + 0xe1a63853bbd26451, 0x5e7873f8a0396973, + 0x8d07e33455637eb2, 0xdb0b487b6423e1e8, + 0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62, + 0xdc5c5301c56b75f7, 0x7641a140cc7810fb, + 0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d, + 0xac2820d9623bf429, 0x546345fa9fbdcd44, + 0xd732290fbacaf133, 0xa97c177947ad4095, + 0x867f59a9d4bed6c0, 0x49ed8eabcccc485d, + 0xa81f301449ee8c70, 0x5c68f256bfff5a74, + 0xd226fc195c6a2f8c, 0x73832eec6fff3111, + 0x83585d8fd9c25db7, 0xc831fd53c5ff7eab, + 0xa42e74f3d032f525, 0xba3e7ca8b77f5e55, + 0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb, + 0x80444b5e7aa7cf85, 0x7980d163cf5b81b3, + 0xa0555e361951c366, 0xd7e105bcc332621f, + 0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7, + 0xfa856334878fc150, 0xb14f98f6f0feb951, + 0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3, + 0xc3b8358109e84f07, 0xa862f80ec4700c8, + 0xf4a642e14c6262c8, 0xcd27bb612758c0fa, + 0x98e7e9cccfbd7dbd, 0x8038d51cb897789c, + 0xbf21e44003acdd2c, 0xe0470a63e6bd56c3, + 0xeeea5d5004981478, 0x1858ccfce06cac74, + 0x95527a5202df0ccb, 0xf37801e0c43ebc8, + 0xbaa718e68396cffd, 0xd30560258f54e6ba, + 0xe950df20247c83fd, 0x47c6b82ef32a2069, + 0x91d28b7416cdd27e, 0x4cdc331d57fa5441, + 0xb6472e511c81471d, 0xe0133fe4adf8e952, + 0xe3d8f9e563a198e5, 0x58180fddd97723a6, + 0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648, + }; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template +constexpr uint64_t + powers_template::power_of_five_128[number_of_entries]; + +#endif + +using powers = powers_template<>; + +} // namespace fast_float + +#endif + +#ifndef FASTFLOAT_DECIMAL_TO_BINARY_H +#define FASTFLOAT_DECIMAL_TO_BINARY_H + +#include +#include +#include +#include +#include +#include + +namespace fast_float { + +// This will compute or rather approximate w * 5**q and return a pair of 64-bit +// words approximating the result, with the "high" part corresponding to the +// most significant bits and the low part corresponding to the least significant +// bits. +// +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 +compute_product_approximation(int64_t q, uint64_t w) { + const int index = 2 * int(q - powers::smallest_power_of_five); + // For small values of q, e.g., q in [0,27], the answer is always exact + // because The line value128 firstproduct = full_multiplication(w, + // power_of_five_128[index]); gives the exact answer. + value128 firstproduct = + full_multiplication(w, powers::power_of_five_128[index]); + static_assert((bit_precision >= 0) && (bit_precision <= 64), + " precision should be in (0,64]"); + constexpr uint64_t precision_mask = + (bit_precision < 64) ? (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision) + : uint64_t(0xFFFFFFFFFFFFFFFF); + if ((firstproduct.high & precision_mask) == + precision_mask) { // could further guard with (lower + w < lower) + // regarding the second product, we only need secondproduct.high, but our + // expectation is that the compiler will optimize this extra work away if + // needed. + value128 secondproduct = + full_multiplication(w, powers::power_of_five_128[index + 1]); + firstproduct.low += secondproduct.high; + if (secondproduct.high > firstproduct.low) { + firstproduct.high++; + } + } + return firstproduct; +} + +namespace detail { +/** + * For q in (0,350), we have that + * f = (((152170 + 65536) * q ) >> 16); + * is equal to + * floor(p) + q + * where + * p = log(5**q)/log(2) = q * log(5)/log(2) + * + * For negative values of q in (-400,0), we have that + * f = (((152170 + 65536) * q ) >> 16); + * is equal to + * -ceil(p) + q + * where + * p = log(5**-q)/log(2) = -q * log(5)/log(2) + */ +constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept { + return (((152170 + 65536) * q) >> 16) + 63; +} +} // namespace detail + +// create an adjusted mantissa, biased by the invalid power2 +// for significant digits already multiplied by 10 ** q. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa +compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept { + int hilz = int(w >> 63) ^ 1; + adjusted_mantissa answer; + answer.mantissa = w << hilz; + int bias = binary::mantissa_explicit_bits() - binary::minimum_exponent(); + answer.power2 = int32_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + + invalid_am_bias); + return answer; +} + +// w * 10 ** q, without rounding the representation up. +// the power2 in the exponent will be adjusted by invalid_am_bias. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +compute_error(int64_t q, uint64_t w) noexcept { + int lz = leading_zeroes(w); + w <<= lz; + value128 product = + compute_product_approximation(q, w); + return compute_error_scaled(q, product.high, lz); +} + +// w * 10 ** q +// The returned value should be a valid ieee64 number that simply need to be +// packed. However, in some very rare cases, the computation will fail. In such +// cases, we return an adjusted_mantissa with a negative power of 2: the caller +// should recompute in such cases. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +compute_float(int64_t q, uint64_t w) noexcept { + adjusted_mantissa answer; + if ((w == 0) || (q < binary::smallest_power_of_ten())) { + answer.power2 = 0; + answer.mantissa = 0; + // result should be zero + return answer; + } + if (q > binary::largest_power_of_ten()) { + // we want to get infinity: + answer.power2 = binary::infinite_power(); + answer.mantissa = 0; + return answer; + } + // At this point in time q is in [powers::smallest_power_of_five, + // powers::largest_power_of_five]. + + // We want the most significant bit of i to be 1. Shift if needed. + int lz = leading_zeroes(w); + w <<= lz; + + // The required precision is binary::mantissa_explicit_bits() + 3 because + // 1. We need the implicit bit + // 2. We need an extra bit for rounding purposes + // 3. We might lose a bit due to the "upperbit" routine (result too small, + // requiring a shift) + + value128 product = + compute_product_approximation(q, w); + // The computed 'product' is always sufficient. + // Mathematical proof: + // Noble Mushtak and Daniel Lemire, Fast Number Parsing Without Fallback (to + // appear) See script/mushtak_lemire.py + + // The "compute_product_approximation" function can be slightly slower than a + // branchless approach: value128 product = compute_product(q, w); but in + // practice, we can win big with the compute_product_approximation if its + // additional branch is easily predicted. Which is best is data specific. + int upperbit = int(product.high >> 63); + int shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + + answer.mantissa = product.high >> shift; + + answer.power2 = int32_t(detail::power(int32_t(q)) + upperbit - lz - + binary::minimum_exponent()); + if (answer.power2 <= 0) { // we have a subnormal? + // Here have that answer.power2 <= 0 so -answer.power2 >= 0 + if (-answer.power2 + 1 >= + 64) { // if we have more than 64 bits below the minimum exponent, you + // have a zero for sure. + answer.power2 = 0; + answer.mantissa = 0; + // result should be zero + return answer; + } + // next line is safe because -answer.power2 + 1 < 64 + answer.mantissa >>= -answer.power2 + 1; + // Thankfully, we can't have both "round-to-even" and subnormals because + // "round-to-even" only occurs for powers close to 0. + answer.mantissa += (answer.mantissa & 1); // round up + answer.mantissa >>= 1; + // There is a weird scenario where we don't have a subnormal but just. + // Suppose we start with 2.2250738585072013e-308, we end up + // with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal + // whereas 0x40000000000000 x 2^-1023-53 is normal. Now, we need to round + // up 0x3fffffffffffff x 2^-1023-53 and once we do, we are no longer + // subnormal, but we can only know this after rounding. + // So we only declare a subnormal if we are smaller than the threshold. + answer.power2 = + (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) + ? 0 + : 1; + return answer; + } + + // usually, we round *up*, but if we fall right in between and and we have an + // even basis, we need to round down + // We are only concerned with the cases where 5**q fits in single 64-bit word. + if ((product.low <= 1) && (q >= binary::min_exponent_round_to_even()) && + (q <= binary::max_exponent_round_to_even()) && + ((answer.mantissa & 3) == 1)) { // we may fall between two floats! + // To be in-between two floats we need that in doing + // answer.mantissa = product.high >> (upperbit + 64 - + // binary::mantissa_explicit_bits() - 3); + // ... we dropped out only zeroes. But if this happened, then we can go + // back!!! + if ((answer.mantissa << shift) == product.high) { + answer.mantissa &= ~uint64_t(1); // flip it so that we do not round up + } + } + + answer.mantissa += (answer.mantissa & 1); // round up + answer.mantissa >>= 1; + if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) { + answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits()); + answer.power2++; // undo previous addition + } + + answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits()); + if (answer.power2 >= binary::infinite_power()) { // infinity + answer.power2 = binary::infinite_power(); + answer.mantissa = 0; + } + return answer; +} + +} // namespace fast_float + +#endif + +#ifndef FASTFLOAT_BIGINT_H +#define FASTFLOAT_BIGINT_H + +#include +#include +#include +#include + + +namespace fast_float { + +// the limb width: we want efficient multiplication of double the bits in +// limb, or for 64-bit limbs, at least 64-bit multiplication where we can +// extract the high and low parts efficiently. this is every 64-bit +// architecture except for sparc, which emulates 128-bit multiplication. +// we might have platforms where `CHAR_BIT` is not 8, so let's avoid +// doing `8 * sizeof(limb)`. +#if defined(FASTFLOAT_64BIT) && !defined(__sparc) +#define FASTFLOAT_64BIT_LIMB 1 +typedef uint64_t limb; +constexpr size_t limb_bits = 64; +#else +#define FASTFLOAT_32BIT_LIMB +typedef uint32_t limb; +constexpr size_t limb_bits = 32; +#endif + +typedef span limb_span; + +// number of bits in a bigint. this needs to be at least the number +// of bits required to store the largest bigint, which is +// `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or +// ~3600 bits, so we round to 4000. +constexpr size_t bigint_bits = 4000; +constexpr size_t bigint_limbs = bigint_bits / limb_bits; + +// vector-like type that is allocated on the stack. the entire +// buffer is pre-allocated, and only the length changes. +template struct stackvec { + limb data[size]; + // we never need more than 150 limbs + uint16_t length{0}; + + stackvec() = default; + stackvec(const stackvec &) = delete; + stackvec &operator=(const stackvec &) = delete; + stackvec(stackvec &&) = delete; + stackvec &operator=(stackvec &&other) = delete; + + // create stack vector from existing limb span. + FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) { + FASTFLOAT_ASSERT(try_extend(s)); + } + + FASTFLOAT_CONSTEXPR14 limb &operator[](size_t index) noexcept { + FASTFLOAT_DEBUG_ASSERT(index < length); + return data[index]; + } + FASTFLOAT_CONSTEXPR14 const limb &operator[](size_t index) const noexcept { + FASTFLOAT_DEBUG_ASSERT(index < length); + return data[index]; + } + // index from the end of the container + FASTFLOAT_CONSTEXPR14 const limb &rindex(size_t index) const noexcept { + FASTFLOAT_DEBUG_ASSERT(index < length); + size_t rindex = length - index - 1; + return data[rindex]; + } + + // set the length, without bounds checking. + FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept { + length = uint16_t(len); + } + constexpr size_t len() const noexcept { return length; } + constexpr bool is_empty() const noexcept { return length == 0; } + constexpr size_t capacity() const noexcept { return size; } + // append item to vector, without bounds checking + FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept { + data[length] = value; + length++; + } + // append item to vector, returning if item was added + FASTFLOAT_CONSTEXPR14 bool try_push(limb value) noexcept { + if (len() < capacity()) { + push_unchecked(value); + return true; + } else { + return false; + } + } + // add items to the vector, from a span, without bounds checking + FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept { + limb *ptr = data + length; + std::copy_n(s.ptr, s.len(), ptr); + set_len(len() + s.len()); + } + // try to add items to the vector, returning if items were added + FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept { + if (len() + s.len() <= capacity()) { + extend_unchecked(s); + return true; + } else { + return false; + } + } + // resize the vector, without bounds checking + // if the new size is longer than the vector, assign value to each + // appended item. + FASTFLOAT_CONSTEXPR20 + void resize_unchecked(size_t new_len, limb value) noexcept { + if (new_len > len()) { + size_t count = new_len - len(); + limb *first = data + len(); + limb *last = first + count; + ::std::fill(first, last, value); + set_len(new_len); + } else { + set_len(new_len); + } + } + // try to resize the vector, returning if the vector was resized. + FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept { + if (new_len > capacity()) { + return false; + } else { + resize_unchecked(new_len, value); + return true; + } + } + // check if any limbs are non-zero after the given index. + // this needs to be done in reverse order, since the index + // is relative to the most significant limbs. + FASTFLOAT_CONSTEXPR14 bool nonzero(size_t index) const noexcept { + while (index < len()) { + if (rindex(index) != 0) { + return true; + } + index++; + } + return false; + } + // normalize the big integer, so most-significant zero limbs are removed. + FASTFLOAT_CONSTEXPR14 void normalize() noexcept { + while (len() > 0 && rindex(0) == 0) { + length--; + } + } +}; + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t +empty_hi64(bool &truncated) noexcept { + truncated = false; + return 0; +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +uint64_hi64(uint64_t r0, bool &truncated) noexcept { + truncated = false; + int shl = leading_zeroes(r0); + return r0 << shl; +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +uint64_hi64(uint64_t r0, uint64_t r1, bool &truncated) noexcept { + int shl = leading_zeroes(r0); + if (shl == 0) { + truncated = r1 != 0; + return r0; + } else { + int shr = 64 - shl; + truncated = (r1 << shl) != 0; + return (r0 << shl) | (r1 >> shr); + } +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +uint32_hi64(uint32_t r0, bool &truncated) noexcept { + return uint64_hi64(r0, truncated); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +uint32_hi64(uint32_t r0, uint32_t r1, bool &truncated) noexcept { + uint64_t x0 = r0; + uint64_t x1 = r1; + return uint64_hi64((x0 << 32) | x1, truncated); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool &truncated) noexcept { + uint64_t x0 = r0; + uint64_t x1 = r1; + uint64_t x2 = r2; + return uint64_hi64(x0, (x1 << 32) | x2, truncated); +} + +// add two small integers, checking for overflow. +// we want an efficient operation. for msvc, where +// we don't have built-in intrinsics, this is still +// pretty fast. +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb +scalar_add(limb x, limb y, bool &overflow) noexcept { + limb z; +// gcc and clang +#if defined(__has_builtin) +#if __has_builtin(__builtin_add_overflow) + if (!cpp20_and_in_constexpr()) { + overflow = __builtin_add_overflow(x, y, &z); + return z; + } +#endif +#endif + + // generic, this still optimizes correctly on MSVC. + z = x + y; + overflow = z < x; + return z; +} + +// multiply two small integers, getting both the high and low bits. +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb +scalar_mul(limb x, limb y, limb &carry) noexcept { +#ifdef FASTFLOAT_64BIT_LIMB +#if defined(__SIZEOF_INT128__) + // GCC and clang both define it as an extension. + __uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry); + carry = limb(z >> limb_bits); + return limb(z); +#else + // fallback, no native 128-bit integer multiplication with carry. + // on msvc, this optimizes identically, somehow. + value128 z = full_multiplication(x, y); + bool overflow; + z.low = scalar_add(z.low, carry, overflow); + z.high += uint64_t(overflow); // cannot overflow + carry = z.high; + return z.low; +#endif +#else + uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry); + carry = limb(z >> limb_bits); + return limb(z); +#endif +} + +// add scalar value to bigint starting from offset. +// used in grade school multiplication +template +inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, + size_t start) noexcept { + size_t index = start; + limb carry = y; + bool overflow; + while (carry != 0 && index < vec.len()) { + vec[index] = scalar_add(vec[index], carry, overflow); + carry = limb(overflow); + index += 1; + } + if (carry != 0) { + FASTFLOAT_TRY(vec.try_push(carry)); + } + return true; +} + +// add scalar value to bigint. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +small_add(stackvec &vec, limb y) noexcept { + return small_add_from(vec, y, 0); +} + +// multiply bigint by scalar value. +template +inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, + limb y) noexcept { + limb carry = 0; + for (size_t index = 0; index < vec.len(); index++) { + vec[index] = scalar_mul(vec[index], y, carry); + } + if (carry != 0) { + FASTFLOAT_TRY(vec.try_push(carry)); + } + return true; +} + +// add bigint to bigint starting from index. +// used in grade school multiplication +template +FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, + size_t start) noexcept { + // the effective x buffer is from `xstart..x.len()`, so exit early + // if we can't get that current range. + if (x.len() < start || y.len() > x.len() - start) { + FASTFLOAT_TRY(x.try_resize(y.len() + start, 0)); + } + + bool carry = false; + for (size_t index = 0; index < y.len(); index++) { + limb xi = x[index + start]; + limb yi = y[index]; + bool c1 = false; + bool c2 = false; + xi = scalar_add(xi, yi, c1); + if (carry) { + xi = scalar_add(xi, 1, c2); + } + x[index + start] = xi; + carry = c1 | c2; + } + + // handle overflow + if (carry) { + FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start)); + } + return true; +} + +// add bigint to bigint. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +large_add_from(stackvec &x, limb_span y) noexcept { + return large_add_from(x, y, 0); +} + +// grade-school multiplication algorithm +template +FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { + limb_span xs = limb_span(x.data, x.len()); + stackvec z(xs); + limb_span zs = limb_span(z.data, z.len()); + + if (y.len() != 0) { + limb y0 = y[0]; + FASTFLOAT_TRY(small_mul(x, y0)); + for (size_t index = 1; index < y.len(); index++) { + limb yi = y[index]; + stackvec zi; + if (yi != 0) { + // re-use the same buffer throughout + zi.set_len(0); + FASTFLOAT_TRY(zi.try_extend(zs)); + FASTFLOAT_TRY(small_mul(zi, yi)); + limb_span zis = limb_span(zi.data, zi.len()); + FASTFLOAT_TRY(large_add_from(x, zis, index)); + } + } + } + + x.normalize(); + return true; +} + +// grade-school multiplication algorithm +template +FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec &x, limb_span y) noexcept { + if (y.len() == 1) { + FASTFLOAT_TRY(small_mul(x, y[0])); + } else { + FASTFLOAT_TRY(long_mul(x, y)); + } + return true; +} + +template struct pow5_tables { + static constexpr uint32_t large_step = 135; + static constexpr uint64_t small_power_of_5[] = { + 1UL, + 5UL, + 25UL, + 125UL, + 625UL, + 3125UL, + 15625UL, + 78125UL, + 390625UL, + 1953125UL, + 9765625UL, + 48828125UL, + 244140625UL, + 1220703125UL, + 6103515625UL, + 30517578125UL, + 152587890625UL, + 762939453125UL, + 3814697265625UL, + 19073486328125UL, + 95367431640625UL, + 476837158203125UL, + 2384185791015625UL, + 11920928955078125UL, + 59604644775390625UL, + 298023223876953125UL, + 1490116119384765625UL, + 7450580596923828125UL, + }; +#ifdef FASTFLOAT_64BIT_LIMB + constexpr static limb large_power_of_5[] = { + 1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL, + 10482974169319127550UL, 198276706040285095UL}; +#else + constexpr static limb large_power_of_5[] = { + 4279965485U, 329373468U, 4020270615U, 2137533757U, 4287402176U, + 1057042919U, 1071430142U, 2440757623U, 381945767U, 46164893U}; +#endif +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template constexpr uint32_t pow5_tables::large_step; + +template constexpr uint64_t pow5_tables::small_power_of_5[]; + +template constexpr limb pow5_tables::large_power_of_5[]; + +#endif + +// big integer type. implements a small subset of big integer +// arithmetic, using simple algorithms since asymptotically +// faster algorithms are slower for a small number of limbs. +// all operations assume the big-integer is normalized. +struct bigint : pow5_tables<> { + // storage of the limbs, in little-endian order. + stackvec vec; + + FASTFLOAT_CONSTEXPR20 bigint() : vec() {} + bigint(const bigint &) = delete; + bigint &operator=(const bigint &) = delete; + bigint(bigint &&) = delete; + bigint &operator=(bigint &&other) = delete; + + FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) : vec() { +#ifdef FASTFLOAT_64BIT_LIMB + vec.push_unchecked(value); +#else + vec.push_unchecked(uint32_t(value)); + vec.push_unchecked(uint32_t(value >> 32)); +#endif + vec.normalize(); + } + + // get the high 64 bits from the vector, and if bits were truncated. + // this is to get the significant digits for the float. + FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool &truncated) const noexcept { +#ifdef FASTFLOAT_64BIT_LIMB + if (vec.len() == 0) { + return empty_hi64(truncated); + } else if (vec.len() == 1) { + return uint64_hi64(vec.rindex(0), truncated); + } else { + uint64_t result = uint64_hi64(vec.rindex(0), vec.rindex(1), truncated); + truncated |= vec.nonzero(2); + return result; + } +#else + if (vec.len() == 0) { + return empty_hi64(truncated); + } else if (vec.len() == 1) { + return uint32_hi64(vec.rindex(0), truncated); + } else if (vec.len() == 2) { + return uint32_hi64(vec.rindex(0), vec.rindex(1), truncated); + } else { + uint64_t result = + uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated); + truncated |= vec.nonzero(3); + return result; + } +#endif + } + + // compare two big integers, returning the large value. + // assumes both are normalized. if the return value is + // negative, other is larger, if the return value is + // positive, this is larger, otherwise they are equal. + // the limbs are stored in little-endian order, so we + // must compare the limbs in ever order. + FASTFLOAT_CONSTEXPR20 int compare(const bigint &other) const noexcept { + if (vec.len() > other.vec.len()) { + return 1; + } else if (vec.len() < other.vec.len()) { + return -1; + } else { + for (size_t index = vec.len(); index > 0; index--) { + limb xi = vec[index - 1]; + limb yi = other.vec[index - 1]; + if (xi > yi) { + return 1; + } else if (xi < yi) { + return -1; + } + } + return 0; + } + } + + // shift left each limb n bits, carrying over to the new limb + // returns true if we were able to shift all the digits. + FASTFLOAT_CONSTEXPR20 bool shl_bits(size_t n) noexcept { + // Internally, for each item, we shift left by n, and add the previous + // right shifted limb-bits. + // For example, we transform (for u8) shifted left 2, to: + // b10100100 b01000010 + // b10 b10010001 b00001000 + FASTFLOAT_DEBUG_ASSERT(n != 0); + FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8); + + size_t shl = n; + size_t shr = limb_bits - shl; + limb prev = 0; + for (size_t index = 0; index < vec.len(); index++) { + limb xi = vec[index]; + vec[index] = (xi << shl) | (prev >> shr); + prev = xi; + } + + limb carry = prev >> shr; + if (carry != 0) { + return vec.try_push(carry); + } + return true; + } + + // move the limbs left by `n` limbs. + FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept { + FASTFLOAT_DEBUG_ASSERT(n != 0); + if (n + vec.len() > vec.capacity()) { + return false; + } else if (!vec.is_empty()) { + // move limbs + limb *dst = vec.data + n; + const limb *src = vec.data; + std::copy_backward(src, src + vec.len(), dst + vec.len()); + // fill in empty limbs + limb *first = vec.data; + limb *last = first + n; + ::std::fill(first, last, 0); + vec.set_len(n + vec.len()); + return true; + } else { + return true; + } + } + + // move the limbs left by `n` bits. + FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept { + size_t rem = n % limb_bits; + size_t div = n / limb_bits; + if (rem != 0) { + FASTFLOAT_TRY(shl_bits(rem)); + } + if (div != 0) { + FASTFLOAT_TRY(shl_limbs(div)); + } + return true; + } + + // get the number of leading zeros in the bigint. + FASTFLOAT_CONSTEXPR20 int ctlz() const noexcept { + if (vec.is_empty()) { + return 0; + } else { +#ifdef FASTFLOAT_64BIT_LIMB + return leading_zeroes(vec.rindex(0)); +#else + // no use defining a specialized leading_zeroes for a 32-bit type. + uint64_t r0 = vec.rindex(0); + return leading_zeroes(r0 << 32); +#endif + } + } + + // get the number of bits in the bigint. + FASTFLOAT_CONSTEXPR20 int bit_length() const noexcept { + int lz = ctlz(); + return int(limb_bits * vec.len()) - lz; + } + + FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { return small_mul(vec, y); } + + FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); } + + // multiply as if by 2 raised to a power. + FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept { return shl(exp); } + + // multiply as if by 5 raised to a power. + FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept { + // multiply by a power of 5 + size_t large_length = sizeof(large_power_of_5) / sizeof(limb); + limb_span large = limb_span(large_power_of_5, large_length); + while (exp >= large_step) { + FASTFLOAT_TRY(large_mul(vec, large)); + exp -= large_step; + } +#ifdef FASTFLOAT_64BIT_LIMB + uint32_t small_step = 27; + limb max_native = 7450580596923828125UL; +#else + uint32_t small_step = 13; + limb max_native = 1220703125U; +#endif + while (exp >= small_step) { + FASTFLOAT_TRY(small_mul(vec, max_native)); + exp -= small_step; + } + if (exp != 0) { + // Work around clang bug https://godbolt.org/z/zedh7rrhc + // This is similar to https://github.com/llvm/llvm-project/issues/47746, + // except the workaround described there don't work here + FASTFLOAT_TRY(small_mul( + vec, limb(((void)small_power_of_5[0], small_power_of_5[exp])))); + } + + return true; + } + + // multiply as if by 10 raised to a power. + FASTFLOAT_CONSTEXPR20 bool pow10(uint32_t exp) noexcept { + FASTFLOAT_TRY(pow5(exp)); + return pow2(exp); + } +}; + +} // namespace fast_float + +#endif + +#ifndef FASTFLOAT_DIGIT_COMPARISON_H +#define FASTFLOAT_DIGIT_COMPARISON_H + +#include +#include +#include +#include + + +namespace fast_float { + +// 1e0 to 1e19 +constexpr static uint64_t powers_of_ten_uint64[] = {1UL, + 10UL, + 100UL, + 1000UL, + 10000UL, + 100000UL, + 1000000UL, + 10000000UL, + 100000000UL, + 1000000000UL, + 10000000000UL, + 100000000000UL, + 1000000000000UL, + 10000000000000UL, + 100000000000000UL, + 1000000000000000UL, + 10000000000000000UL, + 100000000000000000UL, + 1000000000000000000UL, + 10000000000000000000UL}; + +// calculate the exponent, in scientific notation, of the number. +// this algorithm is not even close to optimized, but it has no practical +// effect on performance: in order to have a faster algorithm, we'd need +// to slow down performance for faster algorithms, and this is still fast. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t +scientific_exponent(parsed_number_string_t &num) noexcept { + uint64_t mantissa = num.mantissa; + int32_t exponent = int32_t(num.exponent); + while (mantissa >= 10000) { + mantissa /= 10000; + exponent += 4; + } + while (mantissa >= 100) { + mantissa /= 100; + exponent += 2; + } + while (mantissa >= 10) { + mantissa /= 10; + exponent += 1; + } + return exponent; +} + +// this converts a native floating-point number to an extended-precision float. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +to_extended(T value) noexcept { + using equiv_uint = typename binary_format::equiv_uint; + constexpr equiv_uint exponent_mask = binary_format::exponent_mask(); + constexpr equiv_uint mantissa_mask = binary_format::mantissa_mask(); + constexpr equiv_uint hidden_bit_mask = binary_format::hidden_bit_mask(); + + adjusted_mantissa am; + int32_t bias = binary_format::mantissa_explicit_bits() - + binary_format::minimum_exponent(); + equiv_uint bits; +#if FASTFLOAT_HAS_BIT_CAST + bits = std::bit_cast(value); +#else + ::memcpy(&bits, &value, sizeof(T)); +#endif + if ((bits & exponent_mask) == 0) { + // denormal + am.power2 = 1 - bias; + am.mantissa = bits & mantissa_mask; + } else { + // normal + am.power2 = int32_t((bits & exponent_mask) >> + binary_format::mantissa_explicit_bits()); + am.power2 -= bias; + am.mantissa = (bits & mantissa_mask) | hidden_bit_mask; + } + + return am; +} + +// get the extended precision value of the halfway point between b and b+u. +// we are given a native float that represents b, so we need to adjust it +// halfway between b and b+u. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +to_extended_halfway(T value) noexcept { + adjusted_mantissa am = to_extended(value); + am.mantissa <<= 1; + am.mantissa += 1; + am.power2 -= 1; + return am; +} + +// round an extended-precision float to the nearest machine float. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, + callback cb) noexcept { + int32_t mantissa_shift = 64 - binary_format::mantissa_explicit_bits() - 1; + if (-am.power2 >= mantissa_shift) { + // have a denormal float + int32_t shift = -am.power2 + 1; + cb(am, std::min(shift, 64)); + // check for round-up: if rounding-nearest carried us to the hidden bit. + am.power2 = (am.mantissa < + (uint64_t(1) << binary_format::mantissa_explicit_bits())) + ? 0 + : 1; + return; + } + + // have a normal float, use the default shift. + cb(am, mantissa_shift); + + // check for carry + if (am.mantissa >= + (uint64_t(2) << binary_format::mantissa_explicit_bits())) { + am.mantissa = (uint64_t(1) << binary_format::mantissa_explicit_bits()); + am.power2++; + } + + // check for infinite: we could have carried to an infinite power + am.mantissa &= ~(uint64_t(1) << binary_format::mantissa_explicit_bits()); + if (am.power2 >= binary_format::infinite_power()) { + am.power2 = binary_format::infinite_power(); + am.mantissa = 0; + } +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void +round_nearest_tie_even(adjusted_mantissa &am, int32_t shift, + callback cb) noexcept { + const uint64_t mask = (shift == 64) ? UINT64_MAX : (uint64_t(1) << shift) - 1; + const uint64_t halfway = (shift == 0) ? 0 : uint64_t(1) << (shift - 1); + uint64_t truncated_bits = am.mantissa & mask; + bool is_above = truncated_bits > halfway; + bool is_halfway = truncated_bits == halfway; + + // shift digits into position + if (shift == 64) { + am.mantissa = 0; + } else { + am.mantissa >>= shift; + } + am.power2 += shift; + + bool is_odd = (am.mantissa & 1) == 1; + am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above)); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void +round_down(adjusted_mantissa &am, int32_t shift) noexcept { + if (shift == 64) { + am.mantissa = 0; + } else { + am.mantissa >>= shift; + } + am.power2 += shift; +} +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +skip_zeros(UC const *&first, UC const *last) noexcept { + uint64_t val; + while (!cpp20_and_in_constexpr() && + std::distance(first, last) >= int_cmp_len()) { + ::memcpy(&val, first, sizeof(uint64_t)); + if (val != int_cmp_zeros()) { + break; + } + first += int_cmp_len(); + } + while (first != last) { + if (*first != UC('0')) { + break; + } + first++; + } +} + +// determine if any non-zero digits were truncated. +// all characters must be valid digits. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +is_truncated(UC const *first, UC const *last) noexcept { + // do 8-bit optimizations, can just compare to 8 literal 0s. + uint64_t val; + while (!cpp20_and_in_constexpr() && + std::distance(first, last) >= int_cmp_len()) { + ::memcpy(&val, first, sizeof(uint64_t)); + if (val != int_cmp_zeros()) { + return true; + } + first += int_cmp_len(); + } + while (first != last) { + if (*first != UC('0')) { + return true; + } + ++first; + } + return false; +} +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +is_truncated(span s) noexcept { + return is_truncated(s.ptr, s.ptr + s.len()); +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +parse_eight_digits(const UC *&p, limb &value, size_t &counter, + size_t &count) noexcept { + value = value * 100000000 + parse_eight_digits_unrolled(p); + p += 8; + counter += 8; + count += 8; +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void +parse_one_digit(UC const *&p, limb &value, size_t &counter, + size_t &count) noexcept { + value = value * 10 + limb(*p - UC('0')); + p++; + counter++; + count++; +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +add_native(bigint &big, limb power, limb value) noexcept { + big.mul(power); + big.add(value); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +round_up_bigint(bigint &big, size_t &count) noexcept { + // need to round-up the digits, but need to avoid rounding + // ....9999 to ...10000, which could cause a false halfway point. + add_native(big, 10, 1); + count++; +} + +// parse the significant digits into a big integer +template +inline FASTFLOAT_CONSTEXPR20 void +parse_mantissa(bigint &result, parsed_number_string_t &num, + size_t max_digits, size_t &digits) noexcept { + // try to minimize the number of big integer and scalar multiplication. + // therefore, try to parse 8 digits at a time, and multiply by the largest + // scalar value (9 or 19 digits) for each step. + size_t counter = 0; + digits = 0; + limb value = 0; +#ifdef FASTFLOAT_64BIT_LIMB + size_t step = 19; +#else + size_t step = 9; +#endif + + // process all integer digits. + UC const *p = num.integer.ptr; + UC const *pend = p + num.integer.len(); + skip_zeros(p, pend); + // process all digits, in increments of step per loop + while (p != pend) { + while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && + (max_digits - digits >= 8)) { + parse_eight_digits(p, value, counter, digits); + } + while (counter < step && p != pend && digits < max_digits) { + parse_one_digit(p, value, counter, digits); + } + if (digits == max_digits) { + // add the temporary value, then check if we've truncated any digits + add_native(result, limb(powers_of_ten_uint64[counter]), value); + bool truncated = is_truncated(p, pend); + if (num.fraction.ptr != nullptr) { + truncated |= is_truncated(num.fraction); + } + if (truncated) { + round_up_bigint(result, digits); + } + return; + } else { + add_native(result, limb(powers_of_ten_uint64[counter]), value); + counter = 0; + value = 0; + } + } + + // add our fraction digits, if they're available. + if (num.fraction.ptr != nullptr) { + p = num.fraction.ptr; + pend = p + num.fraction.len(); + if (digits == 0) { + skip_zeros(p, pend); + } + // process all digits, in increments of step per loop + while (p != pend) { + while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && + (max_digits - digits >= 8)) { + parse_eight_digits(p, value, counter, digits); + } + while (counter < step && p != pend && digits < max_digits) { + parse_one_digit(p, value, counter, digits); + } + if (digits == max_digits) { + // add the temporary value, then check if we've truncated any digits + add_native(result, limb(powers_of_ten_uint64[counter]), value); + bool truncated = is_truncated(p, pend); + if (truncated) { + round_up_bigint(result, digits); + } + return; + } else { + add_native(result, limb(powers_of_ten_uint64[counter]), value); + counter = 0; + value = 0; + } + } + } + + if (counter != 0) { + add_native(result, limb(powers_of_ten_uint64[counter]), value); + } +} + +template +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept { + FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent))); + adjusted_mantissa answer; + bool truncated; + answer.mantissa = bigmant.hi64(truncated); + int bias = binary_format::mantissa_explicit_bits() - + binary_format::minimum_exponent(); + answer.power2 = bigmant.bit_length() - 64 + bias; + + round(answer, [truncated](adjusted_mantissa &a, int32_t shift) { + round_nearest_tie_even( + a, shift, + [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool { + return is_above || (is_halfway && truncated) || + (is_odd && is_halfway); + }); + }); + + return answer; +} + +// the scaling here is quite simple: we have, for the real digits `m * 10^e`, +// and for the theoretical digits `n * 2^f`. Since `e` is always negative, +// to scale them identically, we do `n * 2^f * 5^-f`, so we now have `m * 2^e`. +// we then need to scale by `2^(f- e)`, and then the two significant digits +// are of the same magnitude. +template +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( + bigint &bigmant, adjusted_mantissa am, int32_t exponent) noexcept { + bigint &real_digits = bigmant; + int32_t real_exp = exponent; + + // get the value of `b`, rounded down, and get a bigint representation of b+h + adjusted_mantissa am_b = am; + // gcc7 buf: use a lambda to remove the noexcept qualifier bug with + // -Wnoexcept-type. + round(am_b, + [](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); }); + T b; + to_float(false, am_b, b); + adjusted_mantissa theor = to_extended_halfway(b); + bigint theor_digits(theor.mantissa); + int32_t theor_exp = theor.power2; + + // scale real digits and theor digits to be same power. + int32_t pow2_exp = theor_exp - real_exp; + uint32_t pow5_exp = uint32_t(-real_exp); + if (pow5_exp != 0) { + FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp)); + } + if (pow2_exp > 0) { + FASTFLOAT_ASSERT(theor_digits.pow2(uint32_t(pow2_exp))); + } else if (pow2_exp < 0) { + FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp))); + } + + // compare digits, and use it to director rounding + int ord = real_digits.compare(theor_digits); + adjusted_mantissa answer = am; + round(answer, [ord](adjusted_mantissa &a, int32_t shift) { + round_nearest_tie_even( + a, shift, [ord](bool is_odd, bool _, bool __) -> bool { + (void)_; // not needed, since we've done our comparison + (void)__; // not needed, since we've done our comparison + if (ord > 0) { + return true; + } else if (ord < 0) { + return false; + } else { + return is_odd; + } + }); + }); + + return answer; +} + +// parse the significant digits as a big integer to unambiguously round the +// the significant digits. here, we are trying to determine how to round +// an extended float representation close to `b+h`, halfway between `b` +// (the float rounded-down) and `b+u`, the next positive float. this +// algorithm is always correct, and uses one of two approaches. when +// the exponent is positive relative to the significant digits (such as +// 1234), we create a big-integer representation, get the high 64-bits, +// determine if any lower bits are truncated, and use that to direct +// rounding. in case of a negative exponent relative to the significant +// digits (such as 1.2345), we create a theoretical representation of +// `b` as a big-integer type, scaled to the same binary exponent as +// the actual digits. we then compare the big integer representations +// of both, and use that to direct rounding. +template +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +digit_comp(parsed_number_string_t &num, adjusted_mantissa am) noexcept { + // remove the invalid exponent bias + am.power2 -= invalid_am_bias; + + int32_t sci_exp = scientific_exponent(num); + size_t max_digits = binary_format::max_digits(); + size_t digits = 0; + bigint bigmant; + parse_mantissa(bigmant, num, max_digits, digits); + // can't underflow, since digits is at most max_digits. + int32_t exponent = sci_exp + 1 - int32_t(digits); + if (exponent >= 0) { + return positive_digit_comp(bigmant, exponent); + } else { + return negative_digit_comp(bigmant, am, exponent); + } +} + +} // namespace fast_float + +#endif + +#ifndef FASTFLOAT_PARSE_NUMBER_H +#define FASTFLOAT_PARSE_NUMBER_H + + +#include +#include +#include +#include +namespace fast_float { + +namespace detail { +/** + * Special case +inf, -inf, nan, infinity, -infinity. + * The case comparisons could be made much faster given that we know that the + * strings a null-free and fixed. + **/ +template +from_chars_result_t + FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last, + T &value, chars_format fmt) noexcept { + from_chars_result_t answer{}; + answer.ptr = first; + answer.ec = std::errc(); // be optimistic + // assume first < last, so dereference without checks; + bool const minusSign = (*first == UC('-')); + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here + if ((*first == UC('-')) || + (uint64_t(fmt & chars_format::allow_leading_plus) && + (*first == UC('+')))) { + ++first; + } + if (last - first >= 3) { + if (fastfloat_strncasecmp(first, str_const_nan(), 3)) { + answer.ptr = (first += 3); + value = minusSign ? -std::numeric_limits::quiet_NaN() + : std::numeric_limits::quiet_NaN(); + // Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, + // C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan). + if (first != last && *first == UC('(')) { + for (UC const *ptr = first + 1; ptr != last; ++ptr) { + if (*ptr == UC(')')) { + answer.ptr = ptr + 1; // valid nan(n-char-seq-opt) + break; + } else if (!((UC('a') <= *ptr && *ptr <= UC('z')) || + (UC('A') <= *ptr && *ptr <= UC('Z')) || + (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_'))) + break; // forbidden char, not nan(n-char-seq-opt) + } + } + return answer; + } + if (fastfloat_strncasecmp(first, str_const_inf(), 3)) { + if ((last - first >= 8) && + fastfloat_strncasecmp(first + 3, str_const_inf() + 3, 5)) { + answer.ptr = first + 8; + } else { + answer.ptr = first + 3; + } + value = minusSign ? -std::numeric_limits::infinity() + : std::numeric_limits::infinity(); + return answer; + } + } + answer.ec = std::errc::invalid_argument; + return answer; +} + +/** + * Returns true if the floating-pointing rounding mode is to 'nearest'. + * It is the default on most system. This function is meant to be inexpensive. + * Credit : @mwalcott3 + */ +fastfloat_really_inline bool rounds_to_nearest() noexcept { + // https://lemire.me/blog/2020/06/26/gcc-not-nearest/ +#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) + return false; +#endif + // See + // A fast function to check your floating-point rounding mode + // https://lemire.me/blog/2022/11/16/a-fast-function-to-check-your-floating-point-rounding-mode/ + // + // This function is meant to be equivalent to : + // prior: #include + // return fegetround() == FE_TONEAREST; + // However, it is expected to be much faster than the fegetround() + // function call. + // + // The volatile keyword prevents the compiler from computing the function + // at compile-time. + // There might be other ways to prevent compile-time optimizations (e.g., + // asm). The value does not need to be std::numeric_limits::min(), any + // small value so that 1 + x should round to 1 would do (after accounting for + // excess precision, as in 387 instructions). + static volatile float fmin = std::numeric_limits::min(); + float fmini = fmin; // we copy it so that it gets loaded at most once. +// +// Explanation: +// Only when fegetround() == FE_TONEAREST do we have that +// fmin + 1.0f == 1.0f - fmin. +// +// FE_UPWARD: +// fmin + 1.0f > 1 +// 1.0f - fmin == 1 +// +// FE_DOWNWARD or FE_TOWARDZERO: +// fmin + 1.0f == 1 +// 1.0f - fmin < 1 +// +// Note: This may fail to be accurate if fast-math has been +// enabled, as rounding conventions may not apply. +#ifdef FASTFLOAT_VISUAL_STUDIO +#pragma warning(push) +// todo: is there a VS warning? +// see +// https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013 +#elif defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfloat-equal" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + return (fmini + 1.0f == 1.0f - fmini); +#ifdef FASTFLOAT_VISUAL_STUDIO +#pragma warning(pop) +#elif defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +} + +} // namespace detail + +template struct from_chars_caller { + template + FASTFLOAT_CONSTEXPR20 static from_chars_result_t + call(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + return from_chars_advanced(first, last, value, options); + } +}; + +#if __STDCPP_FLOAT32_T__ == 1 +template <> struct from_chars_caller { + template + FASTFLOAT_CONSTEXPR20 static from_chars_result_t + call(UC const *first, UC const *last, std::float32_t &value, + parse_options_t options) noexcept { + // if std::float32_t is defined, and we are in C++23 mode; macro set for + // float32; set value to float due to equivalence between float and + // float32_t + float val; + auto ret = from_chars_advanced(first, last, val, options); + value = val; + return ret; + } +}; +#endif + +#if __STDCPP_FLOAT64_T__ == 1 +template <> struct from_chars_caller { + template + FASTFLOAT_CONSTEXPR20 static from_chars_result_t + call(UC const *first, UC const *last, std::float64_t &value, + parse_options_t options) noexcept { + // if std::float64_t is defined, and we are in C++23 mode; macro set for + // float64; set value as double due to equivalence between double and + // float64_t + double val; + auto ret = from_chars_advanced(first, last, val, options); + value = val; + return ret; + } +}; +#endif + +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars(UC const *first, UC const *last, T &value, + chars_format fmt /*= chars_format::general*/) noexcept { + return from_chars_caller::call(first, last, value, + parse_options_t(fmt)); +} + +/** + * This function overload takes parsed_number_string_t structure that is created + * and populated either by from_chars_advanced function taking chars range and + * parsing options or other parsing custom function implemented by user. + */ +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { + + static_assert(is_supported_float_type(), + "only some floating-point types are supported"); + static_assert(is_supported_char_type(), + "only char, wchar_t, char16_t and char32_t are supported"); + + from_chars_result_t answer; + + answer.ec = std::errc(); // be optimistic + answer.ptr = pns.lastmatch; + // The implementation of the Clinger's fast path is convoluted because + // we want round-to-nearest in all cases, irrespective of the rounding mode + // selected on the thread. + // We proceed optimistically, assuming that detail::rounds_to_nearest() + // returns true. + if (binary_format::min_exponent_fast_path() <= pns.exponent && + pns.exponent <= binary_format::max_exponent_fast_path() && + !pns.too_many_digits) { + // Unfortunately, the conventional Clinger's fast path is only possible + // when the system rounds to the nearest float. + // + // We expect the next branch to almost always be selected. + // We could check it first (before the previous branch), but + // there might be performance advantages at having the check + // be last. + if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) { + // We have that fegetround() == FE_TONEAREST. + // Next is Clinger's fast path. + if (pns.mantissa <= binary_format::max_mantissa_fast_path()) { + value = T(pns.mantissa); + if (pns.exponent < 0) { + value = value / binary_format::exact_power_of_ten(-pns.exponent); + } else { + value = value * binary_format::exact_power_of_ten(pns.exponent); + } + if (pns.negative) { + value = -value; + } + return answer; + } + } else { + // We do not have that fegetround() == FE_TONEAREST. + // Next is a modified Clinger's fast path, inspired by Jakub Jelínek's + // proposal + if (pns.exponent >= 0 && + pns.mantissa <= + binary_format::max_mantissa_fast_path(pns.exponent)) { +#if defined(__clang__) || defined(FASTFLOAT_32BIT) + // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD + if (pns.mantissa == 0) { + value = pns.negative ? T(-0.) : T(0.); + return answer; + } +#endif + value = T(pns.mantissa) * + binary_format::exact_power_of_ten(pns.exponent); + if (pns.negative) { + value = -value; + } + return answer; + } + } + } + adjusted_mantissa am = + compute_float>(pns.exponent, pns.mantissa); + if (pns.too_many_digits && am.power2 >= 0) { + if (am != compute_float>(pns.exponent, pns.mantissa + 1)) { + am = compute_error>(pns.exponent, pns.mantissa); + } + } + // If we called compute_float>(pns.exponent, pns.mantissa) + // and we have an invalid power (am.power2 < 0), then we need to go the long + // way around again. This is very uncommon. + if (am.power2 < 0) { + am = digit_comp(pns, am); + } + to_float(pns.negative, am, value); + // Test for over/underflow. + if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || + am.power2 == binary_format::infinite_power()) { + answer.ec = std::errc::result_out_of_range; + } + return answer; +} + +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_float_advanced(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + + static_assert(is_supported_float_type(), + "only some floating-point types are supported"); + static_assert(is_supported_char_type(), + "only char, wchar_t, char16_t and char32_t are supported"); + + chars_format const fmt = detail::adjust_for_feature_macros(options.format); + + from_chars_result_t answer; + if (uint64_t(fmt & chars_format::skip_white_space)) { + while ((first != last) && fast_float::is_space(*first)) { + first++; + } + } + if (first == last) { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } + parsed_number_string_t pns = + parse_number_string(first, last, options); + if (!pns.valid) { + if (uint64_t(fmt & chars_format::no_infnan)) { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } else { + return detail::parse_infnan(first, last, value, fmt); + } + } + + // call overload that takes parsed_number_string_t directly. + return from_chars_advanced(pns, value); +} + +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars(UC const *first, UC const *last, T &value, int base) noexcept { + + static_assert(std::is_integral::value, "only integer types are supported"); + static_assert(is_supported_char_type(), + "only char, wchar_t, char16_t and char32_t are supported"); + + parse_options_t options; + options.base = base; + return from_chars_advanced(first, last, value, options); +} + +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_int_advanced(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + + static_assert(std::is_integral::value, "only integer types are supported"); + static_assert(is_supported_char_type(), + "only char, wchar_t, char16_t and char32_t are supported"); + + chars_format const fmt = detail::adjust_for_feature_macros(options.format); + int const base = options.base; + + from_chars_result_t answer; + if (uint64_t(fmt & chars_format::skip_white_space)) { + while ((first != last) && fast_float::is_space(*first)) { + first++; + } + } + if (first == last || base < 2 || base > 36) { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } + + return parse_int_string(first, last, value, options); +} + +template struct from_chars_advanced_caller { + template + FASTFLOAT_CONSTEXPR20 static from_chars_result_t + call(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + return from_chars_float_advanced(first, last, value, options); + } +}; + +template <> struct from_chars_advanced_caller { + template + FASTFLOAT_CONSTEXPR20 static from_chars_result_t + call(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + return from_chars_int_advanced(first, last, value, options); + } +}; + +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_advanced(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + return from_chars_advanced_caller()>::call( + first, last, value, options); +} + +} // namespace fast_float + +#endif + diff --git a/third-party/folly/CMakeLists.txt b/third-party/folly/CMakeLists.txt index e72203e7677ce6..cbe7facf590c49 100644 --- a/third-party/folly/CMakeLists.txt +++ b/third-party/folly/CMakeLists.txt @@ -9,6 +9,7 @@ get_target_property(LIBSODIUM_LIBRARY libsodium INTERFACE_LINK_LIBRARIES) get_target_property(ZSTD_INCLUDE_DIR zstd INTERFACE_INCLUDE_DIRECTORIES) get_target_property(ZSTD_LIBRARY zstd INTERFACE_LINK_LIBRARIES) get_target_property(JEMALLOC_INCLUDE_DIR jemalloc INTERFACE_INCLUDE_DIRECTORIES) +get_target_property(FAST_FLOAT_INCLUDE_DIR fast_float INTERFACE_INCLUDE_DIRECTORIES) get_target_property(GFLAGS_INCLUDE_DIR gflags INTERFACE_INCLUDE_DIRECTORIES) get_target_property(GFLAGS_LIBRARY gflags INTERFACE_LINK_LIBRARIES) get_target_property(GLOG_INCLUDE_DIR glog INTERFACE_INCLUDE_DIRECTORIES) @@ -72,6 +73,7 @@ ExternalProject_add( -DBoost_DEBUG=1 -DDOUBLE_CONVERSION_INCLUDE_DIR=${DOUBLE_CONVERSION_INCLUDE_DIR} -DDOUBLE_CONVERSION_LIBRARY=${DOUBLE_CONVERSION_LIBRARY} + -DFASTFLOAT_INCLUDE_DIR=${FAST_FLOAT_INCLUDE_DIR} "-Dfmt_DIR=${fmt_DIR}" -DLIBSODIUM_INCLUDE_DIR=${LIBSODIUM_INCLUDE_DIR} -DLIBSODIUM_LIBRARY=${LIBSODIUM_LIBRARY} @@ -92,6 +94,7 @@ set( FOLLY_DEPS boost double-conversion + fast_float fmt libsodium jemalloc From 6eecfdf722ba5394de28c64ded52714cf05cafea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 16:13:35 +0100 Subject: [PATCH 13/72] Don't build squangle and mcrouter for OSS for now --- ci/ubuntu-20.04-focal/debian/rules | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ci/ubuntu-20.04-focal/debian/rules b/ci/ubuntu-20.04-focal/debian/rules index 52bdafec30d41f..60c95ae89f1f77 100644 --- a/ci/ubuntu-20.04-focal/debian/rules +++ b/ci/ubuntu-20.04-focal/debian/rules @@ -9,7 +9,10 @@ override_dh_auto_configure: -Wno-dev \ -DCMAKE_INSTALL_PREFIX=/opt/hhvm/$(DEB_VERSION_UPSTREAM) \ -DMYSQL_UNIX_SOCK_ADDR=/var/run/mysqld/mysqld.sock \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DENABLE_EXTENSION_MCRYPT=Off \ + -DENABLE_EXTENSION_ASYNC_MYSQL=Off \ + -DENABLE_MCROUTER=Off override_dh_auto_build: dh_auto_build -- -j1 hack hack_rust_ffi_bridge_targets hhbc_ast_cbindgen hack_dune From 17e267ba3d828a1e3bbf9509a693ea834a01a9ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 19:15:41 +0100 Subject: [PATCH 14/72] Add missing extension dependencies --- ci/ubuntu-20.04-focal/debian/control | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/ubuntu-20.04-focal/debian/control b/ci/ubuntu-20.04-focal/debian/control index 82d31deabfdb67..c44c34995349f5 100644 --- a/ci/ubuntu-20.04-focal/debian/control +++ b/ci/ubuntu-20.04-focal/debian/control @@ -34,6 +34,7 @@ Build-Depends: libgmp3-dev, libgoogle-glog-dev, libgoogle-perftools-dev, + libheif-dev, libiberty-dev, libiconv-hook-dev, libicu-dev, @@ -41,6 +42,7 @@ Build-Depends: libjemalloc-dev, libkrb5-dev, libldap2-dev, + liblmdb-dev, liblz4-dev, libmagickwand-dev, libmcrypt-dev, From 719fa951d3127837b58745ab296e25579b1b1b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 19:16:24 +0100 Subject: [PATCH 15/72] hack: skip building blake3 hash for now --- hphp/runtime/ext/hash/ext_hash.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hphp/runtime/ext/hash/ext_hash.cpp b/hphp/runtime/ext/hash/ext_hash.cpp index f65d9c98d893f7..3ab429c88f0085 100644 --- a/hphp/runtime/ext/hash/ext_hash.cpp +++ b/hphp/runtime/ext/hash/ext_hash.cpp @@ -37,7 +37,7 @@ #include "hphp/runtime/ext/std/ext_std_file.h" #include "hphp/runtime/ext/string/ext_string.h" #include "hphp/runtime/ext/hash/hash_blake3.h" -#include "hphp/runtime/ext/hash/hash_keyed_blake3.h" +// #include "hphp/runtime/ext/hash/hash_keyed_blake3.h" #include #include @@ -124,7 +124,7 @@ struct HashEngineMapInitializer { HashEngines["sha3-256"] = HashEnginePtr(new hash_keccak( 512, 32)); HashEngines["sha3-384"] = HashEnginePtr(new hash_keccak( 768, 48)); HashEngines["sha3-512"] = HashEnginePtr(new hash_keccak(1024, 64)); - HashEngines["blake3"] = HashEnginePtr(new hash_blake3()); + // HashEngines["blake3"] = HashEnginePtr(new hash_blake3()); #ifndef HPHP_OSS HashEngines["keyed-blake3"] = HashEnginePtr(new hash_keyed_blake3()); #endif From 25829597b75af85a02bf6988bdedecb5efddbb57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 19:21:28 +0100 Subject: [PATCH 16/72] Disable more broken extensions --- ci/ubuntu-20.04-focal/debian/rules | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ci/ubuntu-20.04-focal/debian/rules b/ci/ubuntu-20.04-focal/debian/rules index 60c95ae89f1f77..c865b4f87fb32c 100644 --- a/ci/ubuntu-20.04-focal/debian/rules +++ b/ci/ubuntu-20.04-focal/debian/rules @@ -12,7 +12,12 @@ override_dh_auto_configure: -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DENABLE_EXTENSION_MCRYPT=Off \ -DENABLE_EXTENSION_ASYNC_MYSQL=Off \ - -DENABLE_MCROUTER=Off + -DENABLE_MCROUTER=Off \ + -DENABLE_EXTENSION_FB=Off \ + -DENABLE_EXTENSION_MYSQL=Off \ + -DENABLE_EXTENSION_OPENSSL=Off \ + -DENABLE_EXTENSION_LIBXML=Off \ + -DENABLE_EXTENSION_SOAP=Off override_dh_auto_build: dh_auto_build -- -j1 hack hack_rust_ffi_bridge_targets hhbc_ast_cbindgen hack_dune From ad83f90b7988d2ac569070657123254c35679438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 19:22:38 +0100 Subject: [PATCH 17/72] Allow building with system lz4 --- ci/ubuntu-20.04-focal/debian/rules | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/ubuntu-20.04-focal/debian/rules b/ci/ubuntu-20.04-focal/debian/rules index c865b4f87fb32c..37731bbeb1a81d 100644 --- a/ci/ubuntu-20.04-focal/debian/rules +++ b/ci/ubuntu-20.04-focal/debian/rules @@ -10,6 +10,7 @@ override_dh_auto_configure: -DCMAKE_INSTALL_PREFIX=/opt/hhvm/$(DEB_VERSION_UPSTREAM) \ -DMYSQL_UNIX_SOCK_ADDR=/var/run/mysqld/mysqld.sock \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DFORCE_BUNDLED_LZ4=Off \ -DENABLE_EXTENSION_MCRYPT=Off \ -DENABLE_EXTENSION_ASYNC_MYSQL=Off \ -DENABLE_MCROUTER=Off \ From 095872abbc0416f9d1a2a6882eb45115eed75536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 19:32:32 +0100 Subject: [PATCH 18/72] Fix spammy -Winconsistent-override in transport.h --- hphp/runtime/server/transport.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hphp/runtime/server/transport.h b/hphp/runtime/server/transport.h index 1cab243c6c3aa2..fd574bbd8646e8 100644 --- a/hphp/runtime/server/transport.h +++ b/hphp/runtime/server/transport.h @@ -158,7 +158,7 @@ struct Transport : IDebuggable, ITransportHeaders { /** * Request URI. */ - virtual const char *getUrl() = 0; + virtual const char *getUrl() override = 0; virtual const char *getRemoteHost() = 0; virtual uint16_t getRemotePort() = 0; // The transport can override REMOTE_ADDR if it has one @@ -213,7 +213,7 @@ struct Transport : IDebuggable, ITransportHeaders { /** * POST request's data. */ - virtual const void *getPostData(size_t &size) = 0; + virtual const void *getPostData(size_t &size) override = 0; virtual bool hasMorePostData() { return false; } virtual const void *getMorePostData(size_t &size) { size = 0;return nullptr; } virtual bool getFiles(std::string& /*files*/) { return false; } @@ -228,7 +228,7 @@ struct Transport : IDebuggable, ITransportHeaders { /** * Is this a GET, POST or anything? */ - virtual Method getMethod() = 0; + virtual Method getMethod() override = 0; virtual const char *getExtendedMethod() { return nullptr;} const char *getMethodName() override; @@ -387,7 +387,7 @@ struct Transport : IDebuggable, ITransportHeaders { * foo/bar?x=1 command is "foo/bar" * /foo/bar?x=1 command is "foo/bar" */ - std::string getCommand(); + std::string getCommand() override; /** * Get value of a parameter. Returns empty string is not present. From 8b417a46109c9d572074fa185a7851fbaf8fc1ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 23:06:18 +0100 Subject: [PATCH 19/72] Fix TBB clang patch --- third-party/tbb/CMakeLists.txt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/third-party/tbb/CMakeLists.txt b/third-party/tbb/CMakeLists.txt index 16d4a30748fb1f..04603347f35df9 100644 --- a/third-party/tbb/CMakeLists.txt +++ b/third-party/tbb/CMakeLists.txt @@ -12,7 +12,7 @@ ExternalProject_Add( SOURCE_DIR "${TBB_ROOT}" CONFIGURE_COMMAND "" PATCH_COMMAND - patch -p4 < "${CMAKE_CURRENT_SOURCE_DIR}/pic_compile.patch" + patch -p4 < "${CMAKE_CURRENT_SOURCE_DIR}/pic_compile.patch" && patch -p4 < "${CMAKE_CURRENT_SOURCE_DIR}/clang_fix.patch" BUILD_COMMAND # We only depend on TBB so we only build this target. cd && make @@ -25,11 +25,6 @@ ExternalProject_Add( INSTALL_COMMAND "" ) -# CLang uses the GCC file too. -if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - execute_process(COMMAND "patch" "-p1" "-f" INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/clang_fix.patch") -endif() - add_library(tbb INTERFACE) add_dependencies(tbb bundled_tbb) From 61b0b1c5afa3d91aa4268855948a03bc79d2cd08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 23:58:27 +0100 Subject: [PATCH 20/72] Attempt to workaround build races --- ci/ubuntu-20.04-focal/debian/rules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/ubuntu-20.04-focal/debian/rules b/ci/ubuntu-20.04-focal/debian/rules index 37731bbeb1a81d..19a867c5078060 100644 --- a/ci/ubuntu-20.04-focal/debian/rules +++ b/ci/ubuntu-20.04-focal/debian/rules @@ -21,8 +21,8 @@ override_dh_auto_configure: -DENABLE_EXTENSION_SOAP=Off override_dh_auto_build: - dh_auto_build -- -j1 hack hack_rust_ffi_bridge_targets hhbc_ast_cbindgen hack_dune - dh_auto_build -- -j8 + dh_auto_build --no-parallel -- hack hack_rust_ffi_bridge_targets hhbc_ast_cbindgen hack_dune || dh_auto_build --no-parallel -- hack hack_rust_ffi_bridge_targets hhbc_ast_cbindgen hack_dune + dh_auto_build --parallel override_dh_strip: dh_strip --dbg-package=hhvm-nightly-dbg From ecd32096d4128a83a1e11f437942e46f6b38f74f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 29 Dec 2024 07:20:05 +0100 Subject: [PATCH 21/72] Install and force libc++ for the OSS build --- .github/workflows/ubuntu.yml | 4 ++++ ci/ubuntu-20.04-focal/debian/rules | 1 + 2 files changed, 5 insertions(+) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 744b4df397b1e6..35c72b7f2cfc76 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -42,6 +42,10 @@ jobs: chmod +x llvm.sh # Note: Keep this version in sync with the one in the Debian control file. ./llvm.sh ${CLANG_VERSION} + + # Manually install libc++ as well. + # Don't use ./llvm.sh ${CLANG_VERSION} all to avoid pulling in a broken libunwind. + apt-get install -y libc++-${CLANG_VERSION}-dev libc++abi-${CLANG_VERSION}-dev - name: Making LLVM the default compiler run: | if [ -f /etc/alternatives/cc ] diff --git a/ci/ubuntu-20.04-focal/debian/rules b/ci/ubuntu-20.04-focal/debian/rules index 19a867c5078060..82795244638535 100644 --- a/ci/ubuntu-20.04-focal/debian/rules +++ b/ci/ubuntu-20.04-focal/debian/rules @@ -10,6 +10,7 @@ override_dh_auto_configure: -DCMAKE_INSTALL_PREFIX=/opt/hhvm/$(DEB_VERSION_UPSTREAM) \ -DMYSQL_UNIX_SOCK_ADDR=/var/run/mysqld/mysqld.sock \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCLANG_FORCE_LIBCPP=On \ -DFORCE_BUNDLED_LZ4=Off \ -DENABLE_EXTENSION_MCRYPT=Off \ -DENABLE_EXTENSION_ASYNC_MYSQL=Off \ From c53718863056fb1a1ec38482bf49731c1054075c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 29 Dec 2024 08:15:13 +0100 Subject: [PATCH 22/72] Silence spammy 'non-local-definitions' rust lint --- hphp/hack/scripts/invoke_cargo.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hphp/hack/scripts/invoke_cargo.sh b/hphp/hack/scripts/invoke_cargo.sh index db371aaa0c6444..89af6412a19992 100755 --- a/hphp/hack/scripts/invoke_cargo.sh +++ b/hphp/hack/scripts/invoke_cargo.sh @@ -54,6 +54,8 @@ BUILD_PARAMS+=(--target-dir "${TARGET_DIR}") BUILD_PARAMS+=(--package "$pkg") BUILD_PARAMS+=("$profile_flags") +export RUSTFLAGS="-A non-local-definitions" + ( # add CARGO_BIN to PATH so that rustc and other tools can be invoked [[ -n "$CARGO_BIN" ]] && PATH="$CARGO_BIN:$PATH"; # note: --manifest-path doesn't work with custom toolchain, so do cd From 15e2300adb3498eeb8b6b9e1cb35270631f0e366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 29 Dec 2024 16:17:02 +0100 Subject: [PATCH 23/72] Use LLVM 17 to satisfy C++20 requirements --- .github/workflows/ubuntu.yml | 2 +- ci/ubuntu-20.04-focal/debian/control | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 35c72b7f2cfc76..8b6ae26580c0e9 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -32,7 +32,7 @@ jobs: env: DISTRO: ubuntu-20.04-focal IS_NIGHTLY: 1 - CLANG_VERSION: 12 + CLANG_VERSION: 17 steps: - name: Installing dependencies to bootstrap env run: apt update -y && apt install -y git wget lsb-release software-properties-common gpg diff --git a/ci/ubuntu-20.04-focal/debian/control b/ci/ubuntu-20.04-focal/debian/control index c44c34995349f5..546dac46bdaca3 100644 --- a/ci/ubuntu-20.04-focal/debian/control +++ b/ci/ubuntu-20.04-focal/debian/control @@ -14,7 +14,7 @@ Build-Depends: curl, debhelper (>= 9), flex, - clang-12, + clang-17, gawk, git, gperf, From 089ec10e743fa4776e882fd1353ddef2ce734255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 29 Dec 2024 17:38:10 +0100 Subject: [PATCH 24/72] Build xed since it's now required --- ci/ubuntu-20.04-focal/debian/rules | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/ubuntu-20.04-focal/debian/rules b/ci/ubuntu-20.04-focal/debian/rules index 82795244638535..edf7a5acd3ea1d 100644 --- a/ci/ubuntu-20.04-focal/debian/rules +++ b/ci/ubuntu-20.04-focal/debian/rules @@ -12,6 +12,7 @@ override_dh_auto_configure: -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCLANG_FORCE_LIBCPP=On \ -DFORCE_BUNDLED_LZ4=Off \ + -DENABLE_XED=On \ -DENABLE_EXTENSION_MCRYPT=Off \ -DENABLE_EXTENSION_ASYNC_MYSQL=Off \ -DENABLE_MCROUTER=Off \ From ccc7102cc85acfafbed9583d92aed27b38fa5ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 29 Dec 2024 17:39:14 +0100 Subject: [PATCH 25/72] Parallelize the folly build --- ci/ubuntu-20.04-focal/debian/rules | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/ubuntu-20.04-focal/debian/rules b/ci/ubuntu-20.04-focal/debian/rules index edf7a5acd3ea1d..bbc7fbd6081cce 100644 --- a/ci/ubuntu-20.04-focal/debian/rules +++ b/ci/ubuntu-20.04-focal/debian/rules @@ -23,6 +23,7 @@ override_dh_auto_configure: -DENABLE_EXTENSION_SOAP=Off override_dh_auto_build: + dh_auto_build --parallel -- bundled_folly dh_auto_build --no-parallel -- hack hack_rust_ffi_bridge_targets hhbc_ast_cbindgen hack_dune || dh_auto_build --no-parallel -- hack hack_rust_ffi_bridge_targets hhbc_ast_cbindgen hack_dune dh_auto_build --parallel From bd176e48bdeb4ebc064ca21da320980f3c313805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 29 Dec 2024 21:13:56 +0100 Subject: [PATCH 26/72] Update Fizz patches --- .../patches/do-not-build-testsupport.patch | 75 +++---------------- .../fizz/patches/fizz-config-libsodium.patch | 3 +- .../patches/use-hhvm-libsodium-cmake.patch | 9 ++- 3 files changed, 17 insertions(+), 70 deletions(-) diff --git a/third-party/fizz/patches/do-not-build-testsupport.patch b/third-party/fizz/patches/do-not-build-testsupport.patch index 29c0627838294b..2ceae641b973bb 100644 --- a/third-party/fizz/patches/do-not-build-testsupport.patch +++ b/third-party/fizz/patches/do-not-build-testsupport.patch @@ -1,78 +1,21 @@ diff --git a/fizz/CMakeLists.txt b/fizz/CMakeLists.txt -index 85b78981..5422ba9b 100644 +index c60177c2..2c41ae84 100644 --- a/fizz/CMakeLists.txt +++ b/fizz/CMakeLists.txt -@@ -314,42 +314,42 @@ SET(FIZZ_TEST_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) +@@ -281,7 +281,6 @@ SET(FIZZ_TEST_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) if(BUILD_TESTS) find_package(GMock 1.8.0 MODULE REQUIRED) find_package(GTest 1.8.0 MODULE REQUIRED) -endif() --add_library(fizz_test_support -- crypto/aead/test/TestUtil.cpp -- crypto/test/TestUtil.cpp -- protocol/ech/test/TestUtil.cpp -- ${FIZZ_TEST_HEADERS} --) -+ add_library(fizz_test_support -+ crypto/aead/test/TestUtil.cpp -+ crypto/test/TestUtil.cpp -+ protocol/ech/test/TestUtil.cpp -+ ${FIZZ_TEST_HEADERS} -+ ) + add_library(fizz_test_support + crypto/aead/test/TestUtil.cpp +@@ -304,6 +303,8 @@ install( + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ) --target_link_libraries(fizz_test_support -- PUBLIC -- fizz -- ${LIBGMOCK_LIBRARIES} -- ${GLOG_LIBRARY} --) -+ target_link_libraries(fizz_test_support -+ PUBLIC -+ fizz -+ ${LIBGMOCK_LIBRARIES} -+ ${GLOG_LIBRARY} -+ ) - --target_compile_definitions(fizz_test_support -- PUBLIC -- ${LIBGMOCK_DEFINES} --) -+ target_compile_definitions(fizz_test_support -+ PUBLIC -+ ${LIBGMOCK_DEFINES} -+ ) - --target_include_directories(fizz_test_support -- SYSTEM -- PUBLIC -- ${LIBGMOCK_INCLUDE_DIR} -- ${LIBGTEST_INCLUDE_DIRS} --) -+ target_include_directories(fizz_test_support -+ SYSTEM -+ PUBLIC -+ ${LIBGMOCK_INCLUDE_DIR} -+ ${LIBGTEST_INCLUDE_DIRS} -+ ) - --# export fizz headers and targets for unit tests utils --# since other projects such as mvfst and proxygen use them --install( -- TARGETS fizz_test_support -- EXPORT fizz-exports -- ARCHIVE DESTINATION ${LIB_INSTALL_DIR} -- LIBRARY DESTINATION ${LIB_INSTALL_DIR} --) -+ # export fizz headers and targets for unit tests utils -+ # since other projects such as mvfst and proxygen use them -+ install( -+ TARGETS fizz_test_support -+ EXPORT fizz-exports -+ ARCHIVE DESTINATION ${LIB_INSTALL_DIR} -+ LIBRARY DESTINATION ${LIB_INSTALL_DIR} -+ ) +endif() - ++ foreach(dir ${FIZZ_TEST_HEADER_DIRS}) get_filename_component(PARENT_DIR "/${dir}" DIRECTORY) + install( diff --git a/third-party/fizz/patches/fizz-config-libsodium.patch b/third-party/fizz/patches/fizz-config-libsodium.patch index 16b2eaa5c39c74..28925b25149af3 100644 --- a/third-party/fizz/patches/fizz-config-libsodium.patch +++ b/third-party/fizz/patches/fizz-config-libsodium.patch @@ -2,10 +2,11 @@ diff --git a/fizz/cmake/fizz-config.cmake.in b/fizz/cmake/fizz-config.cmake.in index 679b0e61..6415688b 100644 --- a/fizz/cmake/fizz-config.cmake.in +++ b/fizz/cmake/fizz-config.cmake.in -@@ -26,7 +26,6 @@ endif() +@@ -30,8 +30,7 @@ endif() set(FIZZ_LIBRARIES fizz::fizz) include(CMakeFindDependencyMacro) + -find_dependency(Sodium) find_dependency(folly CONFIG) find_dependency(ZLIB) diff --git a/third-party/fizz/patches/use-hhvm-libsodium-cmake.patch b/third-party/fizz/patches/use-hhvm-libsodium-cmake.patch index 1cdaefd1fd0657..83a6c019ef1da0 100644 --- a/third-party/fizz/patches/use-hhvm-libsodium-cmake.patch +++ b/third-party/fizz/patches/use-hhvm-libsodium-cmake.patch @@ -2,16 +2,18 @@ Index: fizz/fizz/CMakeLists.txt =================================================================== --- fizz.orig/fizz/CMakeLists.txt +++ fizz/fizz/CMakeLists.txt -@@ -64,7 +64,7 @@ endif() +@@ -62,8 +62,8 @@ endif() include(CheckAtomic) -find_package(Sodium REQUIRED) +-set(FIZZ_HAVE_SODIUM ${Sodium_FOUND}) +find_package(LibSodium REQUIRED) ++set(FIZZ_HAVE_SODIUM ${LibSodium_FOUND}) SET(FIZZ_SHINY_DEPENDENCIES "") SET(FIZZ_LINK_LIBRARIES "") -@@ -237,7 +237,7 @@ target_include_directories( +@@ -201,7 +201,7 @@ target_include_directories( $ ${FOLLY_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} @@ -20,7 +22,7 @@ Index: fizz/fizz/CMakeLists.txt ${ZSTD_INCLUDE_DIR} PRIVATE ${GLOG_INCLUDE_DIRS} -@@ -250,7 +250,7 @@ target_link_libraries(fizz +@@ -213,7 +213,7 @@ target_link_libraries(fizz PUBLIC ${FOLLY_LIBRARIES} ${OPENSSL_LIBRARIES} @@ -29,3 +31,4 @@ Index: fizz/fizz/CMakeLists.txt Threads::Threads ZLIB::ZLIB ${ZSTD_LIBRARY} + From 0e73bd576a07a18197faccb239a87bf52d4d588c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Mon, 30 Dec 2024 15:27:56 +0100 Subject: [PATCH 27/72] Update third-party GitHub actions --- .github/workflows/ubuntu.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 8b6ae26580c0e9..b75952d4da428f 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -63,13 +63,13 @@ jobs: update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${CLANG_VERSION} 500 update-alternatives --set c++ /usr/bin/clang++-${CLANG_VERSION} - name: Fetching HHVM and its submodules - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: 'recursive' - name: Installing HHVM deps and building HHVM run: ci/bin/make-debianish-package - name: Uploading artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: out-directory path: ${{ env.OUT }} From fb963c5513d220a4c1fa3362cd7edc9644275130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Tue, 31 Dec 2024 02:30:54 +0100 Subject: [PATCH 28/72] Switch CI from Focal to Jammy --- .github/workflows/ubuntu.yml | 4 ++-- ci/bin/make-debianish-package | 3 +-- ci/ubuntu-20.04-focal/DISTRIBUTION | 1 - ci/ubuntu-20.04-focal/PKGVER | 1 - ci/ubuntu-22.04-jammy/DISTRIBUTION | 1 + ci/ubuntu-22.04-jammy/PKGVER | 1 + ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/compat | 0 .../debian/conffiles | 0 ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/control | 0 ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/copying | 0 ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/format | 0 .../debian/hhvm-nightly-dev.install.in | 0 .../debian/hhvm-nightly.dirs | 0 .../debian/hhvm-nightly.install.in | 0 .../debian/postinst.in | 0 ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/postrm | 0 ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/preinst | 0 ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/prerm.in | 0 ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/rules | 4 ++++ 19 files changed, 9 insertions(+), 6 deletions(-) delete mode 100644 ci/ubuntu-20.04-focal/DISTRIBUTION delete mode 100644 ci/ubuntu-20.04-focal/PKGVER create mode 100644 ci/ubuntu-22.04-jammy/DISTRIBUTION create mode 100644 ci/ubuntu-22.04-jammy/PKGVER rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/compat (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/conffiles (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/control (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/copying (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/format (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/hhvm-nightly-dev.install.in (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/hhvm-nightly.dirs (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/hhvm-nightly.install.in (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/postinst.in (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/postrm (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/preinst (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/prerm.in (100%) rename ci/{ubuntu-20.04-focal => ubuntu-22.04-jammy}/debian/rules (92%) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index b75952d4da428f..0c566475bbf537 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -28,9 +28,9 @@ jobs: build_ubuntu_focal_nightly: runs-on: ubuntu-24.04 container: - image: ubuntu:focal + image: ubuntu:jammy env: - DISTRO: ubuntu-20.04-focal + DISTRO: ubuntu-22.04-jammy IS_NIGHTLY: 1 CLANG_VERSION: 17 steps: diff --git a/ci/bin/make-debianish-package b/ci/bin/make-debianish-package index caf60b799a2773..c544065f95a52c 100755 --- a/ci/bin/make-debianish-package +++ b/ci/bin/make-debianish-package @@ -57,8 +57,7 @@ dch --create -v "${FULL_VERSION}" --package "${PKGBASE}" --controlmaint --distri # Build debian package that depends on build-depends, and install it mk-build-deps -dpkg -i --force-depends "$BUILD_DEPS" -apt-get -o Acquire::Retries=3 install -y -f +apt-get -o Acquire::Retries=3 install -y ./"$BUILD_DEPS" mv "$BUILD_DEPS" "$OUT" # Build the actual debian packages diff --git a/ci/ubuntu-20.04-focal/DISTRIBUTION b/ci/ubuntu-20.04-focal/DISTRIBUTION deleted file mode 100644 index 037d3d33e19161..00000000000000 --- a/ci/ubuntu-20.04-focal/DISTRIBUTION +++ /dev/null @@ -1 +0,0 @@ -focal diff --git a/ci/ubuntu-20.04-focal/PKGVER b/ci/ubuntu-20.04-focal/PKGVER deleted file mode 100644 index a76b84049d42b9..00000000000000 --- a/ci/ubuntu-20.04-focal/PKGVER +++ /dev/null @@ -1 +0,0 @@ -1~focal diff --git a/ci/ubuntu-22.04-jammy/DISTRIBUTION b/ci/ubuntu-22.04-jammy/DISTRIBUTION new file mode 100644 index 00000000000000..f97ff28ec907d8 --- /dev/null +++ b/ci/ubuntu-22.04-jammy/DISTRIBUTION @@ -0,0 +1 @@ +jammy diff --git a/ci/ubuntu-22.04-jammy/PKGVER b/ci/ubuntu-22.04-jammy/PKGVER new file mode 100644 index 00000000000000..d06c9bab272a9b --- /dev/null +++ b/ci/ubuntu-22.04-jammy/PKGVER @@ -0,0 +1 @@ +1~jammy diff --git a/ci/ubuntu-20.04-focal/debian/compat b/ci/ubuntu-22.04-jammy/debian/compat similarity index 100% rename from ci/ubuntu-20.04-focal/debian/compat rename to ci/ubuntu-22.04-jammy/debian/compat diff --git a/ci/ubuntu-20.04-focal/debian/conffiles b/ci/ubuntu-22.04-jammy/debian/conffiles similarity index 100% rename from ci/ubuntu-20.04-focal/debian/conffiles rename to ci/ubuntu-22.04-jammy/debian/conffiles diff --git a/ci/ubuntu-20.04-focal/debian/control b/ci/ubuntu-22.04-jammy/debian/control similarity index 100% rename from ci/ubuntu-20.04-focal/debian/control rename to ci/ubuntu-22.04-jammy/debian/control diff --git a/ci/ubuntu-20.04-focal/debian/copying b/ci/ubuntu-22.04-jammy/debian/copying similarity index 100% rename from ci/ubuntu-20.04-focal/debian/copying rename to ci/ubuntu-22.04-jammy/debian/copying diff --git a/ci/ubuntu-20.04-focal/debian/format b/ci/ubuntu-22.04-jammy/debian/format similarity index 100% rename from ci/ubuntu-20.04-focal/debian/format rename to ci/ubuntu-22.04-jammy/debian/format diff --git a/ci/ubuntu-20.04-focal/debian/hhvm-nightly-dev.install.in b/ci/ubuntu-22.04-jammy/debian/hhvm-nightly-dev.install.in similarity index 100% rename from ci/ubuntu-20.04-focal/debian/hhvm-nightly-dev.install.in rename to ci/ubuntu-22.04-jammy/debian/hhvm-nightly-dev.install.in diff --git a/ci/ubuntu-20.04-focal/debian/hhvm-nightly.dirs b/ci/ubuntu-22.04-jammy/debian/hhvm-nightly.dirs similarity index 100% rename from ci/ubuntu-20.04-focal/debian/hhvm-nightly.dirs rename to ci/ubuntu-22.04-jammy/debian/hhvm-nightly.dirs diff --git a/ci/ubuntu-20.04-focal/debian/hhvm-nightly.install.in b/ci/ubuntu-22.04-jammy/debian/hhvm-nightly.install.in similarity index 100% rename from ci/ubuntu-20.04-focal/debian/hhvm-nightly.install.in rename to ci/ubuntu-22.04-jammy/debian/hhvm-nightly.install.in diff --git a/ci/ubuntu-20.04-focal/debian/postinst.in b/ci/ubuntu-22.04-jammy/debian/postinst.in similarity index 100% rename from ci/ubuntu-20.04-focal/debian/postinst.in rename to ci/ubuntu-22.04-jammy/debian/postinst.in diff --git a/ci/ubuntu-20.04-focal/debian/postrm b/ci/ubuntu-22.04-jammy/debian/postrm similarity index 100% rename from ci/ubuntu-20.04-focal/debian/postrm rename to ci/ubuntu-22.04-jammy/debian/postrm diff --git a/ci/ubuntu-20.04-focal/debian/preinst b/ci/ubuntu-22.04-jammy/debian/preinst similarity index 100% rename from ci/ubuntu-20.04-focal/debian/preinst rename to ci/ubuntu-22.04-jammy/debian/preinst diff --git a/ci/ubuntu-20.04-focal/debian/prerm.in b/ci/ubuntu-22.04-jammy/debian/prerm.in similarity index 100% rename from ci/ubuntu-20.04-focal/debian/prerm.in rename to ci/ubuntu-22.04-jammy/debian/prerm.in diff --git a/ci/ubuntu-20.04-focal/debian/rules b/ci/ubuntu-22.04-jammy/debian/rules similarity index 92% rename from ci/ubuntu-20.04-focal/debian/rules rename to ci/ubuntu-22.04-jammy/debian/rules index bbc7fbd6081cce..be37924acce6bb 100644 --- a/ci/ubuntu-20.04-focal/debian/rules +++ b/ci/ubuntu-22.04-jammy/debian/rules @@ -1,6 +1,10 @@ #!/usr/bin/make -f include /usr/share/dpkg/pkg-info.mk +export DPKG_EXPORT_BUILDFLAGS=1 +export DEB_BUILD_MAINT_OPTIONS=optimize=-lto +include /usr/share/dpkg/buildflags.mk + %: dh $@ --buildsystem=cmake --parallel From f46797b3e7eac9f9c6c997088b7e2d8affd66ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Tue, 31 Dec 2024 21:31:12 +0100 Subject: [PATCH 29/72] Use single Rust staticlib for FFI --- CMake/HPHPFindLibs.cmake | 6 +- ci/ubuntu-22.04-jammy/debian/rules | 2 +- hphp/compiler/compiler-systemlib.cpp | 2 +- hphp/compiler/compiler.cpp | 2 +- hphp/compiler/package.cpp | 2 +- hphp/hack/CMakeLists.txt | 169 +++++++----------- hphp/hack/src/Cargo.lock | 12 ++ hphp/hack/src/Cargo.toml | 1 + hphp/hack/src/hackc/ffi_bridge/Cargo.toml | 2 +- .../hack/src/hackc/ffi_bridge/decl_provider.h | 2 +- .../hackc/hhvm_cxx/hhvm_hhbc_defs/Cargo.toml | 2 +- .../src/hackc/hhvm_cxx/hhvm_types/Cargo.toml | 2 +- hphp/hack/src/hhvm_ffi/Cargo.toml | 18 ++ hphp/hack/src/hhvm_ffi/lib.rs | 6 + hphp/hack/src/parser/ffi_bridge/Cargo.toml | 2 +- hphp/hack/src/utils/hdf/Cargo.toml | 2 +- hphp/runtime/base/package.cpp | 2 +- hphp/runtime/base/runtime-option.cpp | 2 +- hphp/runtime/base/runtime-option.h | 2 +- hphp/runtime/ext/decl/decl-extractor.cpp | 2 +- hphp/runtime/ext/decl/decl-extractor.h | 2 +- hphp/runtime/ext/facts/file-facts.h | 2 +- hphp/runtime/vm/builtin-symbol-map.cpp | 2 +- hphp/runtime/vm/hackc-translator.h | 2 +- hphp/runtime/vm/unit-parser.cpp | 4 +- 25 files changed, 124 insertions(+), 128 deletions(-) create mode 100644 hphp/hack/src/hhvm_ffi/Cargo.toml create mode 100644 hphp/hack/src/hhvm_ffi/lib.rs diff --git a/CMake/HPHPFindLibs.cmake b/CMake/HPHPFindLibs.cmake index 6549a56b70299e..c954f81f514cd0 100644 --- a/CMake/HPHPFindLibs.cmake +++ b/CMake/HPHPFindLibs.cmake @@ -411,11 +411,7 @@ macro(hphp_link target) target_link_libraries(${target} ${VISIBILITY} fizz) target_link_libraries(${target} ${VISIBILITY} brotli) target_link_libraries(${target} ${VISIBILITY} hhbc_ast_header) - target_link_libraries(${target} ${VISIBILITY} compiler_ffi) - target_link_libraries(${target} ${VISIBILITY} package_ffi) - target_link_libraries(${target} ${VISIBILITY} parser_ffi) - target_link_libraries(${target} ${VISIBILITY} hhvm_types_ffi) - target_link_libraries(${target} ${VISIBILITY} hhvm_hhbc_defs_ffi) + target_link_libraries(${target} ${VISIBILITY} hack_rust_ffi_bridge) target_link_libraries(${target} ${VISIBILITY} tbb) diff --git a/ci/ubuntu-22.04-jammy/debian/rules b/ci/ubuntu-22.04-jammy/debian/rules index be37924acce6bb..14ca6040a6400f 100644 --- a/ci/ubuntu-22.04-jammy/debian/rules +++ b/ci/ubuntu-22.04-jammy/debian/rules @@ -28,7 +28,7 @@ override_dh_auto_configure: override_dh_auto_build: dh_auto_build --parallel -- bundled_folly - dh_auto_build --no-parallel -- hack hack_rust_ffi_bridge_targets hhbc_ast_cbindgen hack_dune || dh_auto_build --no-parallel -- hack hack_rust_ffi_bridge_targets hhbc_ast_cbindgen hack_dune + dh_auto_build --no-parallel -- hack hack_rust_ffi_bridge hhbc_ast_cbindgen hack_dune || dh_auto_build --no-parallel -- hack hack_rust_ffi_bridge hhbc_ast_cbindgen hack_dune dh_auto_build --parallel override_dh_strip: diff --git a/hphp/compiler/compiler-systemlib.cpp b/hphp/compiler/compiler-systemlib.cpp index 80377a5494d279..124e81fb4eaea9 100644 --- a/hphp/compiler/compiler-systemlib.cpp +++ b/hphp/compiler/compiler-systemlib.cpp @@ -16,7 +16,7 @@ #include "hphp/compiler/compiler-systemlib.h" -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" #include "hphp/hhvm/process-init.h" diff --git a/hphp/compiler/compiler.cpp b/hphp/compiler/compiler.cpp index 1cd088997962d5..265d19bb45c000 100644 --- a/hphp/compiler/compiler.cpp +++ b/hphp/compiler/compiler.cpp @@ -19,7 +19,7 @@ #include "hphp/compiler/option.h" #include "hphp/compiler/package.h" -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" #include "hphp/hhbbc/hhbbc.h" #include "hphp/hhbbc/misc.h" diff --git a/hphp/compiler/package.cpp b/hphp/compiler/package.cpp index 21b0b3f2905b0e..7155b7750d975f 100644 --- a/hphp/compiler/package.cpp +++ b/hphp/compiler/package.cpp @@ -31,7 +31,7 @@ #include "hphp/compiler/decl-provider.h" #include "hphp/compiler/option.h" -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" #include "hphp/hhvm/process-init.h" #include "hphp/runtime/base/file-util-defs.h" #include "hphp/runtime/base/file-util.h" diff --git a/hphp/hack/CMakeLists.txt b/hphp/hack/CMakeLists.txt index 6739ae7fc8020d..cf01f6a84ffbfb 100644 --- a/hphp/hack/CMakeLists.txt +++ b/hphp/hack/CMakeLists.txt @@ -229,120 +229,83 @@ HHVM_RENDER_CONFIG_SPECIFICATION( OUTPUT_PATH "${CMAKE_BINARY_DIR}/hphp/hack/src/hackc/compile" ) -# Compiling cxx entrypoints for hhvm -# -# Usage: -# build_cxx_bridge( -# name -# DIR directory -# [EXTRA_SRCS src [src ...]] -# [LINK_LIBS lib [lib ...]] -# ) -# -# Where: -# `name` is the target name of the cxx_bridge. -# `directory` is the required directory of the cxx_bridge sources. -# `src` are extra source files to include in the bridge. -# `lib` are extra link libraries to include in the bridge. -# -function(build_cxx_bridge NAME) - cmake_parse_arguments(CXX_BRIDGE "" "DIR" "EXTRA_SRCS;LINK_LIBS;DEPENDS" ${ARGN}) +set( + FFI_CRATES + "package_ffi" + "parser_ffi" + "compiler_ffi" + "hdf" + "hhvm_types_ffi" + "hhvm_hhbc_defs_ffi" +) - if ("${CXX_BRIDGE_DIR}" STREQUAL "") - message(FATAL_ERROR "Missing DIR parameter") - endif() - if (NOT "${CXX_BRIDGE_UNPARSED_ARGUMENTS}" STREQUAL "") - message(FATAL_ERROR "Unexpected parameters: ${CXX_BRIDGE_UNPARSED_ARGUMENTS}") - endif() +set(FFI_BRIDGE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/hhvm_ffi") +set(FFI_BRIDGE_BIN "${RUST_FFI_BUILD_ROOT}/hphp/hack/src/hhvm_ffi") +set(RUST_PART_LIB "${RUST_FFI_BUILD_ROOT}/hphp/hack/src/hhvm_ffi/${PROFILE}/${CMAKE_STATIC_LIBRARY_PREFIX}hhvm_ffi${CMAKE_STATIC_LIBRARY_SUFFIX}") - set(FFI_BRIDGE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${CXX_BRIDGE_DIR}") - set(FFI_BRIDGE_BIN "${RUST_FFI_BUILD_ROOT}/hphp/hack/${CXX_BRIDGE_DIR}") - - set(RUST_PART_LIB "${FFI_BRIDGE_BIN}/${PROFILE}/${CMAKE_STATIC_LIBRARY_PREFIX}${NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}") - set(RUST_PART_CXX "${FFI_BRIDGE_BIN}/${NAME}.cpp") - set(RUST_PART_HEADER "${FFI_BRIDGE_BIN}/${NAME}.rs.h") - set(GENERATED "${FFI_BRIDGE_BIN}/cxxbridge/${NAME}/${NAME}") - set(GENERATED_CXXBRIDGE "${FFI_BRIDGE_BIN}/cxxbridge") - - add_custom_command( - OUTPUT - ${RUST_PART_CXX} - ${RUST_PART_HEADER} - ${RUST_PART_LIB} - ${GENERATED_CXXBRIDGE} - COMMAND - ${CMAKE_COMMAND} -E make_directory "${FFI_BRIDGE_BIN}" && - . "${CMAKE_CURRENT_BINARY_DIR}/dev_env_rust_only.sh" && - ${INVOKE_CARGO} "${NAME}" "${NAME}" --target-dir "${FFI_BRIDGE_BIN}" && - ${CMAKE_COMMAND} -E copy "${GENERATED}.rs.cc" "${RUST_PART_CXX}" && - ${CMAKE_COMMAND} -E copy "${GENERATED}.rs.h" "${RUST_PART_HEADER}" - WORKING_DIRECTORY ${FFI_BRIDGE_SRC} - DEPENDS rustc cargo "${OPCODE_DATA}" - ) - add_custom_target( - "${NAME}_cxx" - DEPENDS ${RUST_PART_LIB} - ) - add_library("${NAME}" STATIC ${RUST_PART_CXX} ${CXX_BRIDGE_EXTRA_SRCS} ) - if (NOT "${CXX_BRIDGE_DEPENDS}" STREQUAL "") - add_dependencies("${NAME}" "${CXX_BRIDGE_DEPENDS}") - endif() +foreach(NAME ${FFI_CRATES}) + list(APPEND FFI_CXXBRIDGE_ORIG_SRCS "${FFI_BRIDGE_BIN}/cxxbridge/${NAME}/${NAME}.rs.cc") + list(APPEND FFI_CXXBRIDGE_SRCS "${FFI_BRIDGE_BIN}/${NAME}.rs.cc") - add_dependencies(hack_rust_ffi_bridge_targets "${NAME}") - add_library("${NAME}_rust_part" STATIC IMPORTED) - add_dependencies("${NAME}_rust_part" "${NAME}_cxx") - - # Intentionally create link-time cyclic dependency between ${NAME}_rust_part - # and ${NAME} so that CMake will automatically construct the link line so - # that the linker will scan through involved static libraries multiple times. - set_target_properties( - "${NAME}_rust_part" - PROPERTIES - IMPORTED_LOCATION ${RUST_PART_LIB} - IMPORTED_LINK_DEPENDENT_LIBRARIES "${NAME}" - ) - target_link_libraries( - "${NAME}" - PUBLIC - "${NAME}_rust_part" - ${CXX_BRIDGE_LINK_LIBS} - ) - target_include_directories("${NAME}" INTERFACE "${RUST_FFI_BUILD_ROOT}") - target_include_directories("${NAME}" PRIVATE "${GENERATED_CXXBRIDGE}") -endfunction() + list(APPEND FFI_CXXBRIDGE_ORIG_HEADERS "${FFI_BRIDGE_BIN}/cxxbridge/${NAME}/${NAME}.rs.h") + list(APPEND FFI_CXXBRIDGE_HEADERS "${FFI_BRIDGE_BIN}/${NAME}.rs.h") +endforeach() -build_cxx_bridge( - package_ffi - DIR "src/package/ffi_bridge" +add_custom_command( + OUTPUT + ${RUST_PART_LIB} ${FFI_CXXBRIDGE_ORIG_SRCS} ${FFI_CXXBRIDGE_ORIG_HEADERS} + COMMAND + ${CMAKE_COMMAND} -E make_directory "${FFI_BRIDGE_BIN}" && + . "${CMAKE_CURRENT_BINARY_DIR}/dev_env_rust_only.sh" && + ${CMAKE_COMMAND} -E env CXX=${CMAKE_CXX_COMPILER} CXXFLAGS=${CMAKE_CXX_FLAGS} ${INVOKE_CARGO} hhvm_ffi hhvm_ffi --target-dir "${FFI_BRIDGE_BIN}" + WORKING_DIRECTORY ${FFI_BRIDGE_SRC} + DEPENDS rustc cargo hackc_options "${OPCODE_DATA}" ) -build_cxx_bridge( - parser_ffi - DIR "src/parser/ffi_bridge" + +add_custom_target( + hack_rust_ffi_bridge_rust_build + DEPENDS ${RUST_PART_LIB} ) -build_cxx_bridge( - compiler_ffi - DIR "src/hackc/ffi_bridge" - EXTRA_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/src/hackc/ffi_bridge/external_decl_provider.cpp" - LINK_LIBS hdf - DEPENDS hackc_options + +add_custom_command( + OUTPUT ${FFI_CXXBRIDGE_HEADERS} ${FFI_CXXBRIDGE_SRCS} + COMMAND + ${CMAKE_COMMAND} -E make_directory "${FFI_BRIDGE_BIN}" && + ${CMAKE_COMMAND} -E copy_if_different ${FFI_CXXBRIDGE_ORIG_HEADERS} ${FFI_BRIDGE_BIN} && + ${CMAKE_COMMAND} -E copy_if_different ${FFI_CXXBRIDGE_ORIG_SRCS} ${FFI_BRIDGE_BIN} + DEPENDS ${FFI_CXXBRIDGE_ORIG_HEADERS} ${FFI_CXXBRIDGE_ORIG_SRCS} ) -build_cxx_bridge( - hdf - DIR "src/utils/hdf" - EXTRA_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/src/utils/hdf/hdf-wrap.cpp" - LINK_LIBS folly + +add_custom_target( + hack_rust_ffi_bridge_copy_cxxbridge + DEPENDS ${FFI_CXXBRIDGE_HEADERS} ${FFI_CXXBRIDGE_SRCS} ) -build_cxx_bridge( - hhvm_types_ffi - DIR "src/hackc/hhvm_cxx/hhvm_types" - EXTRA_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/src/hackc/hhvm_cxx/hhvm_types/as-base-ffi.cpp" + +add_library(hack_rust_ffi_bridge_rust_part STATIC IMPORTED) +add_dependencies(hack_rust_ffi_bridge_rust_part hack_rust_ffi_bridge_rust_build hack_rust_ffi_bridge_copy_cxxbridge) +set_target_properties( + hack_rust_ffi_bridge_rust_part + PROPERTIES + IMPORTED_LOCATION ${RUST_PART_LIB} + # Intentionally create a link-time cyclic dependency between the Rust library + # and the dependent C++ library so that CMake will automatically construct the link line, + # causing the linker to scan through involved static libraries multiple times. + IMPORTED_LINK_DEPENDENT_LIBRARIES hack_rust_ffi_bridge ) -build_cxx_bridge( - hhvm_hhbc_defs_ffi - DIR "src/hackc/hhvm_cxx/hhvm_hhbc_defs" - EXTRA_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/src/hackc/hhvm_cxx/hhvm_hhbc_defs/as-hhbc-ffi.cpp" + +add_library( + hack_rust_ffi_bridge + ${FFI_CXXBRIDGE_SRCS} + "${CMAKE_CURRENT_SOURCE_DIR}/src/hackc/ffi_bridge/external_decl_provider.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hackc/hhvm_cxx/hhvm_types/as-base-ffi.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hackc/hhvm_cxx/hhvm_hhbc_defs/as-hhbc-ffi.cpp" ) +target_link_libraries(hack_rust_ffi_bridge PRIVATE folly hack_rust_ffi_bridge_rust_part) +target_include_directories(hack_rust_ffi_bridge INTERFACE "${RUST_FFI_BUILD_ROOT}") +target_include_directories(hack_rust_ffi_bridge PRIVATE "${FFI_BRIDGE_BIN}/cxxbridge") + + if (NOT LZ4_FOUND) add_dependencies(hack_dune lz4) add_dependencies(hack_dune_debug lz4) diff --git a/hphp/hack/src/Cargo.lock b/hphp/hack/src/Cargo.lock index c604d66d621099..9cbdf2fb612fa3 100644 --- a/hphp/hack/src/Cargo.lock +++ b/hphp/hack/src/Cargo.lock @@ -2565,6 +2565,18 @@ dependencies = [ "options", ] +[[package]] +name = "hhvm_ffi" +version = "0.0.0" +dependencies = [ + "compiler_ffi", + "hdf", + "hhvm_hhbc_defs_ffi", + "hhvm_types_ffi", + "package_ffi", + "parser_ffi", +] + [[package]] name = "hhvm_hhbc_defs_ffi" version = "0.0.0" diff --git a/hphp/hack/src/Cargo.toml b/hphp/hack/src/Cargo.toml index badc0b6d9515b4..a89f27162e839a 100644 --- a/hphp/hack/src/Cargo.toml +++ b/hphp/hack/src/Cargo.toml @@ -42,6 +42,7 @@ members = [ "hh_fanout/cargo/hh_fanout_dep_graph_is_subgraph_rust", "hh_fanout/cargo/hh_fanout_dep_graph_stats_rust", "hh_naming_table_builder/cargo/naming_table_builder_ffi", + "hhvm_ffi", "naming", "naming/cargo/elaborate_namespaces", "naming/cargo/naming_attributes", diff --git a/hphp/hack/src/hackc/ffi_bridge/Cargo.toml b/hphp/hack/src/hackc/ffi_bridge/Cargo.toml index a82fc9a3a04df0..fb459111bb8f0f 100644 --- a/hphp/hack/src/hackc/ffi_bridge/Cargo.toml +++ b/hphp/hack/src/hackc/ffi_bridge/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" [lib] path = "compiler_ffi.rs" -crate-type = ["lib", "staticlib"] +crate-type = ["rlib"] [dependencies] anyhow = "1.0.98" diff --git a/hphp/hack/src/hackc/ffi_bridge/decl_provider.h b/hphp/hack/src/hackc/ffi_bridge/decl_provider.h index 44a7a2f5c002be..3ede4f832bf6f4 100644 --- a/hphp/hack/src/hackc/ffi_bridge/decl_provider.h +++ b/hphp/hack/src/hackc/ffi_bridge/decl_provider.h @@ -6,7 +6,7 @@ #pragma once #include -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" namespace HPHP { namespace hackc { diff --git a/hphp/hack/src/hackc/hhvm_cxx/hhvm_hhbc_defs/Cargo.toml b/hphp/hack/src/hackc/hhvm_cxx/hhvm_hhbc_defs/Cargo.toml index 51e1000e5395f8..854a93cf3a0d48 100644 --- a/hphp/hack/src/hackc/hhvm_cxx/hhvm_hhbc_defs/Cargo.toml +++ b/hphp/hack/src/hackc/hhvm_cxx/hhvm_hhbc_defs/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" [lib] path = "hhvm_hhbc_defs_ffi.rs" -crate-type = ["lib", "staticlib"] +crate-type = ["rlib"] [dependencies] cxx = "1.0.119" diff --git a/hphp/hack/src/hackc/hhvm_cxx/hhvm_types/Cargo.toml b/hphp/hack/src/hackc/hhvm_cxx/hhvm_types/Cargo.toml index b6252539004f0b..4fffc64909cef3 100644 --- a/hphp/hack/src/hackc/hhvm_cxx/hhvm_types/Cargo.toml +++ b/hphp/hack/src/hackc/hhvm_cxx/hhvm_types/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" [lib] path = "hhvm_types_ffi.rs" -crate-type = ["lib", "staticlib"] +crate-type = ["rlib"] [dependencies] cxx = "1.0.119" diff --git a/hphp/hack/src/hhvm_ffi/Cargo.toml b/hphp/hack/src/hhvm_ffi/Cargo.toml new file mode 100644 index 00000000000000..c4f98995c8c919 --- /dev/null +++ b/hphp/hack/src/hhvm_ffi/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "hhvm_ffi" +version = "0.0.0" +edition = "2021" +repository = "https://github.com/facebook/hhvm" +license = "MIT" + +[lib] +path = "lib.rs" +crate-type = ["staticlib"] + +[dependencies] +hdf = { path = "../utils/hdf" } +compiler_ffi = { path = "../hackc/ffi_bridge" } +package_ffi = { path = "../package/ffi_bridge" } +parser_ffi = { path = "../parser/ffi_bridge" } +hhvm_hhbc_defs_ffi = { path = "../hackc/hhvm_cxx/hhvm_hhbc_defs" } +hhvm_types_ffi = { path = "../hackc/hhvm_cxx/hhvm_types" } diff --git a/hphp/hack/src/hhvm_ffi/lib.rs b/hphp/hack/src/hhvm_ffi/lib.rs new file mode 100644 index 00000000000000..78421b0831ce07 --- /dev/null +++ b/hphp/hack/src/hhvm_ffi/lib.rs @@ -0,0 +1,6 @@ +extern crate hdf; +extern crate compiler_ffi; +extern crate package_ffi; +extern crate parser_ffi; +extern crate hhvm_hhbc_defs_ffi; +extern crate hhvm_types_ffi; diff --git a/hphp/hack/src/parser/ffi_bridge/Cargo.toml b/hphp/hack/src/parser/ffi_bridge/Cargo.toml index 515093711f5677..c04a2e54350ef0 100644 --- a/hphp/hack/src/parser/ffi_bridge/Cargo.toml +++ b/hphp/hack/src/parser/ffi_bridge/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" path = "parser_ffi.rs" test = false doctest = false -crate-type = ["lib", "staticlib"] +crate-type = ["rlib"] [dependencies] bumpalo = { version = "3.14.0", features = ["allocator_api", "collections"] } diff --git a/hphp/hack/src/utils/hdf/Cargo.toml b/hphp/hack/src/utils/hdf/Cargo.toml index 78f5edf0463eb8..f1f55d0c1ca1e2 100644 --- a/hphp/hack/src/utils/hdf/Cargo.toml +++ b/hphp/hack/src/utils/hdf/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" [lib] path = "lib.rs" -crate-type = ["lib", "staticlib"] +crate-type = ["rlib"] [dependencies] cxx = "1.0.119" diff --git a/hphp/runtime/base/package.cpp b/hphp/runtime/base/package.cpp index 3f1729a59234ca..eb915a493ff170 100644 --- a/hphp/runtime/base/package.cpp +++ b/hphp/runtime/base/package.cpp @@ -27,7 +27,7 @@ #include #include "hphp/util/rds-local.h" -#include "hphp/hack/src/package/ffi_bridge/package_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/package_ffi.rs.h" #include #include diff --git a/hphp/runtime/base/runtime-option.cpp b/hphp/runtime/base/runtime-option.cpp index 44ea0b23a2acda..8a144a04dba586 100644 --- a/hphp/runtime/base/runtime-option.cpp +++ b/hphp/runtime/base/runtime-option.cpp @@ -17,7 +17,7 @@ #include "hphp/runtime/base/runtime-option.h" #include "hphp/hack/src/hackc/compile/options_gen.h" -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" #include "hphp/runtime/base/autoload-handler.h" #include "hphp/runtime/base/bespoke-array.h" #include "hphp/runtime/base/builtin-functions.h" diff --git a/hphp/runtime/base/runtime-option.h b/hphp/runtime/base/runtime-option.h index 0be44d0016b6e5..aa8164320c99e0 100644 --- a/hphp/runtime/base/runtime-option.h +++ b/hphp/runtime/base/runtime-option.h @@ -45,7 +45,7 @@ #include "hphp/util/hash-map.h" #include "hphp/util/sha1.h" -#include "hphp/hack/src/parser/ffi_bridge/parser_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/parser_ffi.rs.h" namespace HPHP { /////////////////////////////////////////////////////////////////////////////// diff --git a/hphp/runtime/ext/decl/decl-extractor.cpp b/hphp/runtime/ext/decl/decl-extractor.cpp index 25e604f1e1ccdd..98cb4def3393c3 100644 --- a/hphp/runtime/ext/decl/decl-extractor.cpp +++ b/hphp/runtime/ext/decl/decl-extractor.cpp @@ -5,7 +5,7 @@ #include #include #include -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" #include "hphp/runtime/base/stream-wrapper-registry.h" #include "hphp/runtime/base/unit-cache.h" #include "hphp/runtime/ext/decl/decl-extractor.h" diff --git a/hphp/runtime/ext/decl/decl-extractor.h b/hphp/runtime/ext/decl/decl-extractor.h index 4c38e0166bb6c6..71948680ffbaf4 100644 --- a/hphp/runtime/ext/decl/decl-extractor.h +++ b/hphp/runtime/ext/decl/decl-extractor.h @@ -9,7 +9,7 @@ #include #include #include -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" #include "hphp/runtime/ext/facts/path-and-hash.h" namespace HPHP { diff --git a/hphp/runtime/ext/facts/file-facts.h b/hphp/runtime/ext/facts/file-facts.h index 6420de3f0e70f9..02ae67b6afbad6 100644 --- a/hphp/runtime/ext/facts/file-facts.h +++ b/hphp/runtime/ext/facts/file-facts.h @@ -24,7 +24,7 @@ #include #include #include -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" namespace HPHP { namespace Facts { diff --git a/hphp/runtime/vm/builtin-symbol-map.cpp b/hphp/runtime/vm/builtin-symbol-map.cpp index c213d1db1a0c31..e663d1b716b0e0 100644 --- a/hphp/runtime/vm/builtin-symbol-map.cpp +++ b/hphp/runtime/vm/builtin-symbol-map.cpp @@ -15,7 +15,7 @@ */ #include "hphp/hack/src/hackc/ffi_bridge/decl_provider.h" -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" #include "hphp/runtime/base/autoload-map.h" #include "hphp/runtime/base/static-string-table.h" diff --git a/hphp/runtime/vm/hackc-translator.h b/hphp/runtime/vm/hackc-translator.h index 65384f7a962187..4b13f6e7088c17 100644 --- a/hphp/runtime/vm/hackc-translator.h +++ b/hphp/runtime/vm/hackc-translator.h @@ -16,7 +16,7 @@ #pragma once -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" #include "hphp/hack/src/hackc/hhbc-unit.h" #include "hphp/runtime/vm/native-func-table.h" #include "hphp/runtime/vm/unit-emitter.h" diff --git a/hphp/runtime/vm/unit-parser.cpp b/hphp/runtime/vm/unit-parser.cpp index 39de3ab967b41d..e6dd2855f24eec 100644 --- a/hphp/runtime/vm/unit-parser.cpp +++ b/hphp/runtime/vm/unit-parser.cpp @@ -24,9 +24,9 @@ #include #include -#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/compiler_ffi.rs.h" #include "hphp/hack/src/hackc/hhbc-unit.h" -#include "hphp/hack/src/parser/ffi_bridge/parser_ffi.rs.h" +#include "hphp/hack/src/hhvm_ffi/parser_ffi.rs.h" #include "hphp/runtime/base/autoload-map.h" #include "hphp/runtime/base/file-stream-wrapper.h" #include "hphp/runtime/base/stream-wrapper-registry.h" From c8cbda21045ae74da3a90afdcfb18caa23dad927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 3 Jan 2025 01:37:16 +0100 Subject: [PATCH 30/72] Use underlying type for formatting HPHP::jit::Opcode to fix debug build --- hphp/runtime/vm/jit/ir-opcode.h | 1 + hphp/runtime/vm/jit/ir-unit-inl.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hphp/runtime/vm/jit/ir-opcode.h b/hphp/runtime/vm/jit/ir-opcode.h index 4b8062f43aa58e..601b0f6dfa8d05 100644 --- a/hphp/runtime/vm/jit/ir-opcode.h +++ b/hphp/runtime/vm/jit/ir-opcode.h @@ -19,6 +19,7 @@ #include #include +#include #include #include "hphp/runtime/vm/jit/types.h" diff --git a/hphp/runtime/vm/jit/ir-unit-inl.h b/hphp/runtime/vm/jit/ir-unit-inl.h index ff37f7acbb27c8..d242b7d8d859c4 100644 --- a/hphp/runtime/vm/jit/ir-unit-inl.h +++ b/hphp/runtime/vm/jit/ir-unit-inl.h @@ -129,7 +129,7 @@ struct InstructionBuilder { */ void setter(IRInstruction* inst, Block* target) { assert_flog(!target || inst->hasEdges(), - fmt::format("{}: Mismatch between declared edges and specified target", inst->op()) + fmt::format("{}: Mismatch between declared edges and specified target", fmt::underlying(inst->op())) ); inst->setTaken(target); } From 63eb43c467541702f0239f50e94f56f5f5399c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 3 Jan 2025 01:44:53 +0100 Subject: [PATCH 31/72] Ensure Rust commands execute after OPAM setup --- hphp/hack/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hphp/hack/CMakeLists.txt b/hphp/hack/CMakeLists.txt index cf01f6a84ffbfb..99d80848a4ec97 100644 --- a/hphp/hack/CMakeLists.txt +++ b/hphp/hack/CMakeLists.txt @@ -180,7 +180,7 @@ add_custom_command( ${INVOKE_CARGO} dump-opcodes dump-opcodes --bin dump_opcodes -o "${RUST_OPCODES}" COMMENT "Generating Rust opcode struct for cbindgen to use to generate hhbc-unit.h" - DEPENDS "${OPCODE_DATA}" + DEPENDS opam_setup "${OPCODE_DATA}" ) set(HHBC_AST_HEADER "${RUST_FFI_BUILD_ROOT}/hphp/hack/src/hackc/hhbc-unit.h") @@ -209,7 +209,7 @@ add_custom_command( --header "${HHBC_AST_HEADER}" --namespaces "HPHP,hackc,hhbc" --includes "${FFI_HEADER},${NAMING_SPECIAL_NAMES_HEADER},${TYPE_CONSTRAINT_HEADER},${ATTR_HEADER},${FCALL_HEADER},${ITER_ARGS_HEADER},${HHBC_HEADER}" ${HHBC_AST_SRCS} - DEPENDS rustc cargo "${RUST_OPCODES}" + DEPENDS opam_setup rustc cargo "${RUST_OPCODES}" COMMENT "Generating hhbc-unit.h" ) @@ -259,7 +259,7 @@ add_custom_command( . "${CMAKE_CURRENT_BINARY_DIR}/dev_env_rust_only.sh" && ${CMAKE_COMMAND} -E env CXX=${CMAKE_CXX_COMPILER} CXXFLAGS=${CMAKE_CXX_FLAGS} ${INVOKE_CARGO} hhvm_ffi hhvm_ffi --target-dir "${FFI_BRIDGE_BIN}" WORKING_DIRECTORY ${FFI_BRIDGE_SRC} - DEPENDS rustc cargo hackc_options "${OPCODE_DATA}" + DEPENDS opam_setup rustc cargo hackc_options "${OPCODE_DATA}" ) add_custom_target( From 8f3cd282aec3f536558ea5fffe003c4b6d188cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:37:24 +0100 Subject: [PATCH 32/72] Generate config headers from configs.specification --- hphp/hack/src/Cargo.lock | 1 + .../hackc/compile/cargo/options/Cargo.toml | 1 - hphp/tools/configs/Cargo.lock | 19 ++++++++------- hphp/tools/configs/Cargo.toml | 23 +++++++++++++++++++ 4 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 hphp/tools/configs/Cargo.toml diff --git a/hphp/hack/src/Cargo.lock b/hphp/hack/src/Cargo.lock index 9cbdf2fb612fa3..40b97ec61b2018 100644 --- a/hphp/hack/src/Cargo.lock +++ b/hphp/hack/src/Cargo.lock @@ -2025,6 +2025,7 @@ version = "0.0.0" dependencies = [ "anyhow", "cc", + "clap 4.5.20", "convert_case 0.4.0", "nom 8.0.0", ] diff --git a/hphp/hack/src/hackc/compile/cargo/options/Cargo.toml b/hphp/hack/src/hackc/compile/cargo/options/Cargo.toml index 071e3b9498c33d..16d7b68cba42d1 100644 --- a/hphp/hack/src/hackc/compile/cargo/options/Cargo.toml +++ b/hphp/hack/src/hackc/compile/cargo/options/Cargo.toml @@ -22,4 +22,3 @@ serde = { version = "1.0.185", features = ["derive", "rc"] } generate_configs_lib = { version = "0.0.0", path = "../../../../../../tools/configs" } nom = "8" nom-language = "0.1" -nom = "7.1" diff --git a/hphp/tools/configs/Cargo.lock b/hphp/tools/configs/Cargo.lock index 0db6a6312cb135..d019fd47d7c05a 100644 --- a/hphp/tools/configs/Cargo.lock +++ b/hphp/tools/configs/Cargo.lock @@ -146,6 +146,7 @@ dependencies = [ "clap", "convert_case", "nom", + "nom-language", ] [[package]] @@ -179,19 +180,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] -name = "minimal-lexical" -version = "0.2.1" +name = "nom" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] [[package]] -name = "nom" -version = "7.1.3" +name = "nom-language" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "2de2bc5b451bfedaef92c90b8939a8fff5770bdcc1fafd6239d086aab8fa6b29" dependencies = [ - "memchr", - "minimal-lexical", + "nom", ] [[package]] diff --git a/hphp/tools/configs/Cargo.toml b/hphp/tools/configs/Cargo.toml new file mode 100644 index 00000000000000..24ddedb1f96697 --- /dev/null +++ b/hphp/tools/configs/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "generate_configs_lib" +version = "0.0.0" +edition = "2021" +repository = "https://github.com/facebook/hhvm" +license = "MIT" + +[[bin]] +name = "generate_configs" +path = "generate_configs.rs" + +[lib] +path = "generate_configs_lib.rs" + +[dependencies] +clap = { version = "4.5.20", features = ["derive", "env", "string", "unicode", "wrap_help"] } +convert_case = "0.4.0" +nom = "8" +nom-language = "0.1" + +[build-dependencies] +anyhow = "1.0.86" +cc = "1.0.90" From 909ea32b9416cd55fbf71a8aa9aa776303fc56af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 3 Jan 2025 03:43:19 +0100 Subject: [PATCH 33/72] Add missing dependencies for gd and lmdb extensions --- CMake/FindLibheif.cmake | 23 +++++++++++++++++++++++ CMake/FindLmdb.cmake | 17 +++++++++++++++++ CMake/HHVMExtensionConfig.cmake | 22 ++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 CMake/FindLibheif.cmake create mode 100644 CMake/FindLmdb.cmake diff --git a/CMake/FindLibheif.cmake b/CMake/FindLibheif.cmake new file mode 100644 index 00000000000000..3c05aaee26b660 --- /dev/null +++ b/CMake/FindLibheif.cmake @@ -0,0 +1,23 @@ +if(LIBHEIF_FOUND) + set(LIBHEIF_FIND_QUIETLY TRUE) +endif() + +find_path(LIBHEIF_INCLUDE_DIR + NAMES heif.h + PATH_SUFFIXES libheif + PATHS /usr/include /usr/local/include /usr/pkg/include +) + +find_library(LIBHEIF_LIBRARY + NAMES heif + PATHS /lib /usr/lib /usr/local/lib /usr/pkg/lib +) + +if(LIBHEIF_INCLUDE_DIR AND LIBHEIF_LIBRARY) + set(LIBHEIF_FOUND TRUE) +endif() + +mark_as_advanced( + LIBHEIF_INCLUDE_DIR + LIBHEIF_LIBRARY +) diff --git a/CMake/FindLmdb.cmake b/CMake/FindLmdb.cmake new file mode 100644 index 00000000000000..4e9cdabe663ac8 --- /dev/null +++ b/CMake/FindLmdb.cmake @@ -0,0 +1,17 @@ +if(LMDB_FOUND) + set(LMDB_FIND_QUIETLY TRUE) +endif() + +find_path(LMDB_INCLUDE_DIR + NAMES lmdb.h + PATHS /usr/include /usr/local/include /usr/pkg/include +) + +find_library(LMDB_LIBRARY + NAMES lmdb + PATHS /lib /usr/lib /usr/local/lib /usr/pkg/lib +) + +if(LMDB_INCLUDE_DIR AND LMDB_LIBRARY) + set(LMDB_FOUND TRUE) +endif() diff --git a/CMake/HHVMExtensionConfig.cmake b/CMake/HHVMExtensionConfig.cmake index ca2634652a1f46..958d6e60dea00c 100644 --- a/CMake/HHVMExtensionConfig.cmake +++ b/CMake/HHVMExtensionConfig.cmake @@ -780,6 +780,17 @@ function (HHVM_EXTENSION_INTERNAL_HANDLE_LIBRARY_DEPENDENCY extensionID dependen HHVM_EXTENSION_INTERNAL_ADD_LINK_LIBRARIES(${GMP_LIBRARY}) HHVM_EXTENSION_INTERNAL_ADD_DEFINES("-DHAVE_LIBGMP") endif() + elseif (${libraryName} STREQUAL "heif") + find_package(Libheif ${requiredVersion} REQUIRED) + if (NOT LIBHEIF_INCLUDE_DIR OR NOT LIBHEIF_LIBRARY) + HHVM_EXTENSION_INTERNAL_SET_FAILED_DEPENDENCY(${extensionID} ${dependencyName}) + return() + endif() + + if (${addPaths}) + HHVM_EXTENSION_INTERNAL_ADD_INCLUDE_DIRS(${LIBHEIF_INCLUDE_DIR}) + HHVM_EXTENSION_INTERNAL_ADD_LINK_LIBRARIES(${LIBHEIF_LIBRARY}) + endif() elseif (${libraryName} STREQUAL "iconv") find_package(Libiconv ${requiredVersion}) if (NOT LIBICONV_INCLUDE_DIR) @@ -863,6 +874,17 @@ function (HHVM_EXTENSION_INTERNAL_HANDLE_LIBRARY_DEPENDENCY extensionID dependen HHVM_EXTENSION_INTERNAL_ADD_LINK_LIBRARIES(${LDAP_LIBRARIES}) HHVM_EXTENSION_INTERNAL_ADD_DEFINES("-DHAVE_LIBLDAP") endif() + elseif (${libraryName} STREQUAL "lmdb") + find_package(Lmdb ${requiredVersion} REQUIRED) + if (NOT LMDB_INCLUDE_DIR OR NOT LMDB_LIBRARY) + HHVM_EXTENSION_INTERNAL_SET_FAILED_DEPENDENCY(${extensionID} ${dependencyName}) + return() + endif() + + if (${addPaths}) + HHVM_EXTENSION_INTERNAL_ADD_INCLUDE_DIRS(${LMDB_INCLUDE_DIR}) + HHVM_EXTENSION_INTERNAL_ADD_LINK_LIBRARIES(${LMDB_LIBRARY}) + endif() elseif (${libraryName} STREQUAL "magickwand") find_package(LibMagickWand ${requiredVersion}) if (NOT LIBMAGICKWAND_INCLUDE_DIRS OR NOT LIBMAGICKWAND_LIBRARIES OR NOT LIBMAGICKCORE_LIBRARIES) From 3f24b065c8c55a481fe3616a237445fee2b76c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 3 Jan 2025 03:53:56 +0100 Subject: [PATCH 34/72] Link fizz against liboqs transitively if it was found --- third-party/fizz/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/third-party/fizz/CMakeLists.txt b/third-party/fizz/CMakeLists.txt index d2445c2e929684..8499713218d956 100644 --- a/third-party/fizz/CMakeLists.txt +++ b/third-party/fizz/CMakeLists.txt @@ -93,4 +93,9 @@ target_link_libraries( fizz_deps ) +find_package(liboqs CONFIG) +if (liboqs_FOUND) + target_link_libraries(fizz INTERFACE OQS::oqs) +endif() + set(FIZZ_INSTALL_DIR "${INSTALL_DIR}" PARENT_SCOPE) From 7f0d1b33735549bf550969a14c543d494a73e29e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 3 Jan 2025 04:59:20 +0100 Subject: [PATCH 35/72] Pass CMAKE_CXX_FLAGS to tbb --- third-party/tbb/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/third-party/tbb/CMakeLists.txt b/third-party/tbb/CMakeLists.txt index 04603347f35df9..48ad49b956be8e 100644 --- a/third-party/tbb/CMakeLists.txt +++ b/third-party/tbb/CMakeLists.txt @@ -20,6 +20,7 @@ ExternalProject_Add( tbb_root=${TBB_ROOT} CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} + CXXFLAGS=${CMAKE_CXX_FLAGS} # TODO: We should pass CFLAGS/CXXFLAGS. tbb INSTALL_COMMAND "" From f05e8617506f2338134dceed3d82b7d21b9ec66d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 3 Jan 2025 15:54:38 +0100 Subject: [PATCH 36/72] Add missing 'long long' rr::serialize() specialization --- hphp/runtime/base/record-replay.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hphp/runtime/base/record-replay.cpp b/hphp/runtime/base/record-replay.cpp index bfd6169555ca43..145cea195f6e98 100644 --- a/hphp/runtime/base/record-replay.cpp +++ b/hphp/runtime/base/record-replay.cpp @@ -189,6 +189,11 @@ String serialize(const std::exception_ptr& value) { } } +template<> +String serialize(long long value) { + return serialize(Variant{value}); +} + template<> String serialize(std::int64_t value) { return serialize(Variant{value}); From 535521d4e4727d1fb837af535c588907274b0915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 5 Jan 2025 14:55:38 +0100 Subject: [PATCH 37/72] support new libdwarfp API --- CMake/FindLibDwarf.cmake | 69 ++++- CMake/HPHPFindLibs.cmake | 12 + hphp/runtime/vm/debug/dwarf.h | 2 +- hphp/runtime/vm/debug/elfwriter.cpp | 443 ++++++++++++++++++++++++---- hphp/util/eh-frame.h | 3 + 5 files changed, 454 insertions(+), 75 deletions(-) diff --git a/CMake/FindLibDwarf.cmake b/CMake/FindLibDwarf.cmake index 2dc6142b47bed9..1e4eb649d584ad 100644 --- a/CMake/FindLibDwarf.cmake +++ b/CMake/FindLibDwarf.cmake @@ -25,36 +25,72 @@ endif (LIBDWARF_LIBRARIES AND LIBDWARF_INCLUDE_DIRS) find_package(PkgConfig) pkg_check_modules(PkgConfig_LibDwarf QUIET libdwarf) +set( + LIBDWARF_INCLUDE_PATHS + ${PkgConfig_LibDwarf_INCLUDE_DIRS} + /usr/include + /usr/include/libdwarf + /usr/local/include + /usr/local/include/libdwarf + /opt/local/include + /sw/include +) + find_path (DWARF_INCLUDE_DIR NAMES libdwarf.h dwarf.h PATHS - ${PkgConfig_LibDwarf_INCLUDE_DIRS} - /usr/include - /usr/include/libdwarf - /usr/local/include - /usr/local/include/libdwarf - /opt/local/include - /sw/include + ${LIBDWARF_INCLUDE_PATHS} ENV CPATH) # PATH and INCLUDE will also work if (DWARF_INCLUDE_DIR) set (LIBDWARF_INCLUDE_DIRS ${DWARF_INCLUDE_DIR}) endif () +set(LIBDWARF_LIBRARY_NAMES dwarf libdwarf) + +find_path (LIBDWARF_PRODUCER_PATHS + NAMES + libdwarfp.h + PATHS + ${LIBDWARF_INCLUDE_PATHS} + ENV CPATH +) + +set( + LIBDWARF_LIBRARY_PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ${PkgConfig_LibDwarf_LIBRARY_DIRS} + ENV LIBRARY_PATH # PATH and LIB will also work + ENV LD_LIBRARY_PATH +) + +if (LIBDWARF_PRODUCER_PATHS) + set(LIBDWARF_USE_NEW_PRODUCER_API 1) +else() + set(LIBDWARF_USE_NEW_PRODUCER_API 0) +endif() + find_library (LIBDWARF_LIBRARIES NAMES dwarf libdwarf PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - /sw/lib - ${PkgConfig_LibDwarf_LIBRARY_DIRS} - ENV LIBRARY_PATH # PATH and LIB will also work - ENV LD_LIBRARY_PATH) -include (FindPackageHandleStandardArgs) + ${LIBDWARF_LIBRARY_PATHS}) + +if (LIBDWARF_USE_NEW_PRODUCER_API) + find_library (LIBDWARFP_LIBRARIES + NAMES + dwarfp libdwarfp + PATHS + ${LIBDWARF_LIBRARY_PATHS}) + list(APPEND LIBDWARF_LIBRARIES ${LIBDWARFP_LIBRARIES}) +endif() + +include (FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LIBDWARF_FOUND to TRUE # if all listed variables are TRUE @@ -106,7 +142,7 @@ if (LIBDWARF_LIBRARIES AND LIBDWARF_INCLUDE_DIRS) # Order is important, last one is used. CHECK_LIBDWARF_INIT("dwarf_producer_init" - "0, dwarfCallback, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr" 0) + "0, dwarfCallback, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr" 0) CHECK_LIBDWARF_INIT("dwarf_producer_init_c" "0, dwarfCallback, nullptr, nullptr, nullptr, nullptr" 1) set(CMAKE_REQUIRED_INCLUDES) @@ -127,3 +163,4 @@ endif() mark_as_advanced(LIBDW_INCLUDE_DIR DWARF_INCLUDE_DIR) mark_as_advanced(LIBDWARF_INCLUDE_DIRS LIBDWARF_LIBRARIES) mark_as_advanced(LIBDWARF_CONST_NAME LIBDWARF_USE_INIT_C) +mark_as_advanced(LIBDWARF_USE_NEW_PRODUCER_API) diff --git a/CMake/HPHPFindLibs.cmake b/CMake/HPHPFindLibs.cmake index c954f81f514cd0..c109b6092b5fbd 100644 --- a/CMake/HPHPFindLibs.cmake +++ b/CMake/HPHPFindLibs.cmake @@ -238,6 +238,10 @@ if (NOT WINDOWS) add_definitions("-DLIBDWARF_USE_INIT_C") endif() + if (LIBDWARF_USE_NEW_PRODUCER_API) + add_definitions("-DLIBDWARF_USE_NEW_PRODUCER_API") + endif() + find_package(LibElf REQUIRED) include_directories(${LIBELF_INCLUDE_DIRS}) if (ELF_GETSHDRSTRNDX) @@ -274,6 +278,10 @@ if (APPLE) find_library(KERBEROS_LIB NAMES gssapi_krb5) endif() +if (LINUX) + find_package(LibUnwind REQUIRED) +endif() + # This is required by Homebrew's libc. See # https://github.com/facebook/hhvm/pull/5728#issuecomment-124290712 # for more info. @@ -335,6 +343,10 @@ macro(hphp_link target) target_link_libraries(${target} ${VISIBILITY} ${CURL_LIBRARIES}) target_link_libraries(${target} ${VISIBILITY} glog) + if (LINUX) + target_link_libraries(${target} ${VISIBILITY} ${LIBUNWIND_LIBRARIES}) + endif() + if (LIBINOTIFY_LIBRARY) target_link_libraries(${target} ${VISIBILITY} ${LIBINOTIFY_LIBRARY}) endif() diff --git a/hphp/runtime/vm/debug/dwarf.h b/hphp/runtime/vm/debug/dwarf.h index 2ef1f8beb2f1ad..3e8c82c3821d8e 100644 --- a/hphp/runtime/vm/debug/dwarf.h +++ b/hphp/runtime/vm/debug/dwarf.h @@ -50,7 +50,7 @@ typedef enum { const int DWARF_CODE_ALIGN = 1; const int DWARF_DATA_ALIGN = 8; -#if (defined(HHVM_FACEBOOK) || defined(LIBDWARF_CONST_NAME)) +#if (defined(HHVM_FACEBOOK) || defined(LIBDWARF_CONST_NAME) || defined(LIBDWARF_USE_NEW_PRODUCER_API)) #define LIBDWARF_CALLBACK_NAME_TYPE const char* #else #define LIBDWARF_CALLBACK_NAME_TYPE char* diff --git a/hphp/runtime/vm/debug/elfwriter.cpp b/hphp/runtime/vm/debug/elfwriter.cpp index c7d24a514153db..827c9e5ccb0571 100644 --- a/hphp/runtime/vm/debug/elfwriter.cpp +++ b/hphp/runtime/vm/debug/elfwriter.cpp @@ -16,9 +16,14 @@ #include "hphp/runtime/vm/debug/elfwriter.h" #include "hphp/runtime/vm/debug/gdb-jit.h" #include +#include +#ifdef LIBDWARF_USE_NEW_PRODUCER_API +#include +#endif #include #include #include +#include #include #include @@ -36,6 +41,10 @@ namespace Debug { TRACE_SET_MOD(debuginfo) static const uint8_t CFA_OFFSET = 16; +#ifdef LIBDWARF_USE_NEW_PRODUCER_API +#define DW_DLV_NOCOUNT ((Dwarf_Signed) -1) +#endif + void ElfWriter::logError(const std::string& msg) { perror(""); std::cerr << msg << '\n'; @@ -116,7 +125,7 @@ bool ElfWriter::initDwarfProducer() { bool ElfWriter::initDwarfProducer() { Dwarf_Error error = 0; auto ret = dwarf_producer_init( - DW_DLC_WRITE | DW_DLC_SIZE_64 | DW_DLC_SYMBOLIC_RELOCATIONS, + DW_DLC_SIZE_64 | DW_DLC_SYMBOLIC_RELOCATIONS, g_dwarfCallback, nullptr, nullptr, @@ -134,13 +143,326 @@ bool ElfWriter::initDwarfProducer() { } #endif +Dwarf_Unsigned dwarf_add_expr_gen_compat( + Dwarf_P_Expr expr, + Dwarf_Small opcode, + Dwarf_Unsigned val1, + Dwarf_Unsigned val2, + Dwarf_Error* error +) { + Dwarf_Unsigned len = 0; + int res = dwarf_add_expr_gen_a(expr, opcode, val1, val2, &len, error); + if (res != DW_DLV_OK) { + return DW_DLV_NOCOUNT; + } + + return len; +} + +Dwarf_P_Die dwarf_new_die_compat( + Dwarf_P_Debug producer, + Dwarf_Tag tag, + Dwarf_P_Die parent, + Dwarf_P_Die child, + Dwarf_P_Die left, + Dwarf_P_Die right, + Dwarf_Error* error +) { + Dwarf_P_Die die = nullptr; + int res = dwarf_new_die_a(producer, tag, parent, child, left, right, &die, error); + if (res != DW_DLV_OK) { + return nullptr; + } + + return die; +} + +Dwarf_P_Attribute dwarf_add_AT_name_compat(Dwarf_P_Die die, char* name, Dwarf_Error* error) { + Dwarf_P_Attribute attribute = nullptr; + int res = dwarf_add_AT_name_a(die, name, &attribute, error); + if (res != DW_DLV_OK) { + return nullptr; + } + + return attribute; +} + +Dwarf_P_Attribute dwarf_add_AT_targ_address_compat( + Dwarf_P_Debug producer, + Dwarf_P_Die ownerDie, + Dwarf_Half attr, + Dwarf_Unsigned value, + Dwarf_Unsigned symbolIndex, + Dwarf_Error* error +) { + Dwarf_P_Attribute attribute = nullptr; + int res = dwarf_add_AT_targ_address_c(producer, ownerDie, attr, value, symbolIndex, &attribute, error); + if (res != DW_DLV_OK) { + return nullptr; + } + + return attribute; +} + + +Dwarf_P_Attribute dwarf_add_AT_location_expr_compat( + Dwarf_P_Debug producer, + Dwarf_P_Die ownerDie, + Dwarf_Half attr, + Dwarf_P_Expr locExpr, + Dwarf_Error* error +) { + Dwarf_P_Attribute attribute = nullptr; + int res = dwarf_add_AT_location_expr_a(producer, ownerDie, attr, locExpr, &attribute, error); + if (res != DW_DLV_OK) { + return nullptr; + } + + return attribute; +} + +Dwarf_P_Attribute dwarf_add_AT_reference_compat( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerDie, + Dwarf_Half attr, + Dwarf_P_Die otherDie, + Dwarf_Error* error +) { + Dwarf_P_Attribute attribute = nullptr; + int res = dwarf_add_AT_reference_c(dbg, ownerDie, attr, otherDie, &attribute, error); + if (res != DW_DLV_OK) { + return nullptr; + } + + return attribute; +} + +Dwarf_P_Die dwarf_die_link_compat( + Dwarf_P_Die newDie, + Dwarf_P_Die parent, + Dwarf_P_Die child, + Dwarf_P_Die left, + Dwarf_P_Die right, + Dwarf_Error* error +) { + int res = dwarf_die_link_a(newDie, parent, child, left, right, error); + if (res != DW_DLV_OK) { + return nullptr; + } + + return newDie; +} + +Dwarf_P_Attribute dwarf_add_AT_flag_compat( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerDie, + Dwarf_Half attr, + Dwarf_Small flag, + Dwarf_Error* error +) { + Dwarf_P_Attribute attribute = nullptr; + int res = dwarf_add_AT_flag_a(dbg, ownerDie, attr, flag, &attribute, error); + if (res != DW_DLV_OK) { + return nullptr; + } + + return attribute; +} + +Dwarf_P_Attribute dwarf_add_AT_unsigned_const_compat( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerDie, + Dwarf_Half attr, + Dwarf_Unsigned value, + Dwarf_Error* error +) { + Dwarf_P_Attribute attribute = nullptr; + int res = dwarf_add_AT_unsigned_const_a(dbg, ownerDie, attr, value, &attribute, error); + if (res != DW_DLV_OK) { + return nullptr; + } + + return attribute; +} + +Dwarf_P_Fde dwarf_new_fde_compat( + Dwarf_P_Debug producer, + Dwarf_Error* error +) { + Dwarf_P_Fde fde = nullptr; + int res = dwarf_new_fde_a(producer, &fde, error); + if (res != DW_DLV_OK) { + return nullptr; + } + + return fde; +} + +Dwarf_Unsigned dwarf_add_frame_fde_compat( + Dwarf_P_Debug dbg, + Dwarf_P_Fde fde, + Dwarf_P_Die die, + Dwarf_Unsigned cie, + Dwarf_Unsigned virtAddr, + Dwarf_Unsigned codeLen, + Dwarf_Unsigned symbolIndex, + Dwarf_Error* error +) { + Dwarf_Unsigned index = 0; + int res = dwarf_add_frame_fde_c(dbg, fde, die, cie, virtAddr, codeLen, symbolIndex, 0, 0, &index, error); + if (res != DW_DLV_OK) { + return DW_DLV_NOCOUNT; + } + return index; +} + +Dwarf_Unsigned dwarf_add_file_decl_compat( + Dwarf_P_Debug dbg, + char* name, + Dwarf_Unsigned dirIndex, + Dwarf_Unsigned lastMod, + Dwarf_Unsigned length, + Dwarf_Error* error +) { + Dwarf_Unsigned index = 0; + int res = dwarf_add_file_decl_a(dbg, name, dirIndex, lastMod, length, &index, error); + if (res != DW_DLV_OK) { + return DW_DLV_NOCOUNT; + } + return index; +} + +Dwarf_Unsigned dwarf_lne_set_address_compat( + Dwarf_P_Debug dbg, + Dwarf_Addr addr, + Dwarf_Unsigned fileIndex, + Dwarf_Error* error +) { + int res = dwarf_lne_set_address_a(dbg, addr, fileIndex, error); + if (res != DW_DLV_OK) { + return DW_DLV_NOCOUNT; + } + return 0; +} + +Dwarf_Unsigned dwarf_add_line_entry_compat( + Dwarf_P_Debug dbg, + Dwarf_Unsigned fileIndex, + Dwarf_Addr codeAddress, + Dwarf_Unsigned lineNo, + Dwarf_Signed colNo, + Dwarf_Bool isStmtBegin, + Dwarf_Bool isBBBegin, + Dwarf_Error* error +) { + int res = dwarf_add_line_entry_c(dbg, fileIndex, codeAddress, lineNo, colNo, isStmtBegin, isBBBegin, 0, 0, 0, 0, error); + if (res != DW_DLV_OK) { + return DW_DLV_NOCOUNT; + } + return 0; +} + +Dwarf_Unsigned dwarf_lne_end_sequence_compat( + Dwarf_P_Debug dbg, + Dwarf_Addr endAddress, + Dwarf_Error* error +) { + int res = dwarf_lne_end_sequence_a(dbg, endAddress, error); + if (res != DW_DLV_OK) { + return DW_DLV_NOCOUNT; + } + return 0; +} + +Dwarf_P_Expr dwarf_new_expr_compat(Dwarf_P_Debug producer, Dwarf_Error* error) { + Dwarf_P_Expr expr = nullptr; + int res = dwarf_new_expr_a(producer, &expr, error); + if (res != DW_DLV_OK) { + return nullptr; + } + return expr; +} + +Dwarf_Unsigned dwarf_add_die_to_debug_compat( + Dwarf_P_Debug dbg, + Dwarf_P_Die die, + Dwarf_Error* error +) { + int res = dwarf_add_die_to_debug_a(dbg, die, error); + if (res != DW_DLV_OK) { + return DW_DLV_NOCOUNT; + } + return 0; +} + +Dwarf_Unsigned dwarf_add_frame_cie_compat( + Dwarf_P_Debug dbg, + char* augmenter, + Dwarf_Small codeAlign, + Dwarf_Small dataAlign, + Dwarf_Small returnReg, + Dwarf_Ptr initBytes, + Dwarf_Unsigned initNBytes, + Dwarf_Error* error +) { + Dwarf_Unsigned index = 0; + int res = dwarf_add_frame_cie_a(dbg, augmenter, codeAlign, dataAlign, returnReg, initBytes, initNBytes, &index, error); + if (res != DW_DLV_OK) { + return DW_DLV_NOCOUNT; + } + return index; +} + +Dwarf_Unsigned dwarf_transform_to_disk_form_compat( + Dwarf_P_Debug dbg, + Dwarf_Error* error +) { + std::conditional< + std::is_invocable::value, + Dwarf_Unsigned, + Dwarf_Signed + >::type count; + + int res = dwarf_transform_to_disk_form_a(dbg, &count, error); + if (res == DW_DLV_ERROR) { + return DW_DLV_NOCOUNT; + } + + return static_cast(count); +} + +Dwarf_Ptr dwarf_get_section_bytes_compat( + Dwarf_P_Debug dbg, + Dwarf_Unsigned* sectionIndex, + Dwarf_Unsigned* length, + Dwarf_Error* error +) { + Dwarf_Signed unused; + Dwarf_Ptr bytes = nullptr; + + std::conditional< + std::is_invocable::value, + Dwarf_Unsigned, + Dwarf_Signed + >::type bcSectionIndex; + + int res = dwarf_get_section_bytes_a(dbg, unused, &bcSectionIndex, length, &bytes, error); + if (res != DW_DLV_OK) { + return nullptr; + } + + *sectionIndex = static_cast(bcSectionIndex); + + return bytes; +} + Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { Dwarf_Error error = 0; /* top level DIE for each function */ - Dwarf_P_Die func = dwarf_new_die(m_dwarfProducer, + Dwarf_P_Die func = dwarf_new_die_compat(m_dwarfProducer, DW_TAG_subprogram, nullptr, nullptr, nullptr, nullptr, &error); - if (reinterpret_cast(func) == DW_DLV_BADADDR) { + if (func == nullptr) { logError("unable to create child DIE"); return nullptr; } @@ -150,7 +472,7 @@ Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { /* if this function is from an unseen file, register file name * and get index to file name */ if (it == m_fileDB.end()) { - file = dwarf_add_file_decl(m_dwarfProducer, + file = dwarf_add_file_decl_compat(m_dwarfProducer, (char *)f->file, 0, 0, 1000, &error); if (file == DW_DLV_NOCOUNT) { logError("unable to add file declaration"); @@ -163,24 +485,24 @@ Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { /* add function name attribute to function DIE */ Dwarf_P_Attribute at; - at = dwarf_add_AT_name(func, (char *)f->name.c_str(), &error); - if (reinterpret_cast(at) == DW_DLV_BADADDR) { + at = dwarf_add_AT_name_compat(func, (char *)f->name.c_str(), &error); + if (at == nullptr) { logError("unable to add name attribute to function"); return nullptr; } /* Add lower PC bound to function DIE */ - at = dwarf_add_AT_targ_address(m_dwarfProducer, func, DW_AT_low_pc, + at = dwarf_add_AT_targ_address_compat(m_dwarfProducer, func, DW_AT_low_pc, reinterpret_cast(f->range.begin()), 0, &error); - if (reinterpret_cast(at) == DW_DLV_BADADDR) { + if (at == nullptr) { logError("unable to add low_pc attribute to function"); return nullptr; } /* add upper PC bound to function DIE */ - at = dwarf_add_AT_targ_address(m_dwarfProducer, func, DW_AT_high_pc, + at = dwarf_add_AT_targ_address_compat(m_dwarfProducer, func, DW_AT_high_pc, reinterpret_cast(f->range.end()), 0, &error); - if (reinterpret_cast(at) == DW_DLV_BADADDR) { + if (at == nullptr) { logError("unable to add high_pc attribute to function"); return nullptr; } @@ -188,7 +510,7 @@ Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { /* register line number information for function: * 1. register start address */ Dwarf_Unsigned u; - u = dwarf_lne_set_address(m_dwarfProducer, + u = dwarf_lne_set_address_compat(m_dwarfProducer, reinterpret_cast(f->range.begin()), 0, &error); if (u != 0) { logError("unable to set line start address"); @@ -198,7 +520,7 @@ Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { /* 2. register line number info for each tracelet in function */ std::vector::iterator it2; for (it2 = f->m_lineTable.begin(); it2 != f->m_lineTable.end(); it2++) { - u = dwarf_add_line_entry(m_dwarfProducer, + u = dwarf_add_line_entry_compat(m_dwarfProducer, file, reinterpret_cast(it2->range.begin()), it2->lineNumber, 0, 1, 0, &error); if (u != 0) { @@ -210,7 +532,7 @@ Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { } /* 3. register end address of function */ - u = dwarf_lne_end_sequence(m_dwarfProducer, + u = dwarf_lne_end_sequence_compat(m_dwarfProducer, reinterpret_cast(f->range.end()), &error); if (u != 0) { logError("unable to set line end address"); @@ -219,33 +541,33 @@ Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { { /* 4. register frame base of function */ - Dwarf_P_Expr locExpr = dwarf_new_expr(m_dwarfProducer, &error); + Dwarf_P_Expr locExpr = dwarf_new_expr_compat(m_dwarfProducer, &error); if (locExpr == nullptr) { logError("unable to create new location expression"); return nullptr; } - u = dwarf_add_expr_gen(locExpr, DW_OP_call_frame_cfa, 0, 0, &error); + u = dwarf_add_expr_gen_compat(locExpr, DW_OP_call_frame_cfa, 0, 0, &error); if (u == DW_DLV_NOCOUNT) { logError("unable to add subexpression to location expression"); return nullptr; } - u = dwarf_add_expr_gen(locExpr, DW_OP_const1u, CFA_OFFSET, 0, &error); + u = dwarf_add_expr_gen_compat(locExpr, DW_OP_const1u, CFA_OFFSET, 0, &error); if (u == DW_DLV_NOCOUNT) { logError("unable to add subexpression to location expression"); return nullptr; } - u = dwarf_add_expr_gen(locExpr, DW_OP_minus, 0, 0, &error); + u = dwarf_add_expr_gen_compat(locExpr, DW_OP_minus, 0, 0, &error); if (u == DW_DLV_NOCOUNT) { logError("unable to add subexpression to location expression"); return nullptr; } - Dwarf_P_Attribute frameBaseAttr = dwarf_add_AT_location_expr( + Dwarf_P_Attribute frameBaseAttr = dwarf_add_AT_location_expr_compat( m_dwarfProducer, func, DW_AT_frame_base, locExpr, &error); - if (reinterpret_cast(frameBaseAttr) == DW_DLV_BADADDR) { + if (frameBaseAttr == nullptr) { logError("unable to add frame_base attribute"); return nullptr; } @@ -256,21 +578,21 @@ Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { int i = 1; for (std::vector::iterator it = f->m_namedLocals.begin(); it != f->m_namedLocals.end(); it++) { - Dwarf_P_Die localVar = dwarf_new_die(m_dwarfProducer, + Dwarf_P_Die localVar = dwarf_new_die_compat(m_dwarfProducer, DW_TAG_variable, nullptr, nullptr, nullptr, nullptr, &error); - if (reinterpret_cast(localVar) == DW_DLV_BADADDR) { + if (localVar == nullptr) { logError("unable to create new DIE for local variable"); return nullptr; } /* Create location expression defined w.r.t DW_AT_frame_base */ - Dwarf_P_Expr locExpr = dwarf_new_expr(m_dwarfProducer, &error); + Dwarf_P_Expr locExpr = dwarf_new_expr_compat(m_dwarfProducer, &error); if (locExpr == nullptr) { logError("unable to create new location expression"); return nullptr; } - u = dwarf_add_expr_gen(locExpr, DW_OP_fbreg, + u = dwarf_add_expr_gen_compat(locExpr, DW_OP_fbreg, -(i * sizeof(TypedValue)), 0, &error); ++i; if (u == DW_DLV_NOCOUNT) { @@ -278,33 +600,33 @@ Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { return nullptr; } - Dwarf_P_Attribute locAttr = dwarf_add_AT_location_expr(m_dwarfProducer, + Dwarf_P_Attribute locAttr = dwarf_add_AT_location_expr_compat(m_dwarfProducer, localVar, DW_AT_location, locExpr, &error); - if (reinterpret_cast(locAttr) == DW_DLV_BADADDR) { + if (locAttr == nullptr) { logError("unable to add location attribute to local variable"); return nullptr; } - Dwarf_P_Attribute nameAttr = dwarf_add_AT_name(localVar, const_cast(it->data()), &error); - if (reinterpret_cast(nameAttr) == DW_DLV_BADADDR) { + Dwarf_P_Attribute nameAttr = dwarf_add_AT_name_compat(localVar, const_cast(it->data()), &error); + if (nameAttr == nullptr) { logError("unable to add name attribute to local variable"); return nullptr; } - Dwarf_P_Attribute varTypeAttr = dwarf_add_AT_reference(m_dwarfProducer, + Dwarf_P_Attribute varTypeAttr = dwarf_add_AT_reference_compat(m_dwarfProducer, localVar, DW_AT_type, type, &error); - if (reinterpret_cast(varTypeAttr) == DW_DLV_BADADDR) { + if (varTypeAttr == nullptr) { logError("unable to add type attribute to local variable DIE"); return nullptr; } Dwarf_P_Die res = 0; if (lastLocal != nullptr) { - res = dwarf_die_link(localVar, nullptr, nullptr, lastLocal, nullptr, &error); + res = dwarf_die_link_compat(localVar, nullptr, nullptr, lastLocal, nullptr, &error); } else { - res = dwarf_die_link(localVar, func, nullptr, nullptr, nullptr, &error); + res = dwarf_die_link_compat(localVar, func, nullptr, nullptr, nullptr, &error); } - if (reinterpret_cast(res) == DW_DLV_BADADDR) { + if (res == nullptr) { logError("unable to link die"); return nullptr; } @@ -316,31 +638,31 @@ Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { Dwarf_P_Die ElfWriter::makeLocalTypeDie() { Dwarf_Error error = 0; - Dwarf_P_Die typedValueType = dwarf_new_die(m_dwarfProducer, + Dwarf_P_Die typedValueType = dwarf_new_die_compat(m_dwarfProducer, DW_TAG_structure_type, nullptr, nullptr, nullptr, nullptr, &error); - if (reinterpret_cast(typedValueType) == DW_DLV_BADADDR) { + if (typedValueType == nullptr) { logError("unable to create new DIE for TypedValue type"); return nullptr; } /* hard coding the name of 'HPHP::TypedValue' */ Dwarf_P_Attribute at; - at = dwarf_add_AT_name(typedValueType, "HPHP::TypedValue", &error); - if (reinterpret_cast(at) == DW_DLV_BADADDR) { + at = dwarf_add_AT_name_compat(typedValueType, "HPHP::TypedValue", &error); + if (at == nullptr) { logError("unable to add name attribute to TypedValue type DIE"); return nullptr; } - at = dwarf_add_AT_flag(m_dwarfProducer, + at = dwarf_add_AT_flag_compat(m_dwarfProducer, typedValueType, DW_AT_declaration, 1, &error); - if (reinterpret_cast(at) == DW_DLV_BADADDR) { + if (at == nullptr) { logError("unable to add declaration attribute to TypedValue type DIE"); return nullptr; } - at = dwarf_add_AT_unsigned_const(m_dwarfProducer, + at = dwarf_add_AT_unsigned_const_compat(m_dwarfProducer, typedValueType, DW_AT_byte_size, sizeof(TypedValue), &error); - if (reinterpret_cast(at) == DW_DLV_BADADDR) { + if (at == nullptr) { logError("unable to add byte_size attribute to TypedValue type DIE"); return nullptr; } @@ -353,9 +675,9 @@ bool ElfWriter::addSymbolInfo(DwarfChunk* d) { /* create a top level DIE (debug information entry) * all subsequent DIEs' will be children of this DIE */ - Dwarf_P_Die codeUnit = dwarf_new_die(m_dwarfProducer, + Dwarf_P_Die codeUnit = dwarf_new_die_compat(m_dwarfProducer, DW_TAG_compile_unit, nullptr, nullptr, nullptr, nullptr, &error); - if (reinterpret_cast(codeUnit) == DW_DLV_BADADDR) { + if (codeUnit == nullptr) { logError("unable to create code unit DIE"); return false; } @@ -368,8 +690,8 @@ bool ElfWriter::addSymbolInfo(DwarfChunk* d) { return false; } Dwarf_P_Die linkRes; - linkRes = dwarf_die_link(type, codeUnit, nullptr, nullptr, nullptr, &error); - if (reinterpret_cast(linkRes) == DW_DLV_BADADDR) { + linkRes = dwarf_die_link_compat(type, codeUnit, nullptr, nullptr, nullptr, &error); + if (linkRes == nullptr) { logError("unable to link die"); return false; } @@ -384,11 +706,11 @@ bool ElfWriter::addSymbolInfo(DwarfChunk* d) { } if (lastChild) { - linkRes = dwarf_die_link(func, nullptr, nullptr, lastChild, nullptr, &error); + linkRes = dwarf_die_link_compat(func, nullptr, nullptr, lastChild, nullptr, &error); } else { - linkRes = dwarf_die_link(func, codeUnit, nullptr, nullptr, nullptr, &error); + linkRes = dwarf_die_link_compat(func, codeUnit, nullptr, nullptr, nullptr, &error); } - if (reinterpret_cast(linkRes) == DW_DLV_BADADDR) { + if (linkRes == nullptr) { logError("unable to link die"); return false; } @@ -396,7 +718,7 @@ bool ElfWriter::addSymbolInfo(DwarfChunk* d) { } /* register top level DIE */ - Dwarf_Unsigned res = dwarf_add_die_to_debug(m_dwarfProducer, + Dwarf_Unsigned res = dwarf_add_die_to_debug_compat(m_dwarfProducer, codeUnit, &error); if (res != DW_DLV_OK) { logError("unable to add DIE to DWARF"); @@ -430,7 +752,7 @@ bool ElfWriter::addFrameInfo(DwarfChunk* d) { b.dwarf_cfa_same_value(RSP); /* register above rules in a CIE (common information entry) */ - Dwarf_Signed cie_index = dwarf_add_frame_cie( + Dwarf_Signed cie_index = dwarf_add_frame_cie_compat( m_dwarfProducer, "", DWARF_CODE_ALIGN, @@ -449,8 +771,8 @@ bool ElfWriter::addFrameInfo(DwarfChunk* d) { * an FDE (Frame Description entry) */ FuncPtrDB::iterator it; for (it = d->m_functions.begin(); it != d->m_functions.end(); it++) { - Dwarf_P_Fde fde = dwarf_new_fde(m_dwarfProducer, &error); - if (reinterpret_cast(fde) == DW_DLV_BADADDR) { + Dwarf_P_Fde fde = dwarf_new_fde_compat(m_dwarfProducer, &error); + if (fde == nullptr) { logError("Unable to create FDE"); return false; } @@ -461,12 +783,12 @@ bool ElfWriter::addFrameInfo(DwarfChunk* d) { logError("Unable to add instructions to fde"); return false; } - Dwarf_Unsigned fde_index = dwarf_add_frame_fde( + Dwarf_Unsigned fde_index = dwarf_add_frame_fde_compat( m_dwarfProducer, fde, 0, cie_index, (Dwarf_Unsigned)((*it)->range.begin()), (*it)->range.size(), 0, &error); - if (fde_index == DW_DLV_BADADDR) { + if (fde_index == DW_DLV_NOCOUNT) { logError("Unable to add FDE"); return false; } @@ -523,15 +845,20 @@ bool ElfWriter::addSectionData(int section_index, void *data, uint64_t size) { } bool ElfWriter::writeDwarfInfo() { - Dwarf_Signed sections = dwarf_transform_to_disk_form (m_dwarfProducer, 0); + Dwarf_Unsigned sections = dwarf_transform_to_disk_form_compat(m_dwarfProducer, 0); Dwarf_Signed i = 0; - Dwarf_Signed elf_section_index = 0; + Dwarf_Unsigned elf_section_index = 0; Dwarf_Unsigned length = 0; for (i = 0; i < sections; i++) { - Dwarf_Ptr bytes = dwarf_get_section_bytes( - m_dwarfProducer, 0, &elf_section_index, &length, 0); + Dwarf_Ptr bytes = dwarf_get_section_bytes_compat( + m_dwarfProducer, &elf_section_index, &length, 0); + + if (bytes == nullptr) { + logError("Unable to create section"); + return false; + } if (!addSectionData(elf_section_index, bytes, length)) { logError("Unable to create section"); @@ -632,7 +959,7 @@ ElfWriter::~ElfWriter() { unlink(m_filename.c_str()); } if (m_dwarfProducer != nullptr) - dwarf_producer_finish(m_dwarfProducer, 0); + dwarf_producer_finish_a(m_dwarfProducer, 0); } } diff --git a/hphp/util/eh-frame.h b/hphp/util/eh-frame.h index 8ec0c5da7a624e..278cac6e3c9e2f 100644 --- a/hphp/util/eh-frame.h +++ b/hphp/util/eh-frame.h @@ -30,6 +30,9 @@ #include #include +#ifdef LIBDWARF_USE_NEW_PRODUCER_API +#include +#endif namespace HPHP { From 07eaa4cb8efb2bea40970fd125afce440c8c7707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 5 Jan 2025 16:13:14 +0100 Subject: [PATCH 38/72] Fix tc-print link order --- hphp/tools/tc-print/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hphp/tools/tc-print/CMakeLists.txt b/hphp/tools/tc-print/CMakeLists.txt index 4a5c3438c08923..122aa94c98af2e 100644 --- a/hphp/tools/tc-print/CMakeLists.txt +++ b/hphp/tools/tc-print/CMakeLists.txt @@ -29,7 +29,7 @@ else() endif() add_executable(tc-print ${TC_PRINT_CXX_SOURCES}) -link_object_libraries(tc-print ${HHVM_WHOLE_ARCHIVE_LIBRARIES}) target_link_libraries(tc-print ${HHVM_LINK_LIBRARIES}) +link_object_libraries(tc-print ${HHVM_WHOLE_ARCHIVE_LIBRARIES}) embed_all_systemlibs(tc-print "${CMAKE_CURRENT_BINARY_DIR}/../.." "${CMAKE_CURRENT_BINARY_DIR}/tc-print") From 6f6f2ffc9f32784315506a42a73d1ee7fd76d9d7 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 2 Nov 2022 09:21:50 -0700 Subject: [PATCH 39/72] Fix compilation error with OpenSSL 3 Summary: In OpenSSL 3, `EVP_PKEY_get0_*` functions now return `const` pointers, breaking existing usage depending on mutable pointers returned by OpenSSL 1.x. This diff fix the errors 1. Use `auto` type for return type of `EVP_PKEY_get0_*` functions instead of mutable pointer types. 1. Some `EVP_PKEY_get0_RSA` are replaced with `EVP_PKEY_get1_RSA` in order to get a mutable pointer with the ownership. See https://www.openssl.org/docs/man3.0/man7/crypto.html#LIBRARY-CONVENTIONS for the `get_0` conventions Differential Revision: D40942193 fbshipit-source-id: b9a868aec3d332e9de323cb801af52e2692d4686 --- hphp/runtime/ext/openssl/ext_openssl.cpp | 70 ++++++++++++++++-------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/hphp/runtime/ext/openssl/ext_openssl.cpp b/hphp/runtime/ext/openssl/ext_openssl.cpp index a092577df04d89..742b317c17f303 100644 --- a/hphp/runtime/ext/openssl/ext_openssl.cpp +++ b/hphp/runtime/ext/openssl/ext_openssl.cpp @@ -1905,7 +1905,7 @@ Array HHVM_FUNCTION(openssl_pkey_get_details, const OptResource& key) { case EVP_PKEY_RSA2: { ktype = OPENSSL_KEYTYPE_RSA; - RSA *rsa = EVP_PKEY_get0_RSA(pkey); + auto rsa = EVP_PKEY_get0_RSA(pkey); assertx(rsa); const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; RSA_get0_key(rsa, &n, &e, &d); @@ -1928,7 +1928,7 @@ Array HHVM_FUNCTION(openssl_pkey_get_details, const OptResource& key) { case EVP_PKEY_DSA4: { ktype = OPENSSL_KEYTYPE_DSA; - DSA *dsa = EVP_PKEY_get0_DSA(pkey); + auto dsa = EVP_PKEY_get0_DSA(pkey); assertx(dsa); const BIGNUM *p, *q, *g, *pub_key, *priv_key; DSA_get0_pqg(dsa, &p, &q, &g); @@ -1944,7 +1944,7 @@ Array HHVM_FUNCTION(openssl_pkey_get_details, const OptResource& key) { case EVP_PKEY_DH: { ktype = OPENSSL_KEYTYPE_DH; - DH *dh = EVP_PKEY_get0_DH(pkey); + auto dh = EVP_PKEY_get0_DH(pkey); assertx(dh); const BIGNUM *p, *q, *g, *pub_key, *priv_key; DH_get0_pqg(dh, &p, &q, &g); @@ -2058,11 +2058,17 @@ bool HHVM_FUNCTION(openssl_private_decrypt, const String& data, switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - cryptedlen = RSA_private_decrypt(data.size(), - (unsigned char *)data.data(), - cryptedbuf, - EVP_PKEY_get0_RSA(pkey), - padding); + { + auto rsa = EVP_PKEY_get1_RSA(pkey); + SCOPE_EXIT { + RSA_free(rsa); + }; + cryptedlen = RSA_private_decrypt(data.size(), + (unsigned char *)data.data(), + cryptedbuf, + rsa, + padding); + } if (cryptedlen != -1) { successful = 1; } @@ -2098,11 +2104,17 @@ bool HHVM_FUNCTION(openssl_private_encrypt, const String& data, switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - successful = (RSA_private_encrypt(data.size(), - (unsigned char *)data.data(), - cryptedbuf, - EVP_PKEY_get0_RSA(pkey), - padding) == cryptedlen); + { + auto rsa = EVP_PKEY_get1_RSA(pkey); + SCOPE_EXIT { + RSA_free(rsa); + }; + successful = (RSA_private_encrypt(data.size(), + (unsigned char *)data.data(), + cryptedbuf, + rsa, + padding) == cryptedlen); + } break; default: raise_warning("key type not supported"); @@ -2134,11 +2146,17 @@ bool HHVM_FUNCTION(openssl_public_decrypt, const String& data, switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - cryptedlen = RSA_public_decrypt(data.size(), - (unsigned char *)data.data(), - cryptedbuf, - EVP_PKEY_get0_RSA(pkey), - padding); + { + auto rsa = EVP_PKEY_get1_RSA(pkey); + SCOPE_EXIT { + RSA_free(rsa); + }; + cryptedlen = RSA_public_decrypt(data.size(), + (unsigned char *)data.data(), + cryptedbuf, + rsa, + padding); + } if (cryptedlen != -1) { successful = 1; } @@ -2174,11 +2192,17 @@ bool HHVM_FUNCTION(openssl_public_encrypt, const String& data, switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - successful = (RSA_public_encrypt(data.size(), - (unsigned char *)data.data(), - cryptedbuf, - EVP_PKEY_get0_RSA(pkey), - padding) == cryptedlen); + { + auto rsa = EVP_PKEY_get1_RSA(pkey); + SCOPE_EXIT { + RSA_free(rsa); + }; + successful = (RSA_public_encrypt(data.size(), + (unsigned char *)data.data(), + cryptedbuf, + rsa, + padding) == cryptedlen); + } break; default: raise_warning("key type not supported"); From 8832266ede09f2c121a5842104e6038a71bf453a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 28 Dec 2024 14:54:48 +0100 Subject: [PATCH 40/72] Update systemlib generation to support precompiled systemlibs --- .gitignore | 3 + CMake/HPHPFunctions.cmake | 36 ++- hphp/compiler/compiler-systemlib.cpp | 2 +- hphp/runtime/ext/core/make_systemlib.sh | 2 +- hphp/runtime/ext/core/php.txt | 296 ++++++++++++------------ hphp/system/CMakeLists.txt | 27 +-- hphp/system/php.txt | 1 + hphp/tools/tc-print/CMakeLists.txt | 1 + 8 files changed, 196 insertions(+), 172 deletions(-) create mode 100644 hphp/system/php.txt diff --git a/.gitignore b/.gitignore index 881ca58c8b012a..82373bf8085b46 100644 --- a/.gitignore +++ b/.gitignore @@ -86,6 +86,9 @@ install_manifest.txt /hphp/hack/test/.mypy_cache /hphp/util/generated-hhjs-babel-transform.txt +# Generated core systemlib +/hphp/runtime/ext/core/ext_core.php + # CPack CPackConfig.cmake CPackSourceConfig.cmake diff --git a/CMake/HPHPFunctions.cmake b/CMake/HPHPFunctions.cmake index 9a3f47ddf36106..ad01feededa39d 100644 --- a/CMake/HPHPFunctions.cmake +++ b/CMake/HPHPFunctions.cmake @@ -124,9 +124,6 @@ function(append_systemlib TARGET SOURCE SECTNAME) else() set(${TARGET}_SLIBS ${${TARGET}_SLIBS} "--add-section" "${SECTNAME}=${SOURCE}" PARENT_SCOPE) endif() - # Add the systemlib file to the "LINK_DEPENDS" for the systemlib, this will cause it - # to be relinked and the systemlib re-embedded - set_property(TARGET ${TARGET} APPEND PROPERTY LINK_DEPENDS ${SOURCE}) endif() endfunction(append_systemlib) @@ -186,10 +183,10 @@ function(embed_sections TARGET DEST) endfunction(embed_sections) macro(embed_systemlib_byname TARGET SLIB) - get_filename_component(SLIB_BN ${SLIB} "NAME_WE") - string(LENGTH ${SLIB_BN} SLIB_BN_LEN) - math(EXPR SLIB_BN_REL_LEN "${SLIB_BN_LEN} - 4") - string(SUBSTRING ${SLIB_BN} 4 ${SLIB_BN_REL_LEN} SLIB_EXTNAME) + get_filename_component(SLIB_FILENAME ${SLIB} "NAME") + + set(SLIB_EXTNAME "/:${SLIB_FILENAME}") + string(MD5 SLIB_HASH_NAME ${SLIB_EXTNAME}) # Some platforms limit section names to 16 characters :( string(SUBSTRING ${SLIB_HASH_NAME} 0 12 SLIB_HASH_NAME_SHORT) @@ -204,10 +201,31 @@ endmacro() function(embed_all_systemlibs TARGET ROOT DEST) add_dependencies(${TARGET} systemlib) - append_systemlib(${TARGET} ${ROOT}/system/systemlib.php systemlib) + foreach(SLIB ${EXTENSION_SYSTEMLIB_SOURCES} ${EZC_SYSTEMLIB_SOURCES}) - embed_systemlib_byname(${TARGET} ${SLIB}) + get_filename_component(SLIB_FILENAME ${SLIB} NAME) + file(RELATIVE_PATH SLIB_RELATIVE_PATH ${CMAKE_SOURCE_DIR} ${SLIB}) + list(APPEND SLIB_RELATIVE_PATHS ${SLIB_RELATIVE_PATH}) + list( + APPEND PRECOMPILED_SYSTEMLIB_FILES + ${CMAKE_CURRENT_BINARY_DIR}/slib/${SLIB_FILENAME}.decls + ${CMAKE_CURRENT_BINARY_DIR}/slib/${SLIB_FILENAME}.ue + ) endforeach() + + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/slib + COMMAND $ --compile-systemlib --input-dir ${CMAKE_SOURCE_DIR} --output-dir ${CMAKE_CURRENT_BINARY_DIR}/slib ${SLIB_RELATIVE_PATHS} + DEPENDS ${EXTENSION_SYSTEMLIB_SOURCES} ${EZC_SYSTEMLIB_SOURCES} + COMMENT "Precompiling systemlib files" + VERBATIM) + + foreach(PRECOMPILED_SLIB ${PRECOMPILED_SYSTEMLIB_FILES}) + get_filename_component(PRECOMPILED_SLIB_FILENAME ${PRECOMPILED_SLIB} NAME) + embed_systemlib_byname(${TARGET} ${PRECOMPILED_SLIB}) + endforeach() + embed_sections(${TARGET} ${DEST}) endfunction(embed_all_systemlibs) diff --git a/hphp/compiler/compiler-systemlib.cpp b/hphp/compiler/compiler-systemlib.cpp index 124e81fb4eaea9..eb7a7e34ada495 100644 --- a/hphp/compiler/compiler-systemlib.cpp +++ b/hphp/compiler/compiler-systemlib.cpp @@ -228,7 +228,7 @@ bool process(CompilerOptions &po) { for (auto extension : ExtensionRegistry::getExtensions()) { for (auto file : extension->hackFiles()) { - if (!files.contains(file)) { + if (!files.contains("ext_" + file)) { Logger::Error( "Error while compiling stdlib: %s not found in input files - did you add an extension without any hack files? If so, override hackFiles to return an empty vector.", file.c_str()); } diff --git a/hphp/runtime/ext/core/make_systemlib.sh b/hphp/runtime/ext/core/make_systemlib.sh index cb5e628ebc602c..d30e4a8f59d97d 100755 --- a/hphp/runtime/ext/core/make_systemlib.sh +++ b/hphp/runtime/ext/core/make_systemlib.sh @@ -4,7 +4,7 @@ OUTDIR=$1; shift OUTFILE=$1; shift SYSTEMLIB="${OUTDIR}/${OUTFILE}" -mkdir "${OUTDIR}" +mkdir -p "${OUTDIR}" # If we put the line we're generating into this file, then the linter will think # the generator itself is generated. Encode it into a variable for safe diff --git a/hphp/runtime/ext/core/php.txt b/hphp/runtime/ext/core/php.txt index 5db7e0b08292df..ce779111007411 100644 --- a/hphp/runtime/ext/core/php.txt +++ b/hphp/runtime/ext/core/php.txt @@ -6,158 +6,158 @@ # These restrictions may be lifted at some point in the future. # Order matters here. Put parent classes in this list before child classes -hphp/system/php/lang/stdClass.php -hphp/system/php/lang/Closure.php -hphp/system/php/lang/pinitSentinel.php -hphp/system/php/lang/uninitSentinel.php -hphp/system/php/lang/string.php -hphp/system/php/lang/resource.php - -hphp/system/php/lang/AsyncIterator.ns.php -hphp/system/php/lang/AsyncKeyedIterator.ns.php -hphp/system/php/lang/Traversable.ns.php -hphp/system/php/lang/Iterator.ns.php -hphp/system/php/lang/IteratorAggregate.ns.php -hphp/system/php/lang/KeyedIterator.ns.php -hphp/system/php/lang/KeyedIterable.ns.php -hphp/system/php/lang/Throwable.php -hphp/system/php/lang/BaseException.ns.php -hphp/system/php/lang/Error.php -hphp/system/php/lang/Exception.php -hphp/system/php/spl/exceptions/exceptions.php -hphp/system/php/spl/interfaces/Countable.php -hphp/system/php/spl/interfaces/RecursiveIterator.php - -hphp/system/php/lang/Container.ns.php - -hphp/system/php/spl/datastructures/SplHeap.php - -hphp/system/php/spl/file_handling/SplFileInfo.php -hphp/system/php/spl/interfaces/SeekableIterator.php -hphp/system/php/spl/iterators/DirectoryIterator.php -hphp/system/php/spl/iterators/FilesystemIterator.php -hphp/system/php/spl/iterators/GlobIterator.php -hphp/system/php/spl/iterators/RecursiveDirectoryIterator.php -hphp/system/php/spl/file_handling/SplFileObject.php -hphp/system/php/spl/file_handling/SplTempFileObject.php - -hphp/system/php/lang/ArrayAccess.php -hphp/system/php/lang/Serializeable.php -hphp/system/php/spl/datastructures/SplDoublyLinkedList.php -hphp/system/php/spl/datastructures/SplQueue.php -hphp/system/php/spl/datastructures/SplStack.php - -hphp/system/php/spl/interfaces/OuterIterator.php -hphp/system/php/spl/iterators/IteratorIterator.php -hphp/system/php/spl/iterators/FilterIterator.php -hphp/system/php/spl/iterators/RecursiveFilterIterator.php -hphp/system/php/spl/iterators/RegexIterator.php -hphp/system/php/spl/iterators/RecursiveRegexIterator.php - -hphp/system/php/spl/iterators/ArrayIterator.php - -hphp/system/php/filter/filter_var_array.php - -hphp/system/php/date/datetimeinterface.php -hphp/system/php/date/datetimeimmutable.php - -hphp/system/php/collections/collection_interfaces.ns.php -hphp/system/php/collections/LazyConcatIterable.php -hphp/system/php/collections/LazyConcatIterator.php -hphp/system/php/collections/LazyFilterIterable.php -hphp/system/php/collections/LazyFilterIterator.php -hphp/system/php/collections/LazyFilterKeyedIterable.php -hphp/system/php/collections/LazyFilterKeyedIterator.php -hphp/system/php/collections/LazyFilterWithKeyIterable.php -hphp/system/php/collections/LazyFilterWithKeyIterator.php -hphp/system/php/collections/LazyIterable.php -hphp/system/php/collections/LazyIterableView.php -hphp/system/php/collections/LazyKVZipIterable.php -hphp/system/php/collections/LazyKVZipIterator.php -hphp/system/php/collections/LazyKeyedIterable.php -hphp/system/php/collections/LazyKeyedIterableView.php -hphp/system/php/collections/LazyKeysIterable.php -hphp/system/php/collections/LazyKeysIterator.php -hphp/system/php/collections/LazyMapIterable.php -hphp/system/php/collections/LazyMapIterator.php -hphp/system/php/collections/LazyMapKeyedIterable.php -hphp/system/php/collections/LazyMapKeyedIterator.php -hphp/system/php/collections/LazyMapWithKeyIterable.php -hphp/system/php/collections/LazyMapWithKeyIterator.php -hphp/system/php/collections/LazySkipIterable.php -hphp/system/php/collections/LazySkipIterator.php -hphp/system/php/collections/LazySkipKeyedIterable.php -hphp/system/php/collections/LazySkipKeyedIterator.php -hphp/system/php/collections/LazySkipWhileIterable.php -hphp/system/php/collections/LazySkipWhileIterator.php -hphp/system/php/collections/LazySkipWhileKeyedIterable.php -hphp/system/php/collections/LazySkipWhileKeyedIterator.php -hphp/system/php/collections/LazySliceIterable.php -hphp/system/php/collections/LazySliceIterator.php -hphp/system/php/collections/LazySliceKeyedIterable.php -hphp/system/php/collections/LazySliceKeyedIterator.php -hphp/system/php/collections/LazyTakeIterable.php -hphp/system/php/collections/LazyTakeIterator.php -hphp/system/php/collections/LazyTakeKeyedIterable.php -hphp/system/php/collections/LazyTakeKeyedIterator.php -hphp/system/php/collections/LazyTakeWhileIterable.php -hphp/system/php/collections/LazyTakeWhileIterator.php -hphp/system/php/collections/LazyTakeWhileKeyedIterable.php -hphp/system/php/collections/LazyTakeWhileKeyedIterator.php -hphp/system/php/collections/LazyValuesIterable.php -hphp/system/php/collections/LazyValuesIterator.php -hphp/system/php/collections/LazyZipIterable.php -hphp/system/php/collections/LazyZipIterator.php -hphp/system/php/collections/LazyZipKeyedIterable.php -hphp/system/php/collections/LazyZipKeyedIterator.php -hphp/system/php/collections/StrictIterable.php -hphp/system/php/collections/StrictKeyedIterable.php - -hphp/system/php/async/ResultOrExceptionWrapper.ns.php -hphp/system/php/async/WrappedException.ns.php -hphp/system/php/async/WrappedResult.ns.php -hphp/system/php/async/convenience.ns.php - -hphp/system/php/async/vm.ns.php -hphp/system/php/async/maps.ns.php -hphp/system/php/async/vectors.ns.php +hphp/runtime/ext/core/php/lang/stdClass.php +hphp/runtime/ext/core/php/lang/Closure.php +hphp/runtime/ext/core/php/lang/pinitSentinel.php +hphp/runtime/ext/core/php/lang/uninitSentinel.php +hphp/runtime/ext/core/php/lang/string.php +hphp/runtime/ext/core/php/lang/resource.php + +hphp/runtime/ext/core/php/lang/AsyncIterator.ns.php +hphp/runtime/ext/core/php/lang/AsyncKeyedIterator.ns.php +hphp/runtime/ext/core/php/lang/Traversable.ns.php +hphp/runtime/ext/core/php/lang/Iterator.ns.php +hphp/runtime/ext/core/php/lang/IteratorAggregate.ns.php +hphp/runtime/ext/core/php/lang/KeyedIterator.ns.php +hphp/runtime/ext/core/php/lang/KeyedIterable.ns.php +hphp/runtime/ext/core/php/lang/Throwable.php +hphp/runtime/ext/core/php/lang/BaseException.ns.php +hphp/runtime/ext/core/php/lang/Error.php +hphp/runtime/ext/core/php/lang/Exception.php +hphp/runtime/ext/core/php/spl/exceptions/exceptions.php +hphp/runtime/ext/core/php/spl/interfaces/Countable.php +hphp/runtime/ext/core/php/spl/interfaces/RecursiveIterator.php + +hphp/runtime/ext/core/php/lang/Container.ns.php + +hphp/runtime/ext/core/php/spl/datastructures/SplHeap.php + +hphp/runtime/ext/core/php/spl/file_handling/SplFileInfo.php +hphp/runtime/ext/core/php/spl/interfaces/SeekableIterator.php +hphp/runtime/ext/core/php/spl/iterators/DirectoryIterator.php +hphp/runtime/ext/core/php/spl/iterators/FilesystemIterator.php +hphp/runtime/ext/core/php/spl/iterators/GlobIterator.php +hphp/runtime/ext/core/php/spl/iterators/RecursiveDirectoryIterator.php +hphp/runtime/ext/core/php/spl/file_handling/SplFileObject.php +hphp/runtime/ext/core/php/spl/file_handling/SplTempFileObject.php + +hphp/runtime/ext/core/php/lang/ArrayAccess.php +hphp/runtime/ext/core/php/lang/Serializeable.php +hphp/runtime/ext/core/php/spl/datastructures/SplDoublyLinkedList.php +hphp/runtime/ext/core/php/spl/datastructures/SplQueue.php +hphp/runtime/ext/core/php/spl/datastructures/SplStack.php + +hphp/runtime/ext/core/php/spl/interfaces/OuterIterator.php +hphp/runtime/ext/core/php/spl/iterators/IteratorIterator.php +hphp/runtime/ext/core/php/spl/iterators/FilterIterator.php +hphp/runtime/ext/core/php/spl/iterators/RecursiveFilterIterator.php +hphp/runtime/ext/core/php/spl/iterators/RegexIterator.php +hphp/runtime/ext/core/php/spl/iterators/RecursiveRegexIterator.php + +hphp/runtime/ext/core/php/spl/iterators/ArrayIterator.php + +hphp/runtime/ext/core/php/filter/filter_var_array.php + +hphp/runtime/ext/core/php/date/datetimeinterface.php +hphp/runtime/ext/core/php/date/datetimeimmutable.php + +hphp/runtime/ext/core/php/collections/collection_interfaces.ns.php +hphp/runtime/ext/core/php/collections/LazyConcatIterable.php +hphp/runtime/ext/core/php/collections/LazyConcatIterator.php +hphp/runtime/ext/core/php/collections/LazyFilterIterable.php +hphp/runtime/ext/core/php/collections/LazyFilterIterator.php +hphp/runtime/ext/core/php/collections/LazyFilterKeyedIterable.php +hphp/runtime/ext/core/php/collections/LazyFilterKeyedIterator.php +hphp/runtime/ext/core/php/collections/LazyFilterWithKeyIterable.php +hphp/runtime/ext/core/php/collections/LazyFilterWithKeyIterator.php +hphp/runtime/ext/core/php/collections/LazyIterable.php +hphp/runtime/ext/core/php/collections/LazyIterableView.php +hphp/runtime/ext/core/php/collections/LazyKVZipIterable.php +hphp/runtime/ext/core/php/collections/LazyKVZipIterator.php +hphp/runtime/ext/core/php/collections/LazyKeyedIterable.php +hphp/runtime/ext/core/php/collections/LazyKeyedIterableView.php +hphp/runtime/ext/core/php/collections/LazyKeysIterable.php +hphp/runtime/ext/core/php/collections/LazyKeysIterator.php +hphp/runtime/ext/core/php/collections/LazyMapIterable.php +hphp/runtime/ext/core/php/collections/LazyMapIterator.php +hphp/runtime/ext/core/php/collections/LazyMapKeyedIterable.php +hphp/runtime/ext/core/php/collections/LazyMapKeyedIterator.php +hphp/runtime/ext/core/php/collections/LazyMapWithKeyIterable.php +hphp/runtime/ext/core/php/collections/LazyMapWithKeyIterator.php +hphp/runtime/ext/core/php/collections/LazySkipIterable.php +hphp/runtime/ext/core/php/collections/LazySkipIterator.php +hphp/runtime/ext/core/php/collections/LazySkipKeyedIterable.php +hphp/runtime/ext/core/php/collections/LazySkipKeyedIterator.php +hphp/runtime/ext/core/php/collections/LazySkipWhileIterable.php +hphp/runtime/ext/core/php/collections/LazySkipWhileIterator.php +hphp/runtime/ext/core/php/collections/LazySkipWhileKeyedIterable.php +hphp/runtime/ext/core/php/collections/LazySkipWhileKeyedIterator.php +hphp/runtime/ext/core/php/collections/LazySliceIterable.php +hphp/runtime/ext/core/php/collections/LazySliceIterator.php +hphp/runtime/ext/core/php/collections/LazySliceKeyedIterable.php +hphp/runtime/ext/core/php/collections/LazySliceKeyedIterator.php +hphp/runtime/ext/core/php/collections/LazyTakeIterable.php +hphp/runtime/ext/core/php/collections/LazyTakeIterator.php +hphp/runtime/ext/core/php/collections/LazyTakeKeyedIterable.php +hphp/runtime/ext/core/php/collections/LazyTakeKeyedIterator.php +hphp/runtime/ext/core/php/collections/LazyTakeWhileIterable.php +hphp/runtime/ext/core/php/collections/LazyTakeWhileIterator.php +hphp/runtime/ext/core/php/collections/LazyTakeWhileKeyedIterable.php +hphp/runtime/ext/core/php/collections/LazyTakeWhileKeyedIterator.php +hphp/runtime/ext/core/php/collections/LazyValuesIterable.php +hphp/runtime/ext/core/php/collections/LazyValuesIterator.php +hphp/runtime/ext/core/php/collections/LazyZipIterable.php +hphp/runtime/ext/core/php/collections/LazyZipIterator.php +hphp/runtime/ext/core/php/collections/LazyZipKeyedIterable.php +hphp/runtime/ext/core/php/collections/LazyZipKeyedIterator.php +hphp/runtime/ext/core/php/collections/StrictIterable.php +hphp/runtime/ext/core/php/collections/StrictKeyedIterable.php + +hphp/runtime/ext/core/php/async/ResultOrExceptionWrapper.ns.php +hphp/runtime/ext/core/php/async/WrappedException.ns.php +hphp/runtime/ext/core/php/async/WrappedResult.ns.php +hphp/runtime/ext/core/php/async/convenience.ns.php + +hphp/runtime/ext/core/php/async/vm.ns.php +hphp/runtime/ext/core/php/async/maps.ns.php +hphp/runtime/ext/core/php/async/vectors.ns.php # If you have no inheritance relationship, go here in alphabetical order -hphp/system/php/array_filter.php -hphp/system/php/array_map.php -hphp/system/php/array_reduce.php -hphp/system/php/asio/InvalidOperationException.php -hphp/system/php/async/EntryPoint.ns.php -hphp/system/php/curl/CURLFile.php -hphp/system/php/date/dateperiod.php -hphp/system/php/date/datetime_funcs.php -hphp/system/php/dom/DOMException.php -hphp/system/php/file_system/Directory.php -hphp/system/php/lang/Disposable.php -hphp/system/php/lang/ErrorException.php -hphp/system/php/lang/fun.ns.php -hphp/system/php/lang/invariant.ns.php -hphp/system/php/lang/null.ns.php -hphp/system/php/lang/readonly.ns.php -hphp/system/php/misc/idx.php -hphp/system/php/pdo/PDOException.php -hphp/system/php/rx/mutable.php -hphp/system/php/shapes/ext_shapes.php -hphp/system/php/soap/SoapFault.php -hphp/system/php/spl/datastructures/SplPriorityQueue.php -hphp/system/php/spl/interfaces/SplObserver.php -hphp/system/php/spl/interfaces/SplSubject.php -hphp/system/php/spl/iterators/EmptyIterator.php -hphp/system/php/spl/iterators/InfiniteIterator.php -hphp/system/php/spl/iterators/NoRewindIterator.php -hphp/system/php/spl/iterators/RecursiveIteratorIterator.php -hphp/system/php/experimental_parser_utils.php +hphp/runtime/ext/core/php/array_filter.php +hphp/runtime/ext/core/php/array_map.php +hphp/runtime/ext/core/php/array_reduce.php +hphp/runtime/ext/core/php/asio/InvalidOperationException.php +hphp/runtime/ext/core/php/async/EntryPoint.ns.php +hphp/runtime/ext/core/php/curl/CURLFile.php +hphp/runtime/ext/core/php/date/dateperiod.php +hphp/runtime/ext/core/php/date/datetime_funcs.php +hphp/runtime/ext/core/php/dom/DOMException.php +hphp/runtime/ext/core/php/file_system/Directory.php +hphp/runtime/ext/core/php/lang/Disposable.php +hphp/runtime/ext/core/php/lang/ErrorException.php +hphp/runtime/ext/core/php/lang/fun.ns.php +hphp/runtime/ext/core/php/lang/invariant.ns.php +hphp/runtime/ext/core/php/lang/null.ns.php +hphp/runtime/ext/core/php/lang/readonly.ns.php +hphp/runtime/ext/core/php/misc/idx.php +hphp/runtime/ext/core/php/pdo/PDOException.php +hphp/runtime/ext/core/php/rx/mutable.php +hphp/runtime/ext/core/php/shapes/ext_shapes.php +hphp/runtime/ext/core/php/soap/SoapFault.php +hphp/runtime/ext/core/php/spl/datastructures/SplPriorityQueue.php +hphp/runtime/ext/core/php/spl/interfaces/SplObserver.php +hphp/runtime/ext/core/php/spl/interfaces/SplSubject.php +hphp/runtime/ext/core/php/spl/iterators/EmptyIterator.php +hphp/runtime/ext/core/php/spl/iterators/InfiniteIterator.php +hphp/runtime/ext/core/php/spl/iterators/NoRewindIterator.php +hphp/runtime/ext/core/php/spl/iterators/RecursiveIteratorIterator.php +hphp/runtime/ext/core/php/experimental_parser_utils.php # This provides a temporary workaround for renamed lz4 methods -hphp/system/php/zlib/ext_zlib.php +hphp/runtime/ext/core/php/zlib/ext_zlib.php -hphp/system/php/member_of.ns.php +hphp/runtime/ext/core/php/member_of.ns.php -hphp/system/php/attributes.php +hphp/runtime/ext/core/php/attributes.php -hphp/system/php/password/password.php +hphp/runtime/ext/core/php/password/password.php diff --git a/hphp/system/CMakeLists.txt b/hphp/system/CMakeLists.txt index b287e66452e88a..d741df679d6993 100644 --- a/hphp/system/CMakeLists.txt +++ b/hphp/system/CMakeLists.txt @@ -6,31 +6,32 @@ target_link_libraries(hphp_system hphp_util proxygen hhvm_base_headers) auto_sources(files "*.h" "${CMAKE_CURRENT_SOURCE_DIR}") HHVM_PUBLIC_HEADERS(system ${files}) -FILE(STRINGS "php.txt" SYSTEMLIB_CLASSES) +FILE(STRINGS ${CMAKE_SOURCE_DIR}/hphp/runtime/ext/core/php.txt SYSTEMLIB_CLASSES) set(SYSTEMLIB_SRCS) -set(SYSTEMLIB_SRCS_STR) + foreach(cls ${SYSTEMLIB_CLASSES}) STRING(REGEX REPLACE "[ \t]*#.*" "" cls "${cls}") if (NOT "${cls}" STREQUAL "") - list(APPEND SYSTEMLIB_SRCS "../../${cls}") - set( - SYSTEMLIB_SRCS_STR - "${SYSTEMLIB_SRCS_STR} ${CMAKE_CURRENT_SOURCE_DIR}/../../${cls}" - ) + list(APPEND SYSTEMLIB_SRCS "${CMAKE_SOURCE_DIR}/${cls}") endif() endforeach() +set(CORE_SYSTEMLIB_FILE "${CMAKE_SOURCE_DIR}/hphp/runtime/ext/core/ext_core.php") + add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/systemlib.php + OUTPUT ${CORE_SYSTEMLIB_FILE} DEPENDS "php.txt" ${SYSTEMLIB_SRCS} - COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/make_systemlib.sh" - "${CMAKE_CURRENT_BINARY_DIR}/systemlib.php" - "${SYSTEMLIB_SRCS_STR}" - COMMENT "Generating systemlib.php") + COMMAND "${CMAKE_SOURCE_DIR}/hphp/runtime/ext/core/make_systemlib.sh" + "${CMAKE_SOURCE_DIR}/hphp/runtime/ext/core" + "ext_core.php" + ${SYSTEMLIB_SRCS} + COMMENT "Generating systemlib.php" + VERBATIM + ) add_custom_target( systemlib DEPENDS - ${CMAKE_CURRENT_BINARY_DIR}/systemlib.php + ${CORE_SYSTEMLIB_FILE} generated_systemlib ) diff --git a/hphp/system/php.txt b/hphp/system/php.txt new file mode 100644 index 00000000000000..0d52389ad6f45c --- /dev/null +++ b/hphp/system/php.txt @@ -0,0 +1 @@ +../runtime/ext/core/php.txt diff --git a/hphp/tools/tc-print/CMakeLists.txt b/hphp/tools/tc-print/CMakeLists.txt index 122aa94c98af2e..85c5fbbe66e213 100644 --- a/hphp/tools/tc-print/CMakeLists.txt +++ b/hphp/tools/tc-print/CMakeLists.txt @@ -29,6 +29,7 @@ else() endif() add_executable(tc-print ${TC_PRINT_CXX_SOURCES}) +add_dependencies(tc-print hhvm) target_link_libraries(tc-print ${HHVM_LINK_LIBRARIES}) link_object_libraries(tc-print ${HHVM_WHOLE_ARCHIVE_LIBRARIES}) embed_all_systemlibs(tc-print "${CMAKE_CURRENT_BINARY_DIR}/../.." From fbacde8e1efe08e461842988dbed0aacc707ed39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 5 Jan 2025 19:33:08 +0100 Subject: [PATCH 41/72] Use an Ubuntu 24.04 CI --- .github/workflows/ubuntu.yml | 18 ++++-------------- ci/ubuntu-22.04-jammy/DISTRIBUTION | 1 - ci/ubuntu-22.04-jammy/PKGVER | 1 - ci/ubuntu-24.04-noble/DISTRIBUTION | 1 + ci/ubuntu-24.04-noble/PKGVER | 1 + .../debian/compat | 0 .../debian/conffiles | 0 .../debian/control | 2 +- .../debian/copying | 0 .../debian/format | 0 .../debian/hhvm-nightly-dev.install.in | 0 .../debian/hhvm-nightly.dirs | 0 .../debian/hhvm-nightly.install.in | 0 .../debian/postinst.in | 0 .../debian/postrm | 0 .../debian/preinst | 0 .../debian/prerm.in | 0 .../debian/rules | 7 ++----- 18 files changed, 9 insertions(+), 22 deletions(-) delete mode 100644 ci/ubuntu-22.04-jammy/DISTRIBUTION delete mode 100644 ci/ubuntu-22.04-jammy/PKGVER create mode 100644 ci/ubuntu-24.04-noble/DISTRIBUTION create mode 100644 ci/ubuntu-24.04-noble/PKGVER rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/compat (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/conffiles (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/control (99%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/copying (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/format (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/hhvm-nightly-dev.install.in (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/hhvm-nightly.dirs (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/hhvm-nightly.install.in (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/postinst.in (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/postrm (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/preinst (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/prerm.in (100%) rename ci/{ubuntu-22.04-jammy => ubuntu-24.04-noble}/debian/rules (88%) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 0c566475bbf537..ce5b97dc1d8ecc 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -28,24 +28,14 @@ jobs: build_ubuntu_focal_nightly: runs-on: ubuntu-24.04 container: - image: ubuntu:jammy + image: ubuntu:noble env: - DISTRO: ubuntu-22.04-jammy + DISTRO: ubuntu-24.04-noble IS_NIGHTLY: 1 - CLANG_VERSION: 17 + CLANG_VERSION: 18 steps: - name: Installing dependencies to bootstrap env - run: apt update -y && apt install -y git wget lsb-release software-properties-common gpg - - name: Installing llvm - run: | - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - # Note: Keep this version in sync with the one in the Debian control file. - ./llvm.sh ${CLANG_VERSION} - - # Manually install libc++ as well. - # Don't use ./llvm.sh ${CLANG_VERSION} all to avoid pulling in a broken libunwind. - apt-get install -y libc++-${CLANG_VERSION}-dev libc++abi-${CLANG_VERSION}-dev + run: apt update -y && apt install -y git wget lsb-release software-properties-common gpg clang clang-${CLANG_VERSION} libc++-${CLANG_VERSION}-dev libc++abi-${CLANG_VERSION}-dev - name: Making LLVM the default compiler run: | if [ -f /etc/alternatives/cc ] diff --git a/ci/ubuntu-22.04-jammy/DISTRIBUTION b/ci/ubuntu-22.04-jammy/DISTRIBUTION deleted file mode 100644 index f97ff28ec907d8..00000000000000 --- a/ci/ubuntu-22.04-jammy/DISTRIBUTION +++ /dev/null @@ -1 +0,0 @@ -jammy diff --git a/ci/ubuntu-22.04-jammy/PKGVER b/ci/ubuntu-22.04-jammy/PKGVER deleted file mode 100644 index d06c9bab272a9b..00000000000000 --- a/ci/ubuntu-22.04-jammy/PKGVER +++ /dev/null @@ -1 +0,0 @@ -1~jammy diff --git a/ci/ubuntu-24.04-noble/DISTRIBUTION b/ci/ubuntu-24.04-noble/DISTRIBUTION new file mode 100644 index 00000000000000..465786fba6f71b --- /dev/null +++ b/ci/ubuntu-24.04-noble/DISTRIBUTION @@ -0,0 +1 @@ +noble diff --git a/ci/ubuntu-24.04-noble/PKGVER b/ci/ubuntu-24.04-noble/PKGVER new file mode 100644 index 00000000000000..a75f79b8bac1df --- /dev/null +++ b/ci/ubuntu-24.04-noble/PKGVER @@ -0,0 +1 @@ +1~noble diff --git a/ci/ubuntu-22.04-jammy/debian/compat b/ci/ubuntu-24.04-noble/debian/compat similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/compat rename to ci/ubuntu-24.04-noble/debian/compat diff --git a/ci/ubuntu-22.04-jammy/debian/conffiles b/ci/ubuntu-24.04-noble/debian/conffiles similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/conffiles rename to ci/ubuntu-24.04-noble/debian/conffiles diff --git a/ci/ubuntu-22.04-jammy/debian/control b/ci/ubuntu-24.04-noble/debian/control similarity index 99% rename from ci/ubuntu-22.04-jammy/debian/control rename to ci/ubuntu-24.04-noble/debian/control index 546dac46bdaca3..bcbbfc8cc8bc29 100644 --- a/ci/ubuntu-22.04-jammy/debian/control +++ b/ci/ubuntu-24.04-noble/debian/control @@ -14,7 +14,7 @@ Build-Depends: curl, debhelper (>= 9), flex, - clang-17, + clang-18, gawk, git, gperf, diff --git a/ci/ubuntu-22.04-jammy/debian/copying b/ci/ubuntu-24.04-noble/debian/copying similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/copying rename to ci/ubuntu-24.04-noble/debian/copying diff --git a/ci/ubuntu-22.04-jammy/debian/format b/ci/ubuntu-24.04-noble/debian/format similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/format rename to ci/ubuntu-24.04-noble/debian/format diff --git a/ci/ubuntu-22.04-jammy/debian/hhvm-nightly-dev.install.in b/ci/ubuntu-24.04-noble/debian/hhvm-nightly-dev.install.in similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/hhvm-nightly-dev.install.in rename to ci/ubuntu-24.04-noble/debian/hhvm-nightly-dev.install.in diff --git a/ci/ubuntu-22.04-jammy/debian/hhvm-nightly.dirs b/ci/ubuntu-24.04-noble/debian/hhvm-nightly.dirs similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/hhvm-nightly.dirs rename to ci/ubuntu-24.04-noble/debian/hhvm-nightly.dirs diff --git a/ci/ubuntu-22.04-jammy/debian/hhvm-nightly.install.in b/ci/ubuntu-24.04-noble/debian/hhvm-nightly.install.in similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/hhvm-nightly.install.in rename to ci/ubuntu-24.04-noble/debian/hhvm-nightly.install.in diff --git a/ci/ubuntu-22.04-jammy/debian/postinst.in b/ci/ubuntu-24.04-noble/debian/postinst.in similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/postinst.in rename to ci/ubuntu-24.04-noble/debian/postinst.in diff --git a/ci/ubuntu-22.04-jammy/debian/postrm b/ci/ubuntu-24.04-noble/debian/postrm similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/postrm rename to ci/ubuntu-24.04-noble/debian/postrm diff --git a/ci/ubuntu-22.04-jammy/debian/preinst b/ci/ubuntu-24.04-noble/debian/preinst similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/preinst rename to ci/ubuntu-24.04-noble/debian/preinst diff --git a/ci/ubuntu-22.04-jammy/debian/prerm.in b/ci/ubuntu-24.04-noble/debian/prerm.in similarity index 100% rename from ci/ubuntu-22.04-jammy/debian/prerm.in rename to ci/ubuntu-24.04-noble/debian/prerm.in diff --git a/ci/ubuntu-22.04-jammy/debian/rules b/ci/ubuntu-24.04-noble/debian/rules similarity index 88% rename from ci/ubuntu-22.04-jammy/debian/rules rename to ci/ubuntu-24.04-noble/debian/rules index 14ca6040a6400f..f99ca05c2d5a7a 100644 --- a/ci/ubuntu-22.04-jammy/debian/rules +++ b/ci/ubuntu-24.04-noble/debian/rules @@ -13,18 +13,15 @@ override_dh_auto_configure: -Wno-dev \ -DCMAKE_INSTALL_PREFIX=/opt/hhvm/$(DEB_VERSION_UPSTREAM) \ -DMYSQL_UNIX_SOCK_ADDR=/var/run/mysqld/mysqld.sock \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_BUILD_TYPE=Debug \ -DCLANG_FORCE_LIBCPP=On \ -DFORCE_BUNDLED_LZ4=Off \ -DENABLE_XED=On \ -DENABLE_EXTENSION_MCRYPT=Off \ -DENABLE_EXTENSION_ASYNC_MYSQL=Off \ -DENABLE_MCROUTER=Off \ - -DENABLE_EXTENSION_FB=Off \ -DENABLE_EXTENSION_MYSQL=Off \ - -DENABLE_EXTENSION_OPENSSL=Off \ - -DENABLE_EXTENSION_LIBXML=Off \ - -DENABLE_EXTENSION_SOAP=Off + -DENABLE_EXTENSION_IMAGICK=Off override_dh_auto_build: dh_auto_build --parallel -- bundled_folly From 7f05bcc81d51181f13d4f737f83c42872b471f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 5 Jan 2025 23:38:01 +0100 Subject: [PATCH 42/72] Fix ocamlrep_marshal dune lock --- hphp/hack/src/ocamlrep_marshal/dune | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hphp/hack/src/ocamlrep_marshal/dune b/hphp/hack/src/ocamlrep_marshal/dune index 3dd5ac45b6fc3e..6b9bc5ed236bb1 100644 --- a/hphp/hack/src/ocamlrep_marshal/dune +++ b/hphp/hack/src/ocamlrep_marshal/dune @@ -11,6 +11,6 @@ (targets libocamlrep_marshal_ffi_bindings.a) (deps (source_tree %{workspace_root}/hack/src)) - (locks cargo) + (locks /cargo) (action (run %{workspace_root}/hack/scripts/invoke_cargo.sh ocamlrep_marshal_ffi_bindings ocamlrep_marshal_ffi_bindings))) From 49f6df7f63b389b3dc372c1533134f21570ac5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Mon, 6 Jan 2025 19:20:58 +0100 Subject: [PATCH 43/72] Use Opensource Team-approved runner label --- .github/workflows/ubuntu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index ce5b97dc1d8ecc..8945435b14f647 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -26,7 +26,7 @@ env: jobs: build_ubuntu_focal_nightly: - runs-on: ubuntu-24.04 + runs-on: 8-core-ubuntu container: image: ubuntu:noble env: From a7c7389e7ab2782d9abf07847279857a121ec6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Mon, 6 Jan 2025 23:59:05 +0100 Subject: [PATCH 44/72] Fix tc-print subdirectory load order --- hphp/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hphp/CMakeLists.txt b/hphp/CMakeLists.txt index cc8b48e371eabe..cc1c22c10bc49c 100644 --- a/hphp/CMakeLists.txt +++ b/hphp/CMakeLists.txt @@ -134,7 +134,6 @@ endif() add_subdirectory(tools/hfsort) add_subdirectory(tools/version) -add_subdirectory(tools/tc-print) add_subdirectory(compiler) add_subdirectory(hack) @@ -144,6 +143,10 @@ add_subdirectory(neo) add_subdirectory(runtime) add_subdirectory(runtime/ext) +# Note: tc-print depends on EXTENSION_SYSTEMLIB_SOURCES being already set +# and therefore should be added after extensions. +add_subdirectory(tools/tc-print) + # The runtime/test binary require GTest and GMock to be installed globally option(RUNTIME_TEST_BIN "Create the HHVM runtime/test binary" OFF) if (RUNTIME_TEST_BIN) From be93ce6484ffe2ad13d6c10b7e6a0898e82c5332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Tue, 7 Jan 2025 04:52:29 +0100 Subject: [PATCH 45/72] Switch back to RelWithDebInfo builds after stabilizing CI --- ci/ubuntu-24.04-noble/debian/rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/ubuntu-24.04-noble/debian/rules b/ci/ubuntu-24.04-noble/debian/rules index f99ca05c2d5a7a..fb0a9caff044a9 100644 --- a/ci/ubuntu-24.04-noble/debian/rules +++ b/ci/ubuntu-24.04-noble/debian/rules @@ -13,7 +13,7 @@ override_dh_auto_configure: -Wno-dev \ -DCMAKE_INSTALL_PREFIX=/opt/hhvm/$(DEB_VERSION_UPSTREAM) \ -DMYSQL_UNIX_SOCK_ADDR=/var/run/mysqld/mysqld.sock \ - -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCLANG_FORCE_LIBCPP=On \ -DFORCE_BUNDLED_LZ4=Off \ -DENABLE_XED=On \ From 64509a57d4980fe53ac1c37d9854bcf9d712db3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 1 Feb 2025 17:20:53 +0100 Subject: [PATCH 46/72] Stabilize ocaml build --- hphp/hack/Makefile.dune | 19 ++++++++++++------- hphp/hack/src/Cargo.lock | 10 ++++++++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/hphp/hack/Makefile.dune b/hphp/hack/Makefile.dune index 929c4ca9b1b513..0c666d39b6c65e 100644 --- a/hphp/hack/Makefile.dune +++ b/hphp/hack/Makefile.dune @@ -32,13 +32,18 @@ clean: define build_hack $(eval ext := $(if $(filter $(2),-debug),".bc","")) build-hack$(2): - dune build \ - src/hh_server.$(1) \ - src/hh_client.$(1) \ - src/hh_single_type_check.$(1) \ - src/hackfmt.$(1) \ - src/hh_parse.$(1) \ - src/generate_full_fidelity.$(1) + rm -rf "$(DUNE_BUILD_DIR)/default/target/release" + dune build src/hh_server.$(1) + rm -rf "$(DUNE_BUILD_DIR)/default/target/release" + dune build src/hh_client.$(1) + rm -rf "$(DUNE_BUILD_DIR)/default/target/release" + dune build src/hh_single_type_check.$(1) + rm -rf "$(DUNE_BUILD_DIR)/default/target/release" + dune build src/hackfmt.$(1) + rm -rf "$(DUNE_BUILD_DIR)/default/target/release" + dune build src/hh_parse.$(1) + rm -rf "$(DUNE_BUILD_DIR)/default/target/release" + dune build src/generate_full_fidelity.$(1) copy-hack$(2)-files: build-hack$(2) mkdir -p "$(HACK_BIN_DIR)" diff --git a/hphp/hack/src/Cargo.lock b/hphp/hack/src/Cargo.lock index 40b97ec61b2018..cc09e2e1de1657 100644 --- a/hphp/hack/src/Cargo.lock +++ b/hphp/hack/src/Cargo.lock @@ -3542,7 +3542,7 @@ dependencies = [ "bumpalo", "indexmap 2.10.0", "ocamlrep_derive", - "rustc-hash", + "rustc-hash 1.1.0", "serde", ] @@ -4568,7 +4568,13 @@ checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" From 31dba4e1b976f0ab4b5ac3e0d06ddf555e82b83a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sun, 2 Feb 2025 11:49:05 +0100 Subject: [PATCH 47/72] Lowercase fizz reference --- third-party/thrift/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/third-party/thrift/CMakeLists.txt b/third-party/thrift/CMakeLists.txt index bd5aff7a5281ea..0617037be28773 100644 --- a/third-party/thrift/CMakeLists.txt +++ b/third-party/thrift/CMakeLists.txt @@ -52,6 +52,7 @@ ExternalProject_Add( "-DZSTD_INCLUDE_DIRS=${ZSTD_INCLUDE_DIR}" "-DZSTD_LIBRARIES=${ZSTD_LIBRARY}" + "-Dfizz_DIR=${FIZZ_INSTALL_DIR}/lib/cmake/fizz" "-DFizz_DIR=${FIZZ_INSTALL_DIR}/lib/cmake/fizz" "-Dfmt_DIR=${fmt_DIR}" "-Dfolly_DIR=${FOLLY_INSTALL_DIR}/lib/cmake/folly" From 8c511af652a3da9bfb107673a9316f43c0523aad Mon Sep 17 00:00:00 2001 From: mszabo Date: Tue, 11 Feb 2025 00:41:05 +0100 Subject: [PATCH 48/72] Undefine a MySQL constant until the client is updated --- hphp/runtime/ext/mysql/ext_mysql.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hphp/runtime/ext/mysql/ext_mysql.cpp b/hphp/runtime/ext/mysql/ext_mysql.cpp index 388a67a619783d..04e316ace78cd2 100644 --- a/hphp/runtime/ext/mysql/ext_mysql.cpp +++ b/hphp/runtime/ext/mysql/ext_mysql.cpp @@ -825,7 +825,11 @@ void mysqlExtension::moduleRegisterNative() { HHVM_RC_INT(MYSQL_CLIENT_CR_INSECURE_API_ERR, CR_INSECURE_API_ERR) HHVM_RC_INT(MYSQL_CLIENT_CR_FILE_NAME_TOO_LONG, CR_FILE_NAME_TOO_LONG) HHVM_RC_INT(MYSQL_CLIENT_CR_SSL_FIPS_MODE_ERR, CR_SSL_FIPS_MODE_ERR) +#ifdef CR_DEPRECATED_COMPRESSION_NOT_SUPPORTED HHVM_RC_INT(MYSQL_CLIENT_CR_COMPRESSION_NOT_SUPPORTED, CR_DEPRECATED_COMPRESSION_NOT_SUPPORTED) +#else + HHVM_RC_INT(MYSQL_CLIENT_CR_COMPRESSION_NOT_SUPPORTED, CR_COMPRESSION_NOT_SUPPORTED) +#endif // We can't add the following yet as some builds are not using a new enough MySQL client From a4a25ccf458f595c8dd497077796ff627facad6c Mon Sep 17 00:00:00 2001 From: mszabo Date: Tue, 11 Feb 2025 00:42:24 +0100 Subject: [PATCH 49/72] Remove outdated Squangle patches --- third-party/squangle/CMakeLists.txt | 5 +-- ...-mode-if-we-have-a-MySQL-client-lib-.patch | 42 ------------------- ...o-not-set-MYSQL_OPT_TOS-if-undefined.patch | 20 --------- third-party/squangle/patches/series | 2 - 4 files changed, 2 insertions(+), 67 deletions(-) delete mode 100644 third-party/squangle/patches/0001-only-disable-SSL-mode-if-we-have-a-MySQL-client-lib-.patch delete mode 100644 third-party/squangle/patches/do-not-set-MYSQL_OPT_TOS-if-undefined.patch delete mode 100644 third-party/squangle/patches/series diff --git a/third-party/squangle/CMakeLists.txt b/third-party/squangle/CMakeLists.txt index cb58461a7ccf8a..22a8073fd073cf 100644 --- a/third-party/squangle/CMakeLists.txt +++ b/third-party/squangle/CMakeLists.txt @@ -29,9 +29,6 @@ ExternalProject_Add( "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/squangle-CMakeLists.txt" /CMakeLists.txt - && - "${CMAKE_CURRENT_SOURCE_DIR}/../apply-quilt-patches.sh" - "${CMAKE_CURRENT_SOURCE_DIR}/patches" CMAKE_ARGS "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" -DCMAKE_MODULE_PATH=${CMAKE_SOURCE_DIR}/CMake @@ -40,6 +37,8 @@ ExternalProject_Add( -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} + -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT} -DBoost_NO_SYSTEM_PATHS=ON diff --git a/third-party/squangle/patches/0001-only-disable-SSL-mode-if-we-have-a-MySQL-client-lib-.patch b/third-party/squangle/patches/0001-only-disable-SSL-mode-if-we-have-a-MySQL-client-lib-.patch deleted file mode 100644 index cf88aca09b1560..00000000000000 --- a/third-party/squangle/patches/0001-only-disable-SSL-mode-if-we-have-a-MySQL-client-lib-.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 5237d8ce57269a2f58d1b491f76684d632f96d85 Mon Sep 17 00:00:00 2001 -From: Fred Emmott -Date: Thu, 30 Aug 2018 10:58:40 -0700 -Subject: [PATCH] only disable SSL mode if we have a MySQL client lib that - supports it - ---- - squangle/mysql_client/AsyncMysqlClient.cpp | 2 ++ - squangle/mysql_client/SSLOptionsProviderBase.cpp | 2 ++ - 2 files changed, 4 insertions(+) - -Index: bundled_squangle/squangle/mysql_client/SSLOptionsProviderBase.cpp -=================================================================== ---- bundled_squangle.orig/squangle/mysql_client/SSLOptionsProviderBase.cpp -+++ bundled_squangle/squangle/mysql_client/SSLOptionsProviderBase.cpp -@@ -20,8 +20,10 @@ bool SSLOptionsProviderBase::setMysqlSSL - } - // We need to set ssl_mode because we set it to disabled after we call - // mysql_init. -+#ifdef MYSQL_OPT_SSL_MODE - enum mysql_ssl_mode ssl_mode = SSL_MODE_PREFERRED; - mysql_options(mysql, MYSQL_OPT_SSL_MODE, &ssl_mode); -+#endif - mysql_options(mysql, MYSQL_OPT_SSL_CONTEXT, sslContext->getSSLCtx()); - auto sslSession = getRawSSLSession(); - if (sslSession) { -Index: bundled_squangle/squangle/mysql_client/Connection.cpp -=================================================================== ---- bundled_squangle.orig/squangle/mysql_client/Connection.cpp -+++ bundled_squangle/squangle/mysql_client/Connection.cpp -@@ -46,9 +46,11 @@ void Connection::initMysqlOnly() { - if (!mysql_client_->supportsLocalFiles()) { - mysql_connection_->mysql()->options.client_flag &= ~CLIENT_LOCAL_FILES; - } -+#ifdef MYSQL_OPT_SSL_MODE - // Turn off SSL by default for tests that rely on this. - enum mysql_ssl_mode ssl_mode = SSL_MODE_DISABLED; - mysql_options(mysql_connection_->mysql(), MYSQL_OPT_SSL_MODE, &ssl_mode); -+#endif - } - - void Connection::initialize(bool initMysql) { diff --git a/third-party/squangle/patches/do-not-set-MYSQL_OPT_TOS-if-undefined.patch b/third-party/squangle/patches/do-not-set-MYSQL_OPT_TOS-if-undefined.patch deleted file mode 100644 index fb760d2bcbdfb1..00000000000000 --- a/third-party/squangle/patches/do-not-set-MYSQL_OPT_TOS-if-undefined.patch +++ /dev/null @@ -1,20 +0,0 @@ -Index: bundled_squangle/squangle/mysql_client/Operation.cpp -=================================================================== ---- bundled_squangle.orig/squangle/mysql_client/Operation.cpp -+++ bundled_squangle/squangle/mysql_client/Operation.cpp -@@ -641,6 +641,7 @@ void ConnectOperation::specializedRunImp - (*conn_options_.getSniServerName()).c_str()); - } - -+#ifdef MYSQL_OPT_TOS - if (conn_options_.getDscp().has_value()) { - // DS field (QOS/TOS level) is 8 bits with DSCP packed into the most - // significant 6 bits. -@@ -652,6 +653,7 @@ void ConnectOperation::specializedRunImp - *conn_options_.getDscp()); - } - } -+#endif - - if (conn_options_.getCertValidationCallback()) { - MysqlCertValidatorCallback callback = mysqlCertValidator; diff --git a/third-party/squangle/patches/series b/third-party/squangle/patches/series deleted file mode 100644 index 3f92ca84a02fc8..00000000000000 --- a/third-party/squangle/patches/series +++ /dev/null @@ -1,2 +0,0 @@ -0001-only-disable-SSL-mode-if-we-have-a-MySQL-client-lib-.patch -do-not-set-MYSQL_OPT_TOS-if-undefined.patch From 2b1b1c511976387e055429e91bec99262803b441 Mon Sep 17 00:00:00 2001 From: mszabo Date: Wed, 12 Feb 2025 01:16:31 +0100 Subject: [PATCH 50/72] Use C++20 for building Squangle --- third-party/squangle/squangle-CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/third-party/squangle/squangle-CMakeLists.txt b/third-party/squangle/squangle-CMakeLists.txt index 3fd6d36e2055cf..83d674b31f17ec 100644 --- a/third-party/squangle/squangle-CMakeLists.txt +++ b/third-party/squangle/squangle-CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.10) project(squangle CXX C) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) @@ -23,4 +23,3 @@ target_link_libraries(squangle Folly::folly) install(TARGETS squangle LIBRARY ARCHIVE DESTINATION lib) install(DIRECTORY "${CMAKE_SOURCE_DIR}/" DESTINATION include FILES_MATCHING PATTERN "*.h") - From abf44f0fe24bb672f92e08f0d6ddc2bbf9942749 Mon Sep 17 00:00:00 2001 From: mszabo Date: Fri, 14 Feb 2025 00:01:15 +0100 Subject: [PATCH 51/72] Forward CMAKE_CXX_STANDARD to fizz, mvfst and wangle --- third-party/fizz/CMakeLists.txt | 1 + third-party/mvfst/CMakeLists.txt | 1 + third-party/wangle/CMakeLists.txt | 1 + 3 files changed, 3 insertions(+) diff --git a/third-party/fizz/CMakeLists.txt b/third-party/fizz/CMakeLists.txt index 8499713218d956..0cf4e8bd83fad4 100644 --- a/third-party/fizz/CMakeLists.txt +++ b/third-party/fizz/CMakeLists.txt @@ -53,6 +53,7 @@ ExternalProject_Add( -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT} -DBUILD_TESTS=OFF diff --git a/third-party/mvfst/CMakeLists.txt b/third-party/mvfst/CMakeLists.txt index cdbfd8724d8502..fcb89667305437 100644 --- a/third-party/mvfst/CMakeLists.txt +++ b/third-party/mvfst/CMakeLists.txt @@ -27,6 +27,7 @@ ExternalProject_Add( -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT} -DBUILD_TESTS=OFF diff --git a/third-party/wangle/CMakeLists.txt b/third-party/wangle/CMakeLists.txt index c4bc463403bfaf..f8c3f85e3e4843 100644 --- a/third-party/wangle/CMakeLists.txt +++ b/third-party/wangle/CMakeLists.txt @@ -37,6 +37,7 @@ ExternalProject_Add( -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT} -DBUILD_TESTS=OFF From abe8821a7719f5ebf573cf014041539338b1bf18 Mon Sep 17 00:00:00 2001 From: mszabo Date: Fri, 14 Feb 2025 22:20:45 +0100 Subject: [PATCH 52/72] Remove SSE4.2 and AVX2 toggles in favor of march=x86-64-v3 --- CMake/HPHPCompiler.cmake | 27 ++------------------- CMake/HPHPFindLibs.cmake | 41 +++++++------------------------- CMake/Options.cmake | 4 +--- CMakeLists.txt | 2 +- hphp/util/hphp-config.h.in | 2 -- hphp/util/memset-x64-avx2.S | 2 +- third-party/folly/CMakeLists.txt | 7 ------ 7 files changed, 13 insertions(+), 72 deletions(-) diff --git a/CMake/HPHPCompiler.cmake b/CMake/HPHPCompiler.cmake index fabdbd646299f2..a5b7c0533014e0 100644 --- a/CMake/HPHPCompiler.cmake +++ b/CMake/HPHPCompiler.cmake @@ -93,19 +93,8 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQU endif() if (IS_X64) - # For unclear reasons, our detection for what crc32 intrinsics you have - # will cause Apple clang to ICE. Specifying a baseline here works around - # the issue. (SSE4.2 has been available on processors for quite some time now.) - if(ENABLE_SSE4_2 OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "AppleClang") - list(APPEND GENERAL_CXX_OPTIONS - # SSE4.2 has been available on processors for quite some time now. This - # allows enabling CRC hash function code - "msse4.2" - ) - # Also pass the right option to ASM files to avoid inconsistencies - # in CRC hash function handling - set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -msse4.2") - endif() + list(APPEND GENERAL_CXX_OPTIONS "march=x86-64-v3") + set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -march=x86-64-v3") endif() if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "AppleClang") # using Clang @@ -285,13 +274,6 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQU set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -${opt}") endforeach() - # The ASM part of this makes it more effort than it's worth - # to add these to the general flags system. - if(ENABLE_AVX2) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx2 -march=core-avx2") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx2 -march=core-avx2") - set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -mavx2 -march=core-avx2") - endif() # using Intel C++ elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -no-ipo -fp-model precise -wd584 -wd1418 -wd1918 -wd383 -wd869 -wd981 -wd424 -wd1419 -wd444 -wd271 -wd2259 -wd1572 -wd1599 -wd82 -wd177 -wd593 -w") @@ -349,11 +331,6 @@ elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") list(APPEND MSVC_GENERAL_OPTIONS "MP") endif() - # Enable AVX2 codegen if available and requested. - if (ENABLE_AVX2) - list(APPEND MSVC_GENERAL_OPTIONS "arch:AVX2") - endif() - # Validate, and then add the favored architecture. if (NOT MSVC_FAVORED_ARCHITECTURE STREQUAL "blend" AND NOT MSVC_FAVORED_ARCHITECTURE STREQUAL "AMD64" AND NOT MSVC_FAVORED_ARCHITECTURE STREQUAL "INTEL64" AND NOT MSVC_FAVORED_ARCHITECTURE STREQUAL "ATOM") message(FATAL_ERROR "MSVC_FAVORED_ARCHITECTURE must be set to one of exactly, 'blend', 'AMD64', 'INTEL64', or 'ATOM'! Got '${MSVC_FAVORED_ARCHITECTURE}' instead!") diff --git a/CMake/HPHPFindLibs.cmake b/CMake/HPHPFindLibs.cmake index c109b6092b5fbd..05fc964eebc0d4 100644 --- a/CMake/HPHPFindLibs.cmake +++ b/CMake/HPHPFindLibs.cmake @@ -442,39 +442,14 @@ macro(hphp_link target) target_link_libraries(${target} ${VISIBILITY} dbghelp.lib dnsapi.lib) endif() -# Check whether atomic operations require -latomic or not -# See https://github.com/facebook/hhvm/issues/5217 - include(CheckCXXSourceCompiles) - set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - set(CMAKE_REQUIRED_FLAGS "-std=c++1y") - CHECK_CXX_SOURCE_COMPILES(" -#include -#include -#include -int main() { - struct Test { int64_t val1; int64_t val2; }; - std::atomic s; - // Do this to stop modern compilers from optimizing away the libatomic - // calls in release builds, making this test always pass in release builds, - // and incorrectly think that HHVM doesn't need linking against libatomic. - bool (std::atomic::* volatile x)(void) const = - &std::atomic::is_lock_free; - std::cout << (s.*x)() << std::endl; -} - " NOT_REQUIRE_ATOMIC_LINKER_FLAG) - - if(NOT "${NOT_REQUIRE_ATOMIC_LINKER_FLAG}") - message(STATUS "-latomic is required to link hhvm") - find_library(ATOMIC_LIBRARY NAMES atomic libatomic.so.1) - if (ATOMIC_LIBRARY STREQUAL "ATOMIC_LIBRARY-NOTFOUND") - # -latomic should be available for gcc even when libatomic.so.1 is not - # in the library search path - target_link_libraries(${target} ${VISIBILITY} atomic) - else() - target_link_libraries(${target} ${VISIBILITY} ${ATOMIC_LIBRARY}) - endif() - endif() - set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) + find_library(ATOMIC_LIBRARY NAMES atomic libatomic.so.1) + if (ATOMIC_LIBRARY STREQUAL "ATOMIC_LIBRARY-NOTFOUND") + # -latomic should be available for gcc even when libatomic.so.1 is not + # in the library search path + target_link_libraries(${target} ${VISIBILITY} atomic) + else() + target_link_libraries(${target} ${VISIBILITY} ${ATOMIC_LIBRARY}) + endif() if (ENABLE_XED) if (LibXed_FOUND) diff --git a/CMake/Options.cmake b/CMake/Options.cmake index a26e8e47f80436..8ad29c42504e81 100644 --- a/CMake/Options.cmake +++ b/CMake/Options.cmake @@ -3,10 +3,8 @@ option(ALWAYS_ASSERT "Enabled asserts in a release build" OFF) option(ENABLE_SSP "Enabled GCC/LLVM stack-smashing protection" OFF) option(STATIC_CXX_LIB "Statically link libstd++ and libgcc." OFF) -option(ENABLE_AVX2 "Enable the use of AVX2 instructions" OFF) option(ENABLE_AARCH64_CRC "Enable the use of CRC instructions" OFF) option(ENABLE_FASTCGI "Enable the FastCGI interface." ON) -option(ENABLE_SSE4_2 "Enable SSE4.2 supported code." OFF) option(EXECUTION_PROFILER "Enable the execution profiler" OFF) @@ -44,7 +42,7 @@ option(ENABLE_PROXYGEN_SERVER "Build the Proxygen HTTP server" ON) option(ENABLE_SPLIT_DWARF "Reduce linker memory usage by putting debugging information into .dwo files" OFF) IF (LINUX) - option(MAP_TEXT_HUGE_PAGES "Remap hot static code onto huge pages" ON) + option(MAP_TEXT_HUGE_PAGES "Remap hot static code onto huge pages" ON) ENDIF() IF (NOT DEFAULT_CONFIG_DIR) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc7b18f9698343..2487d03fd2040f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,7 @@ if(NOT SKIP_CCACHE) message(STATUS "Found ccache: ${CCACHE_FOUND} - enabling ccache as compiler wrapper") else() message(STATUS "Found ccache - ccache already in use as C and/or CXX compiler wrapper") - endif() + endif() endif(CCACHE_FOUND) endif(NOT SKIP_CCACHE) diff --git a/hphp/util/hphp-config.h.in b/hphp/util/hphp-config.h.in index a63b1cc35f3202..53c4411d220a9d 100644 --- a/hphp/util/hphp-config.h.in +++ b/hphp/util/hphp-config.h.in @@ -39,11 +39,9 @@ */ #ifdef USE_CMAKE -#cmakedefine ENABLE_AVX2 1 #cmakedefine ENABLE_AARCH64_CRC 1 #cmakedefine EXECUTION_PROFILER 1 #else -/* #undef ENABLE_AVX2 */ /* #undef ENABLE_AARCH64_CRC */ /* #undef EXECUTION_PROFILER */ #endif diff --git a/hphp/util/memset-x64-avx2.S b/hphp/util/memset-x64-avx2.S index 2cbf543b465342..be5ee84314a94a 100644 --- a/hphp/util/memset-x64-avx2.S +++ b/hphp/util/memset-x64-avx2.S @@ -101,7 +101,7 @@ ETCH_LABEL(more_than_63bytes): addq %rax, %rcx subq %rax, %rdx je ETCH_LABEL(EXIT_MEMSET) - + ETCH_ALIGN8 ETCH_ALIGN4 ETCH_LABEL(128byte_loop_data_guzzler): diff --git a/third-party/folly/CMakeLists.txt b/third-party/folly/CMakeLists.txt index cbe7facf590c49..13560b75594760 100644 --- a/third-party/folly/CMakeLists.txt +++ b/third-party/folly/CMakeLists.txt @@ -27,13 +27,6 @@ get_filename_component(BOOST_LIBRARY_DIR "${FIRST_LIB}" DIRECTORY) set(FOLLY_CXXFLAGS "-I${JEMALLOC_INCLUDE_DIR} -I${CMAKE_CURRENT_LIST_DIR}/include") message(STATUS "FOLLY_CXXFLAGS: ${FOLLY_CXXFLAGS}") -if(ENABLE_SSE4_2 OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "AppleClang") - if(IS_X64) - message(STATUS "Enabling SSE 4.2 for bundled folly") - set(FOLLY_CXXFLAGS "${FOLLY_CXXFLAGS} -msse4.2") - endif() -endif() - ExternalProject_add( bundled_folly SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/ From eabb229add1b4ad2dd45e63e8ae51ef24522349e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 14 Mar 2025 00:38:04 +0100 Subject: [PATCH 53/72] Add sandcastle module dependency --- hphp/hack/src/client_and_server/dune | 1 + 1 file changed, 1 insertion(+) diff --git a/hphp/hack/src/client_and_server/dune b/hphp/hack/src/client_and_server/dune index a6b9e6db491eea..fcf54fdae6a0a4 100644 --- a/hphp/hack/src/client_and_server/dune +++ b/hphp/hack/src/client_and_server/dune @@ -396,6 +396,7 @@ (libraries ci_util client_provider + sandcastle server_config server_notifier) (preprocess From 9312231e88d4de18224a9fb480c4918f9e7c9b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Tue, 18 Mar 2025 13:51:52 +0100 Subject: [PATCH 54/72] Add diagnostics stub --- hphp/hack/src/stubs/logging/hackEventLogger.ml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hphp/hack/src/stubs/logging/hackEventLogger.ml b/hphp/hack/src/stubs/logging/hackEventLogger.ml index de23b013fa7388..543c5c406bff06 100644 --- a/hphp/hack/src/stubs/logging/hackEventLogger.ml +++ b/hphp/hack/src/stubs/logging/hackEventLogger.ml @@ -587,3 +587,7 @@ end module TypingErrors = struct let log_errors ~type_check_end_id:_ ~data:_ = () end + +module Diagnostics = struct + let log _ = () +end From f21df694bd666e97263df9fab387ac7c2aad6891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Sat, 1 Feb 2025 19:04:59 +0100 Subject: [PATCH 55/72] Update mvfst submodule ref --- third-party/mvfst/src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third-party/mvfst/src b/third-party/mvfst/src index 57bf5ac97e9a9c..c41e14aea7b456 160000 --- a/third-party/mvfst/src +++ b/third-party/mvfst/src @@ -1 +1 @@ -Subproject commit 57bf5ac97e9a9c347a781912b468909f600188d7 +Subproject commit c41e14aea7b4564b1a8ae07d0d18cf42f94e3bf9 From 0434897c2c6e72234837c0422bfe8cd66adef745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Tue, 15 Apr 2025 00:37:59 +0200 Subject: [PATCH 56/72] Update to Rust 1.87 --- third-party/rustc/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/third-party/rustc/CMakeLists.txt b/third-party/rustc/CMakeLists.txt index 9ccfe95d806c1c..ba920e6439907e 100644 --- a/third-party/rustc/CMakeLists.txt +++ b/third-party/rustc/CMakeLists.txt @@ -28,7 +28,7 @@ if(RUSTC_EXECUTABLE) else() message(STATUS "Using bundled Rust") - set(RUST_NIGHTLY_VERSION "2024-10-14") + set(RUST_NIGHTLY_VERSION "2025-03-31") SET_HHVM_THIRD_PARTY_SOURCE_ARGS( RUST_DOWNLOAD_ARGS @@ -37,9 +37,9 @@ else() Darwin_URL "https://static.rust-lang.org/dist/${RUST_NIGHTLY_VERSION}/rust-nightly-x86_64-apple-darwin.tar.gz" Linux_HASH - "SHA512=a4d6006d413022c72f6da8043affae0883fcfb0c8b7269933e90f1ec3238f0d14fa41a4656fa6069a2ee12956d0de09d6e2badf3d7be3e66de8902a075c6df83" + "SHA512=fe11a7b0e9a016cd9777f2977988409d750e26e6e3ad5652b438e1af82b755848fe0bdd03f35eef84d75c645f75ce40c3360e728c83131d9730164b709ed0e56" Darwin_HASH - "SHA512=f1e36f0adaa8e0c7c7504ae68b39545a45b5e2025e97309499f06295db89be9bafae5fb6c143a5214e95730fcd7f639a30250553f3bef435ebc86505d809223c" + "SHA512=ebdcecf7ccd7cee07e48e6937716040f9764ce13388f136c05a8b20f20c5a0a2f1ca3bf7a5a921d3a15ec1d2de51be8206e9599cb0d89b41784b652efbdef63f" # The original filename doesn't contain any version information, so add the version information as a prefix to avoid cache collisions when updating later FILENAME_PREFIX "rustc-${RUST_NIGHTLY_VERSION}-" ) From 3a4878b58331609051c0f43d1cb70a1ace06269d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Tue, 15 Apr 2025 01:08:28 +0200 Subject: [PATCH 57/72] Stub DeclarationsRewriter.rename_decls --- hphp/hack/src/stubs/declarationsRewriter.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hphp/hack/src/stubs/declarationsRewriter.ml b/hphp/hack/src/stubs/declarationsRewriter.ml index 526c4ce5902a5e..6d6e21efeabcc8 100644 --- a/hphp/hack/src/stubs/declarationsRewriter.ml +++ b/hphp/hack/src/stubs/declarationsRewriter.ml @@ -1 +1,3 @@ let start _ = () + +let rename_decls ~rename:_ ~hack_source_code:_ = "" From 13ed6bd5d92f44517833e8985de20b11ab12c775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Tue, 15 Apr 2025 04:44:34 +0200 Subject: [PATCH 58/72] Include cxxabi and libunwind headers in unique-stubs.cpp --- hphp/runtime/vm/jit/unique-stubs.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hphp/runtime/vm/jit/unique-stubs.cpp b/hphp/runtime/vm/jit/unique-stubs.cpp index 8341f2b9a7d888..991f04ba8c890b 100644 --- a/hphp/runtime/vm/jit/unique-stubs.cpp +++ b/hphp/runtime/vm/jit/unique-stubs.cpp @@ -75,6 +75,9 @@ #include +#include +#include + namespace HPHP::jit { /////////////////////////////////////////////////////////////////////////////// From b5579c63fb3490cd6fd1ed6049be2c94495ce9c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Tue, 13 May 2025 21:18:40 +0200 Subject: [PATCH 59/72] Drop unused headers --- hphp/runtime/ext/facts/config.cmake | 1 - hphp/runtime/ext/fileinfo/config.cmake | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/hphp/runtime/ext/facts/config.cmake b/hphp/runtime/ext/facts/config.cmake index 0fa428792f9da5..593a1c34d27d09 100644 --- a/hphp/runtime/ext/facts/config.cmake +++ b/hphp/runtime/ext/facts/config.cmake @@ -30,7 +30,6 @@ HHVM_DEFINE_EXTENSION( logging.h path-and-hash.h path-symbols-map.h - path-versions.h sqlite-autoload-db.h sqlite-key.h static-watcher.h diff --git a/hphp/runtime/ext/fileinfo/config.cmake b/hphp/runtime/ext/fileinfo/config.cmake index 1b7c6c83773269..6fc09bd7ab0324 100644 --- a/hphp/runtime/ext/fileinfo/config.cmake +++ b/hphp/runtime/ext/fileinfo/config.cmake @@ -20,7 +20,6 @@ HHVM_DEFINE_EXTENSION("fileinfo" HEADERS libmagic/cdf.h libmagic/compat.h - libmagic/elfclass.h libmagic/file.h libmagic/magic.h libmagic/names.h @@ -29,4 +28,4 @@ HHVM_DEFINE_EXTENSION("fileinfo" libmagic/tar.h SYSTEMLIB ext_fileinfo.php -) \ No newline at end of file +) From ab67afe27104ea19640a745fe5f44059780b23f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 16 May 2025 00:59:54 +0200 Subject: [PATCH 60/72] Fix OCaml stubs --- hphp/hack/src/stubs/declarationsRewriter.ml | 2 +- hphp/hack/src/stubs/dune | 11 +++ hphp/hack/src/stubs/hh_distc_ffi.ml | 2 +- hphp/hack/src/stubs/state_loader.mli | 74 +++++++++++++++++++ hphp/hack/src/stubs/state_loader_futures.ml | 30 ++++++++ hphp/hack/src/stubs/state_loader_lwt.ml | 40 ++++++++++ .../src/utils/ignore/filesToIgnore.stubs.ml | 4 - 7 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 hphp/hack/src/stubs/state_loader.mli create mode 100644 hphp/hack/src/stubs/state_loader_futures.ml create mode 100644 hphp/hack/src/stubs/state_loader_lwt.ml diff --git a/hphp/hack/src/stubs/declarationsRewriter.ml b/hphp/hack/src/stubs/declarationsRewriter.ml index 6d6e21efeabcc8..e0248cd880201b 100644 --- a/hphp/hack/src/stubs/declarationsRewriter.ml +++ b/hphp/hack/src/stubs/declarationsRewriter.ml @@ -1,3 +1,3 @@ -let start _ = () +let start _ ~file_whose_existence_indicates_hhvm_is_paused:_ = () let rename_decls ~rename:_ ~hack_source_code:_ = "" diff --git a/hphp/hack/src/stubs/dune b/hphp/hack/src/stubs/dune index c3c5923aad7137..a3454452dcb381 100644 --- a/hphp/hack/src/stubs/dune +++ b/hphp/hack/src/stubs/dune @@ -59,6 +59,17 @@ (preprocess (pps lwt_ppx ppx_deriving.std))) +(library + (name state_loader_stubs) + (wrapped false) + (modules saved_state_loader state_loader_futures state_loader_lwt) + (libraries + hg + server_env + typechecker_options) + (preprocess + (pps lwt_ppx ppx_deriving.std))) + (library (name remote_old_decls_ffi) (wrapped false) diff --git a/hphp/hack/src/stubs/hh_distc_ffi.ml b/hphp/hack/src/stubs/hh_distc_ffi.ml index 37ff10aa451257..6a5dce0b6bbb7f 100644 --- a/hphp/hack/src/stubs/hh_distc_ffi.ml +++ b/hphp/hack/src/stubs/hh_distc_ffi.ml @@ -8,7 +8,7 @@ type handle -let spawn ~root:_ ~ss_dir:_ ~hhdg_path:_ _ = failwith "start not implemented" +let spawn ~root:_ ~ss_dir:_ ~hhdg_path:_ ~fanout:_ _ = failwith "start not implemented" let join _ = failwith "join_handle not implemented" diff --git a/hphp/hack/src/stubs/state_loader.mli b/hphp/hack/src/stubs/state_loader.mli new file mode 100644 index 00000000000000..c56c324d0befb8 --- /dev/null +++ b/hphp/hack/src/stubs/state_loader.mli @@ -0,0 +1,74 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the "hack" directory of this source tree. + * + *) + +type dirty_files = { + master_changes: Relative_path.t list; + local_changes: Relative_path.t list; +} + +type hot_decls_paths = { + legacy_hot_decls_path: string; + shallow_hot_decls_path: string; +} + +type native_load_result = { + naming_table_path: string; + corresponding_rev: Hg.rev; + mergebase_rev: Hg.global_rev option; + mergebase: Hg.Rev.t option Future.t; + is_cached: bool; + state_distance: int; + deptable_fn: string; + dirty_files: dirty_files Future.t; + hot_decls_paths: hot_decls_paths; + errors_path: string; +} + +type saved_state_handle = { + saved_state_for_rev: Hg.rev; + saved_state_everstore_handle: string; + watchman_mergebase: MonitorUtils.watchman_mergebase option; +} + +type error = unit + +type verbose_error = { + message: string; + stack: Utils.callstack; + auto_retry: bool; + environment: string option; +} +[@@deriving show] + +val error_string_verbose : error -> verbose_error + +val cached_state : + load_64bit:bool -> + ?saved_state_handle:saved_state_handle -> + config_hash:string -> + rev:Hg.rev -> + (Hg.rev * string * MonitorUtils.watchman_mergebase option) option + +val fetch_saved_state : + load_64bit:bool -> + ?cache_limit:int -> + config:State_loader_config.timeouts -> + config_hash:string -> + saved_state_handle -> + (string, error) result Future.t + +val mk_state_future : + config:State_loader_config.timeouts -> + load_64bit:bool -> + ?saved_state_handle:saved_state_handle -> + config_hash:string option -> + ignore_hh_version:bool -> + ignore_hhconfig:bool -> + use_prechecked_files:bool -> + Path.t -> + (native_load_result, error) result Future.t diff --git a/hphp/hack/src/stubs/state_loader_futures.ml b/hphp/hack/src/stubs/state_loader_futures.ml new file mode 100644 index 00000000000000..44d8d24f711928 --- /dev/null +++ b/hphp/hack/src/stubs/state_loader_futures.ml @@ -0,0 +1,30 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the "hack" directory of this source tree. + * + *) + +let get_project_metadata + ~progress_callback:_ + ~saved_state_type:_ + ~repo:_ + ~ignore_hh_version:_ + ~opts:_ = + failwith "Not implemented" + +let load ~ssopt:_ ~progress_callback:_ ~watchman_opts:_ ~ignore_hh_version:_ = + Future.of_value (Error "Not implemented") + +let wait_for_finish _ = failwith "Not implemented" + +let wait_for_finish_with_debug_details _ = failwith "Not implemented" + +let download_and_unpack_saved_state_from_manifold + ~ssopt:_ + ~progress_callback:_ + ~manifold_path:_ + ~target_path:_ + ~saved_state_type:_ = + failwith "Not implemented" diff --git a/hphp/hack/src/stubs/state_loader_lwt.ml b/hphp/hack/src/stubs/state_loader_lwt.ml new file mode 100644 index 00000000000000..e7e1914f8307be --- /dev/null +++ b/hphp/hack/src/stubs/state_loader_lwt.ml @@ -0,0 +1,40 @@ +(** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the "hack" directory of this source tree. + * + *) + +let get_project_metadata ~repo:_ ~ignore_hh_version:_ ~opts:_ = + Lwt.return (Error ("Not implemented", Telemetry.create ())) + +let load ~ssopt:_ ~progress_callback:_ ~watchman_opts:_ ~ignore_hh_version:_ = + Lwt.return (Error "Not implemented") + +let load_internal + ~ssopt:_ + ~progress_callback:_ + ~watchman_opts:_ + ~ignore_hh_version:_ + ~saved_state_type:_ = + failwith "Not implemented" + +let prepare_download_dir () = failwith "Not implemented" + +let get_saved_state_target_path ~download_dir:_ ~manifold_path:_ = + failwith "Not implemented" + +let download_and_unpack_saved_state_from_manifold + ~ssopt:_ ~progress_callback:_ ~manifold_path:_ ~target_path:_ = + failwith "Not implemented" + +module FromDisk = struct + type load_result = { + naming_table_path: Path.t; + warning_saved_state_path: Path.t; + files_changed: Saved_state_loader.changed_files; + } + + let load ~project_metadata:_ ~threshold:_ ~root:_ = Error "Not implemented" +end diff --git a/hphp/hack/src/utils/ignore/filesToIgnore.stubs.ml b/hphp/hack/src/utils/ignore/filesToIgnore.stubs.ml index 2ece706c29ba12..b376498bc3d8c0 100644 --- a/hphp/hack/src/utils/ignore/filesToIgnore.stubs.ml +++ b/hphp/hack/src/utils/ignore/filesToIgnore.stubs.ml @@ -23,8 +23,6 @@ let svn_dirname = J.strlist ["dirname"; ".svn"] type watch_spec = { include_extensions: string list; include_file_names: string list; - exclude_directories: string list; - exclude_vcs_directories: bool; } let server_watch_spec = @@ -32,8 +30,6 @@ let server_watch_spec = include_extensions = ["php"; "phpt"; "hack"; "hackpartial"; "hck"; "hh"; "hhi"; "xhp"]; include_file_names = [".hhconfig"; "PACKAGES.toml"]; - exclude_directories = ["scripts/build/artifacts/sqlfacts"]; - exclude_vcs_directories = true; } let watchman_server_expression_terms = From 60317bb36c60f1c687ef9d01ddce7d74efa5b7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 16 May 2025 02:21:15 +0200 Subject: [PATCH 61/72] Add libbpf dependency --- CMake/FindBpf.cmake | 15 +++++++++++++++ CMake/HPHPFindLibs.cmake | 11 ++++++----- ci/ubuntu-24.04-noble/debian/control | 1 + 3 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 CMake/FindBpf.cmake diff --git a/CMake/FindBpf.cmake b/CMake/FindBpf.cmake new file mode 100644 index 00000000000000..1591ab2f73b051 --- /dev/null +++ b/CMake/FindBpf.cmake @@ -0,0 +1,15 @@ +find_path(BPF_INCLUDE_DIR bpf/bpf.h) +find_library(BPF_LIBRARY NAMES bpf) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(BPF DEFAULT_MSG BPF_LIBRARY BPF_INCLUDE_DIR) + +if(BPF_FOUND) + set(BPF_LIBRARIES ${BPF_LIBRARY}) + set(BPF_INCLUDE_DIRS ${BPF_INCLUDE_DIR}) +else() + set(BPF_LIBRARIES) + set(BPF_INCLUDE_DIRS) +endif() + +mark_as_advanced(BPF_LIBRARIES BPF_INCLUDE_DIRS) diff --git a/CMake/HPHPFindLibs.cmake b/CMake/HPHPFindLibs.cmake index 05fc964eebc0d4..b440c6ab1ba594 100644 --- a/CMake/HPHPFindLibs.cmake +++ b/CMake/HPHPFindLibs.cmake @@ -44,8 +44,8 @@ include_directories(${LIBEVENT_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES "${LIBEVENT_LIB}") CHECK_FUNCTION_EXISTS("evhttp_bind_socket_with_fd" HAVE_CUSTOM_LIBEVENT) if(HAVE_CUSTOM_LIBEVENT) - message("Using custom LIBEVENT") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_CUSTOM_LIBEVENT") + message("Using custom LIBEVENT") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_CUSTOM_LIBEVENT") endif() set(CMAKE_REQUIRED_LIBRARIES) @@ -280,6 +280,7 @@ endif() if (LINUX) find_package(LibUnwind REQUIRED) + find_package(Bpf REQUIRED) endif() # This is required by Homebrew's libc. See @@ -344,7 +345,7 @@ macro(hphp_link target) target_link_libraries(${target} ${VISIBILITY} glog) if (LINUX) - target_link_libraries(${target} ${VISIBILITY} ${LIBUNWIND_LIBRARIES}) + target_link_libraries(${target} ${VISIBILITY} ${LIBUNWIND_LIBRARIES} ${BPF_LIBRARIES}) endif() if (LIBINOTIFY_LIBRARY) @@ -453,9 +454,9 @@ macro(hphp_link target) if (ENABLE_XED) if (LibXed_FOUND) - target_link_libraries(${target} ${VISIBILITY} ${LibXed_LIBRARY}) + target_link_libraries(${target} ${VISIBILITY} ${LibXed_LIBRARY}) else() - target_link_libraries(${target} ${VISIBILITY} xed) + target_link_libraries(${target} ${VISIBILITY} xed) endif() endif() diff --git a/ci/ubuntu-24.04-noble/debian/control b/ci/ubuntu-24.04-noble/debian/control index bcbbfc8cc8bc29..dc7b2922e5086e 100644 --- a/ci/ubuntu-24.04-noble/debian/control +++ b/ci/ubuntu-24.04-noble/debian/control @@ -19,6 +19,7 @@ Build-Depends: git, gperf, libboost-all-dev, + libbpf-dev, libbz2-dev, libc-client-dev, libc-client2007e-dev, From f562c9fce624ed7fbc7396007dd9dfd663b3a001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 16 May 2025 02:26:29 +0200 Subject: [PATCH 62/72] Silence noisy nontrivial-memcall diagnostic on clang 20 --- CMake/HPHPCompiler.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMake/HPHPCompiler.cmake b/CMake/HPHPCompiler.cmake index a5b7c0533014e0..b816557708c421 100644 --- a/CMake/HPHPCompiler.cmake +++ b/CMake/HPHPCompiler.cmake @@ -123,6 +123,10 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQU if(CLANG_FORCE_LIBCPP) list(APPEND GENERAL_CXX_OPTIONS "stdlib=libc++") endif() + + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 20) + list(APPEND GENERAL_OPTIONS "Wno-nontrivial-memcall") + endif() else() # using GCC list(APPEND DISABLED_NAMED_WARNINGS "deprecated-declarations" From 63186ca0132714a8a931eaaa539c9e77998e56b6 Mon Sep 17 00:00:00 2001 From: hershel-theodore-layton <81193606+hershel-theodore-layton@users.noreply.github.com> Date: Sun, 1 Jun 2025 09:44:14 +0200 Subject: [PATCH 63/72] Try to include the MySQL extension --- ci/ubuntu-24.04-noble/debian/rules | 2 -- 1 file changed, 2 deletions(-) diff --git a/ci/ubuntu-24.04-noble/debian/rules b/ci/ubuntu-24.04-noble/debian/rules index fb0a9caff044a9..88b70aaa458d32 100644 --- a/ci/ubuntu-24.04-noble/debian/rules +++ b/ci/ubuntu-24.04-noble/debian/rules @@ -18,9 +18,7 @@ override_dh_auto_configure: -DFORCE_BUNDLED_LZ4=Off \ -DENABLE_XED=On \ -DENABLE_EXTENSION_MCRYPT=Off \ - -DENABLE_EXTENSION_ASYNC_MYSQL=Off \ -DENABLE_MCROUTER=Off \ - -DENABLE_EXTENSION_MYSQL=Off \ -DENABLE_EXTENSION_IMAGICK=Off override_dh_auto_build: From 06b51e9499bfc5f18b979515c802e42f47348d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 6 Jun 2025 00:54:24 +0200 Subject: [PATCH 64/72] Only containerize the actual package build --- .github/workflows/ubuntu.yml | 63 ++++++++++++++--------------------- ci/bin/make-debianish-package | 20 +++++++++-- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 8945435b14f647..95cba76e752053 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -5,7 +5,7 @@ on: branches-ignore: # Exclude the push event for exported diffs, because the CI for export # should have been covered by GitHub Actions triggered by pull requests. - - 'export-D+' + - "export-D+" pull_request: concurrency: @@ -25,41 +25,28 @@ env: DEBIAN_FRONTEND: "noninteractive" jobs: - build_ubuntu_focal_nightly: - runs-on: 8-core-ubuntu - container: - image: ubuntu:noble - env: - DISTRO: ubuntu-24.04-noble - IS_NIGHTLY: 1 - CLANG_VERSION: 18 + build_ubuntu_noble_nightly: + runs-on: ubuntu-latest steps: - - name: Installing dependencies to bootstrap env - run: apt update -y && apt install -y git wget lsb-release software-properties-common gpg clang clang-${CLANG_VERSION} libc++-${CLANG_VERSION}-dev libc++abi-${CLANG_VERSION}-dev - - name: Making LLVM the default compiler - run: | - if [ -f /etc/alternatives/cc ] - then - update-alternatives --remove-all cc - fi - - if [ -f /etc/alternatives/c++ ] - then - update-alternatives --remove-all c++ - fi - - update-alternatives --install /usr/bin/cc cc /usr/bin/clang++-${CLANG_VERSION} 500 - update-alternatives --set cc /usr/bin/clang++-${CLANG_VERSION} - update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${CLANG_VERSION} 500 - update-alternatives --set c++ /usr/bin/clang++-${CLANG_VERSION} - - name: Fetching HHVM and its submodules - uses: actions/checkout@v4 - with: - submodules: 'recursive' - - name: Installing HHVM deps and building HHVM - run: ci/bin/make-debianish-package - - name: Uploading artifacts - uses: actions/upload-artifact@v4 - with: - name: out-directory - path: ${{ env.OUT }} + # The HHVM build requires more disk space than what is available + # on a default Actions runner, so remove some cruft. + - name: Free up disk space + uses: jlumbroso/free-disk-space@v1.3.1 + - name: Fetching HHVM and its submodules + uses: actions/checkout@v4 + with: + submodules: "recursive" + - name: Installing HHVM deps and building HHVM + uses: docker://ubuntu:noble + env: + DISTRO: ubuntu-24.04-noble + IS_NIGHTLY: 1 + CLANG_VERSION: 18 + with: + entrypoint: /bin/bash + args: ci/bin/make-debianish-package + - name: Uploading artifacts + uses: actions/upload-artifact@v4 + with: + name: out-directory + path: ${{ env.OUT }} diff --git a/ci/bin/make-debianish-package b/ci/bin/make-debianish-package index c544065f95a52c..b839d0aff0cc81 100755 --- a/ci/bin/make-debianish-package +++ b/ci/bin/make-debianish-package @@ -34,9 +34,23 @@ OUT=${OUT:-/var/out} mkdir -p "$OUT" # Environment set up -apt-get -o Acquire::Retries=3 update -y -apt-get clean -apt-get -o Acquire::Retries=3 install -y devscripts equivs +apt update -y && apt install -y devscripts equivs git wget lsb-release software-properties-common gpg clang clang-${CLANG_VERSION} libc++-${CLANG_VERSION}-dev libc++abi-${CLANG_VERSION}-dev + +# Making LLVM the default compiler +if [ -f /etc/alternatives/cc ] +then + update-alternatives --remove-all cc +fi + +if [ -f /etc/alternatives/c++ ] +then + update-alternatives --remove-all c++ +fi + +update-alternatives --install /usr/bin/cc cc /usr/bin/clang++-${CLANG_VERSION} 500 +update-alternatives --set cc /usr/bin/clang++-${CLANG_VERSION} +update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${CLANG_VERSION} 500 +update-alternatives --set c++ /usr/bin/clang++-${CLANG_VERSION} # Copy the debian directory to the root of the git repo # so that all the devscripts command work. From 62e4a1b78d92aeca69d80845b831d59e58e5fa05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 6 Jun 2025 02:42:46 +0200 Subject: [PATCH 65/72] Use separate build directories for Rust libraries in dune Currently these all use default/target, which seems to cause difficult-to-debug race conditions in OSS CI. Strangely, (locks /cargo) is supposed to prevent this given that locks with an absolute path is documented by dune to be a global lock, but it doesn't seem to work as intended. --- hphp/hack/Makefile.dune | 19 +++++++------------ hphp/hack/scripts/invoke_cargo.sh | 2 +- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/hphp/hack/Makefile.dune b/hphp/hack/Makefile.dune index 0c666d39b6c65e..929c4ca9b1b513 100644 --- a/hphp/hack/Makefile.dune +++ b/hphp/hack/Makefile.dune @@ -32,18 +32,13 @@ clean: define build_hack $(eval ext := $(if $(filter $(2),-debug),".bc","")) build-hack$(2): - rm -rf "$(DUNE_BUILD_DIR)/default/target/release" - dune build src/hh_server.$(1) - rm -rf "$(DUNE_BUILD_DIR)/default/target/release" - dune build src/hh_client.$(1) - rm -rf "$(DUNE_BUILD_DIR)/default/target/release" - dune build src/hh_single_type_check.$(1) - rm -rf "$(DUNE_BUILD_DIR)/default/target/release" - dune build src/hackfmt.$(1) - rm -rf "$(DUNE_BUILD_DIR)/default/target/release" - dune build src/hh_parse.$(1) - rm -rf "$(DUNE_BUILD_DIR)/default/target/release" - dune build src/generate_full_fidelity.$(1) + dune build \ + src/hh_server.$(1) \ + src/hh_client.$(1) \ + src/hh_single_type_check.$(1) \ + src/hackfmt.$(1) \ + src/hh_parse.$(1) \ + src/generate_full_fidelity.$(1) copy-hack$(2)-files: build-hack$(2) mkdir -p "$(HACK_BIN_DIR)" diff --git a/hphp/hack/scripts/invoke_cargo.sh b/hphp/hack/scripts/invoke_cargo.sh index 89af6412a19992..1f00e081b3ad74 100755 --- a/hphp/hack/scripts/invoke_cargo.sh +++ b/hphp/hack/scripts/invoke_cargo.sh @@ -40,7 +40,7 @@ if [ -z "${HACK_NO_CARGO_VENDOR}" ]; then fi if [ -z "${TARGET_DIR}" ]; then - TARGET_DIR="${HACK_BUILD_ROOT}/target" + TARGET_DIR="${HACK_BUILD_ROOT}/target/$pkg" fi if [ -z ${HACKDEBUG+1} ]; then From 96df5f51108a507dfcd8cf132411e78c93a90d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 6 Jun 2025 03:27:28 +0200 Subject: [PATCH 66/72] Remove use of deprecated boost/filesystem/string_file --- hphp/compiler/compiler-systemlib.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/hphp/compiler/compiler-systemlib.cpp b/hphp/compiler/compiler-systemlib.cpp index eb7a7e34ada495..fcbaff18cf8c6c 100644 --- a/hphp/compiler/compiler-systemlib.cpp +++ b/hphp/compiler/compiler-systemlib.cpp @@ -35,7 +35,6 @@ #include "hphp/util/rds-local.h" #include "hphp/util/timer.h" -#include #include #include #include @@ -43,6 +42,7 @@ #include +#include #include using namespace boost::program_options; @@ -151,9 +151,23 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) { return 0; } +void load_string_file(const std::filesystem::path& path, std::string& content) { + std::ifstream file(path, std::ios_base::binary); + auto file_size = std::filesystem::file_size(path); + + content.resize(static_cast(file_size), '\0'); + file.read(&content[0], static_cast(file_size)); +} + +void save_string_file(const std::filesystem::path& path, const std::string& content) { + std::ofstream file(path, std::ios_base::binary); + file.write(content.data(), static_cast(content.size())); +} + bool compile_systemlib(const std::filesystem::path& path, std::string output_dir, const Extension* extension) { std::string content; - boost::filesystem::load_string_file(path.string(), content); + + load_string_file(path, content); // Create Unit Emitter std::string fname = "/:"+path.filename().string(); @@ -178,7 +192,7 @@ bool compile_systemlib(const std::filesystem::path& path, std::string output_dir BlobEncoder uew_encoder; uew.serde(uew_encoder); - boost::filesystem::save_string_file(output_dir + "/" + path.filename().string() + ".ue", std::string(static_cast(uew_encoder.data()), uew_encoder.size())); + save_string_file(output_dir + "/" + path.filename().string() + ".ue", std::string(static_cast(uew_encoder.data()), uew_encoder.size())); // Create Decls auto const& defaults = RepoOptions::defaultsForSystemlib(); @@ -200,7 +214,7 @@ bool compile_systemlib(const std::filesystem::path& path, std::string output_dir } auto serialized = hackc::decls_holder_to_binary(*decls.decls); - boost::filesystem::save_string_file(output_dir + "/" + path.filename().string() + ".decls", std::string(serialized.begin(), serialized.end())); + save_string_file(output_dir + "/" + path.filename().string() + ".decls", std::string(serialized.begin(), serialized.end())); return true; } From ed86253e29ce5c5977e177c25acc8b8b98dd6ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 6 Jun 2025 04:24:59 +0200 Subject: [PATCH 67/72] Build the mcrouter extension --- CMake/HPHPFindLibs.cmake | 5 ++ CMake/Options.cmake | 9 +-- ci/ubuntu-24.04-noble/debian/rules | 2 +- hphp/runtime/ext/mcrouter/config.cmake | 2 +- third-party/mcrouter/CMakeLists.txt | 27 +++++-- third-party/mcrouter/mcrouter-CMakeLists.txt | 66 ++++++++++++++-- .../mcrouter/mcrouter-thrift-codegen.cmake | 75 ------------------- third-party/thrift/CMakeLists.txt | 63 +++++----------- 8 files changed, 110 insertions(+), 139 deletions(-) delete mode 100644 third-party/mcrouter/mcrouter-thrift-codegen.cmake diff --git a/CMake/HPHPFindLibs.cmake b/CMake/HPHPFindLibs.cmake index b440c6ab1ba594..2e5c44378a3161 100644 --- a/CMake/HPHPFindLibs.cmake +++ b/CMake/HPHPFindLibs.cmake @@ -291,6 +291,9 @@ if (PAM_INCLUDE_PATH) include_directories(${PAM_INCLUDE_PATH}) endif() +# Needed by fbthrift. +find_package(Xxhash REQUIRED) + include_directories(${HPHP_HOME}/hphp) macro(hphp_link target) @@ -386,6 +389,8 @@ macro(hphp_link target) target_link_libraries(${target} ${VISIBILITY} ${LBER_LIBRARIES}) + target_link_libraries(${target} ${VISIBILITY} ${Xxhash_LIBRARY}) + if (CRYPT_LIB) target_link_libraries(${target} ${VISIBILITY} ${CRYPT_LIB}) endif() diff --git a/CMake/Options.cmake b/CMake/Options.cmake index 8ad29c42504e81..6dd11631fee6a8 100644 --- a/CMake/Options.cmake +++ b/CMake/Options.cmake @@ -28,14 +28,7 @@ option(ENABLE_COTIRE "Speed up the build by precompiling headers" OFF) include(CheckCXXSymbolExists) -# Mcrouter uses Folly's AtomicSharedPtr, which only supports libstdc++ -# See https://github.com/facebook/hhvm/blob/156a77d5a301033200601ddefb4dcaf26eb1ff9c/third-party/folly/src/folly/concurrency/detail/AtomicSharedPtr-detail.h#L28-L34 -check_cxx_symbol_exists(__GLIBCXX__ cstdlib DEFAULT_STDLIB_IS_LIBSTDCXX) -if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CLANG_FORCE_LIBSTDCXX OR DEFAULT_STDLIB_IS_LIBSTDCXX) - option(ENABLE_MCROUTER "Build the mcrouter library and extension" ON) -else() - option(ENABLE_MCROUTER "Build the mcrouter library and extension" OFF) -endif() +option(ENABLE_MCROUTER "Build the mcrouter library and extension" OFF) option(ENABLE_PROXYGEN_SERVER "Build the Proxygen HTTP server" ON) diff --git a/ci/ubuntu-24.04-noble/debian/rules b/ci/ubuntu-24.04-noble/debian/rules index 88b70aaa458d32..53cf9caa324248 100644 --- a/ci/ubuntu-24.04-noble/debian/rules +++ b/ci/ubuntu-24.04-noble/debian/rules @@ -18,7 +18,7 @@ override_dh_auto_configure: -DFORCE_BUNDLED_LZ4=Off \ -DENABLE_XED=On \ -DENABLE_EXTENSION_MCRYPT=Off \ - -DENABLE_MCROUTER=Off \ + -DENABLE_MCROUTER=On \ -DENABLE_EXTENSION_IMAGICK=Off override_dh_auto_build: diff --git a/hphp/runtime/ext/mcrouter/config.cmake b/hphp/runtime/ext/mcrouter/config.cmake index 6022bb06640fe2..e48dadcc884169 100644 --- a/hphp/runtime/ext/mcrouter/config.cmake +++ b/hphp/runtime/ext/mcrouter/config.cmake @@ -1,4 +1,4 @@ -option(ENABLE_EXTENSION_MCROUTER "Build the imap extension" ${ENABLE_MCROUTER}) +option(ENABLE_EXTENSION_MCROUTER "Build the mcrouter extension" ${ENABLE_MCROUTER}) HHVM_DEFINE_EXTENSION("mcrouter" SOURCES diff --git a/third-party/mcrouter/CMakeLists.txt b/third-party/mcrouter/CMakeLists.txt index 1490d93c0daeb9..7da97481cb83d2 100644 --- a/third-party/mcrouter/CMakeLists.txt +++ b/third-party/mcrouter/CMakeLists.txt @@ -26,10 +26,6 @@ ExternalProject_Add( "${CMAKE_CURRENT_SOURCE_DIR}/mcrouter-CMakeLists.txt" "CMakeLists.txt" && - "${CMAKE_COMMAND}" -E create_symlink - "${CMAKE_CURRENT_SOURCE_DIR}/mcrouter-thrift-codegen.cmake" - "mcrouter-thrift-codegen.cmake" - && "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/config.h" "mcrouter/" @@ -41,6 +37,7 @@ ExternalProject_Add( -DCMAKE_INSTALL_PREFIX= -DCMAKE_INSTALL_INCLUDEDIR=include -DCMAKE_INSTALL_LIBDIR=lib + -DCMAKE_MODULE_PATH=${CMAKE_SOURCE_DIR}/build/fbcode_builder/CMake -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} @@ -59,8 +56,10 @@ ExternalProject_Add( "-Dfmt_DIR=${fmt_DIR}" "-Dfolly_DIR=${FOLLY_INSTALL_DIR}/lib/cmake/folly" "-Dfizz_DIR=${FIZZ_INSTALL_DIR}/lib/cmake/fizz" + "-DFizz_DIR=${FIZZ_INSTALL_DIR}/lib/cmake/fizz" "-DFBThrift_DIR=${THRIFT_INSTALL_DIR}/lib/cmake/fbthrift" "-Dwangle_DIR=${WANGLE_INSTALL_DIR}/lib/cmake/wangle" + "-Dmvfst_DIR=${MVFST_INSTALL_DIR}/lib/cmake/mvfst" DEPENDS ${MCROUTER_DEPS} ragel EXCLUDE_FROM_ALL ) @@ -76,10 +75,26 @@ target_include_directories( "${BINARY_DIR}" "${BINARY_DIR}/thrift-gen/src" ) + +list(APPEND MCROUTER_INSTALL_TARGETS + mcrouter + mcrouter_memcache_service_thrift + mcrouter_memcache_thrift + mcrouter_common_thrift + mcrouter_carbon_result_thrift + mcrouter_carbon_thrift +) + +foreach(target ${MCROUTER_INSTALL_TARGETS}) + target_link_libraries( + mcrouter + INTERFACE + "${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${target}${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) +endforeach() + target_link_libraries( mcrouter INTERFACE - "${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}mcrouter${CMAKE_STATIC_LIBRARY_SUFFIX}" - "${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}mcrouter_thrift_lib${CMAKE_STATIC_LIBRARY_SUFFIX}" mcrouter_deps ) diff --git a/third-party/mcrouter/mcrouter-CMakeLists.txt b/third-party/mcrouter/mcrouter-CMakeLists.txt index fb09baa7929161..ccd387eda0bc87 100644 --- a/third-party/mcrouter/mcrouter-CMakeLists.txt +++ b/third-party/mcrouter/mcrouter-CMakeLists.txt @@ -1,11 +1,10 @@ cmake_minimum_required(VERSION 3.10) project(watchman CXX C) include(GNUInstallDirs) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) - set(C_SOURCES) # TODO when Ubuntu 18.04 support is dropped: @@ -102,12 +101,69 @@ find_package(wangle REQUIRED) find_path(JEMALLOC_INCLUDE_DIR NAMES jemalloc/jemalloc.h REQUIRED) -include(mcrouter-thrift-codegen.cmake) +include(FBThriftCppLibrary) +set(THRIFT_OPTIONS stack_arguments sync_methods_return_try + deprecated_terse_writes) + +add_fbthrift_cpp_library(mcrouter_carbon_result_thrift mcrouter/lib/carbon/carbon_result.thrift OPTIONS ${THRIFT_OPTIONS}) +add_fbthrift_cpp_library(mcrouter_carbon_thrift mcrouter/lib/carbon/carbon.thrift OPTIONS ${THRIFT_OPTIONS}) +add_fbthrift_cpp_library(mcrouter_common_thrift mcrouter/lib/network/gen/Common.thrift + OPTIONS ${THRIFT_OPTIONS} + DEPENDS + mcrouter_carbon_thrift + mcrouter_carbon_result_thrift +) +add_fbthrift_cpp_library(mcrouter_memcache_thrift mcrouter/lib/network/gen/Memcache.thrift + OPTIONS ${THRIFT_OPTIONS} + DEPENDS + mcrouter_carbon_thrift + mcrouter_carbon_result_thrift + mcrouter_common_thrift +) +add_fbthrift_cpp_library(mcrouter_memcache_service_thrift mcrouter/lib/network/gen/MemcacheService.thrift + OPTIONS ${THRIFT_OPTIONS} + DEPENDS + mcrouter_common_thrift + mcrouter_memcache_thrift + SERVICES + Memcache +) -target_link_libraries(mcrouter mcrouter_thrift_lib Folly::folly boost fizz fmt) +target_link_libraries( + mcrouter + mcrouter_carbon_result_thrift + mcrouter_carbon_thrift + mcrouter_common_thrift + mcrouter_memcache_thrift + mcrouter_memcache_service_thrift + Folly::folly + boost + fizz + fmt + FBThrift::thriftcpp2 + FBThrift::async + FBThrift::serverdbginfo + FBThrift::transport + FBThrift::thriftanyrep + FBThrift::thrifttype + FBThrift::thrifttyperep + FBThrift::thriftprotocol + FBThrift::rpcmetadata + FBThrift::thriftannotation + FBThrift::thriftmetadata + FBThrift::concurrency + FBThrift::runtime + FBThrift::thrift-core +) target_include_directories(mcrouter PUBLIC "${CMAKE_CURRENT_BINARY_DIR}" "${JEMALLOC_INCLUDE_DIR}") install( - TARGETS mcrouter + TARGETS + mcrouter + mcrouter_carbon_result_thrift + mcrouter_carbon_thrift + mcrouter_common_thrift + mcrouter_memcache_thrift + mcrouter_memcache_service_thrift LIBRARY ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} ) diff --git a/third-party/mcrouter/mcrouter-thrift-codegen.cmake b/third-party/mcrouter/mcrouter-thrift-codegen.cmake deleted file mode 100644 index 939631508af2d9..00000000000000 --- a/third-party/mcrouter/mcrouter-thrift-codegen.cmake +++ /dev/null @@ -1,75 +0,0 @@ -# ----- Generate C++ sources from .thrift files ----- -include(GNUInstallDirs) - -add_custom_target(mcrouter_thrift1_codegen) - -set(CODEGEN_SOURCES_DIR "${CMAKE_CURRENT_BINARY_DIR}/thrift-gen/src") -set(CODEGEN_SOURCES) - -macro(mcrouter_thrift1_impl GEN_ARGS SOURCE SOURCE_SUBDIR) - get_filename_component(BASENAME "${SOURCE}" NAME_WE) - file(MAKE_DIRECTORY "${CODEGEN_SOURCES_DIR}/${SOURCE_SUBDIR}") - # Taken from FBThriftCppLibrary.cmake in fbcode_builder - set(OUTPUTS - "${CODEGEN_SOURCES_DIR}/${SOURCE_SUBDIR}/gen-cpp2/${BASENAME}_constants.cpp" - "${CODEGEN_SOURCES_DIR}/${SOURCE_SUBDIR}/gen-cpp2/${BASENAME}_data.cpp" - "${CODEGEN_SOURCES_DIR}/${SOURCE_SUBDIR}/gen-cpp2/${BASENAME}_types.cpp" - "${CODEGEN_SOURCES_DIR}/${SOURCE_SUBDIR}/gen-cpp2/${BASENAME}_metadata.cpp" - ) - if("${BASENAME}" MATCHES "Service$") - string(REPLACE "Service" "" SERVICE "${BASENAME}") - list(APPEND OUTPUTS - "${CODEGEN_SOURCES_DIR}/${SOURCE_SUBDIR}/gen-cpp2/${SERVICE}.cpp" - "${CODEGEN_SOURCES_DIR}/${SOURCE_SUBDIR}/gen-cpp2/${SERVICE}AsyncClient.cpp" - "${CODEGEN_SOURCES_DIR}/${SOURCE_SUBDIR}/gen-cpp2/${SERVICE}_processmap_binary.cpp" - "${CODEGEN_SOURCES_DIR}/${SOURCE_SUBDIR}/gen-cpp2/${SERVICE}_processmap_compact.cpp" - ) - endif() - list(APPEND CODEGEN_SOURCES ${OUTPUTS}) - - add_custom_command( - OUTPUT ${OUTPUTS} - COMMAND - FBThrift::thrift1 --gen - "${GEN_ARGS},include-prefix=${SOURCE_SUBDIR}" - -o "${CODEGEN_SOURCES_DIR}/${SOURCE_SUBDIR}" - -I "${SOURCE_SUBDIR}" -I "${CMAKE_CURRENT_SOURCE_DIR}" - "${SOURCE_SUBDIR}/${SOURCE}" - BYPRODUCTS ${OUTPUTS} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_SUBDIR}/${SOURCE}" - ) - add_custom_target("mcrouter_thrift1_${BASENAME}" DEPENDS ${OUTPUTS}) - add_dependencies(mcrouter_thrift1_codegen "mcrouter_thrift1_${BASENAME}") -endmacro() - -macro(carbon_thrift1 SOURCE) - mcrouter_thrift1_impl("mstch_cpp2:stack_arguments,sync_methods_return_try" "${SOURCE}" mcrouter/lib/carbon) -endmacro() - -carbon_thrift1(carbon.thrift) -carbon_thrift1(carbon_result.thrift) - -macro(network_thrift1 SOURCE) - mcrouter_thrift1_impl( - "mstch_cpp2:stack_arguments,sync_methods_return_try,terse_writes" - "${SOURCE}" - mcrouter/lib/network/gen - ) -endmacro() - -network_thrift1(Common.thrift) -network_thrift1(Memcache.thrift) -network_thrift1(MemcacheService.thrift) - -# ----- Build a static library from the generated C++ sources ------ - -add_library(mcrouter_thrift_lib STATIC EXCLUDE_FROM_ALL ${CODEGEN_SOURCES}) -add_dependencies(mcrouter_thrift_lib mcrouter_thrift1_codegen) -target_link_libraries(mcrouter_thrift_lib PUBLIC FBThrift::thriftcpp2) -target_include_directories(mcrouter_thrift_lib PUBLIC ${CODEGEN_SOURCES_DIR} "${JEMALLOC_INCLUDE_DIR}") - -install( - TARGETS mcrouter_thrift_lib - LIBRARY ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} -) \ No newline at end of file diff --git a/third-party/thrift/CMakeLists.txt b/third-party/thrift/CMakeLists.txt index 0617037be28773..379f366cea9f78 100644 --- a/third-party/thrift/CMakeLists.txt +++ b/third-party/thrift/CMakeLists.txt @@ -83,50 +83,27 @@ target_include_directories(thrift INTERFACE "${INSTALL_DIR}/include") target_link_libraries(thrift INTERFACE ${THRIFT_DEPS} ${OPENSSL_LIBRARIES}) set(THRIFT_INSTALL_DIR "${INSTALL_DIR}" PARENT_SCOPE) -# ----- Export a single 'thrift' library target ----- - -# Usage: thrift_lib NAME [DEP1 [DEP2...]] -macro(thrift_lib NAME) - set(DEPENDENCIES) - foreach(DEP ${ARGN}) - list(APPEND DEPENDENCIES "thrift_lib_${DEP}") - endforeach() - add_library("thrift_lib_${NAME}" STATIC IMPORTED) - set_target_properties( - "thrift_lib_${NAME}" - PROPERTIES - IMPORTED_LOCATION - "${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}" - ) - - if(DEPENDENCIES) - # On newer versions of CMake, we can use `target_link_libraries()`, but this isn't supported - # on `IMPORTED` targets in the oldest versions we currently support. - set_target_properties( - "thrift_lib_${NAME}" - PROPERTIES - INTERFACE_LINK_LIBRARIES - "${DEPENDENCIES}" - ) - endif() - - target_link_libraries(thrift INTERFACE "thrift_lib_${NAME}") -endmacro() - -thrift_lib(concurrency) -thrift_lib(rpcmetadata) -thrift_lib(thrift-core) -thrift_lib(thriftmetadata) -thrift_lib(thriftannotation) -thrift_lib(thrifttype) -thrift_lib(thrifttyperep thriftannotation) -thrift_lib(thriftanyrep thriftannotation thrifttype) +list(APPEND THRIFT_INSTALL_TARGETS + thriftcpp2 + async + serverdbginfo + transport + thriftanyrep + thrifttype + thrifttyperep + thriftprotocol + rpcmetadata + thriftannotation + thriftmetadata + concurrency + runtime + thrift-core + common +) -thrift_lib(transport concurrency thrift-core rpcmetadata) -thrift_lib(async concurrency transport) -thrift_lib(thriftprotocol thrift-core) -thrift_lib(thriftfrozen2 thriftmetadata thriftprotocol) -thrift_lib(thriftcpp2 rpcmetadata thriftmetadata thriftannotation thriftanyrep thrifttyperep thriftfrozen2 thriftprotocol transport async) +foreach (target ${THRIFT_INSTALL_TARGETS}) + target_link_libraries(thrift INTERFACE "${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${target}${CMAKE_STATIC_LIBRARY_SUFFIX}") +endforeach() # ----- Export the thrift compiler as a target ----- From 7de1540f47edf11f917863084acdf58c8725ef6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Wed, 25 Jun 2025 02:48:08 +0200 Subject: [PATCH 68/72] Consistently check connection validity in AsyncMysqlConnection The Squangle connection pointer wrapped by AsyncMysqlConnection may be nullptr if the connection was closed or is currently busy waiting for the result of an async query. Most code paths already call either verifyValidConnection() to raise an appropriate Hack exception or explicitly check for and handle a null backing connection, but Query::toString__FOR_DEBUGGING_ONLY() and the SSL-related getters from D33663743 do not, which can lead to segfaults. Slightly simplified reproducer from #8678: ```hack use namespace HH\Lib\SQL; <<__EntryPoint>> async function main_async(): Awaitable { // connection parameters as needed $async_conn = await AsyncMysqlClient::connect('127.0.0.1', 3306, 'foo', 'root', 'pass'); $async_conn->close(); var_dump($async_conn->getSslCertCn()); } async function func_async(AsyncMysqlConnection $asyncMysql, SQL\Query $query): Awaitable { $query->toString__FOR_DEBUGGING_ONLY($asyncMysql); var_dump($asyncMysql->getSslCertCn()); await $asyncMysql->queryf('SELECT %s', 'something'); } ``` and for `(get|is)Ssl.*`: ```hack use namespace HH\Lib\SQL; <<__EntryPoint>> async function main_async(): Awaitable { $async_conn = await AsyncMysqlClient::connect('127.0.0.1', 3306, 'foo', 'root', 'wikia123456'); $async_conn->close(); var_dump($async_conn->getSslCertCn()); } ``` Call verifyValidConnection() in all these cases, as raising an appropriate exception (e.g. closed/busy connection) seems appropriate here. Fixes #8678 --- hphp/runtime/ext/async_mysql/ext_async_mysql.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/hphp/runtime/ext/async_mysql/ext_async_mysql.cpp b/hphp/runtime/ext/async_mysql/ext_async_mysql.cpp index cb481d53a6bb82..a9b09382ab3b39 100644 --- a/hphp/runtime/ext/async_mysql/ext_async_mysql.cpp +++ b/hphp/runtime/ext/async_mysql/ext_async_mysql.cpp @@ -326,9 +326,11 @@ static String HHLibSQLQuery__toString__FOR_DEBUGGING_ONLY( val(this_->propRvalAtOffset(s_query_format_idx).tv()).pstr; const auto args = val(this_->propRvalAtOffset(s_query_args_idx).tv()).parr; const auto query = amquery_from_queryf(format, args); - auto mysql = Native::data(conn) - ->m_conn - ->mysql_for_testing_only(); + + auto* data = Native::data(conn); + data->verifyValidConnection(); + + auto mysql = data->m_conn->mysql_for_testing_only(); const auto str = query.render(mysql); return String(str.data(), str.length(), CopyString); } @@ -1244,6 +1246,8 @@ static void HHVM_METHOD(AsyncMysqlConnection, close) { static String HHVM_METHOD(AsyncMysqlConnection, getSslCertCn) { auto* data = Native::data(this_); + data->verifyValidConnection(); + const auto* context = data->m_conn->getConnectionContext(); if (context && context->sslCertCn.hasValue()) { return context->sslCertCn.value(); @@ -1254,6 +1258,8 @@ static String HHVM_METHOD(AsyncMysqlConnection, getSslCertCn) { static Object HHVM_METHOD(AsyncMysqlConnection, getSslCertSan) { auto* data = Native::data(this_); + data->verifyValidConnection(); + auto ret = req::make(); const auto* context = data->m_conn->getConnectionContext(); if (context && context->sslCertSan.hasValue()) { @@ -1266,6 +1272,8 @@ static Object HHVM_METHOD(AsyncMysqlConnection, getSslCertSan) { static Object HHVM_METHOD(AsyncMysqlConnection, getSslCertExtensions) { auto* data = Native::data(this_); + data->verifyValidConnection(); + auto ret = req::make(); const auto* context = data->m_conn->getConnectionContext(); if (context && context->sslCertIdentities.hasValue()) { @@ -1278,6 +1286,8 @@ static Object HHVM_METHOD(AsyncMysqlConnection, getSslCertExtensions) { static bool HHVM_METHOD(AsyncMysqlConnection, isSslCertValidationEnforced) { auto* data = Native::data(this_); + data->verifyValidConnection(); + const auto* context = data->m_conn->getConnectionContext(); return context && context->isServerCertValidated; } From 44c81c2b161015ad0fd05df5db61c5c39eba32b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Wed, 25 Jun 2025 13:01:04 +0200 Subject: [PATCH 69/72] Disable push builds for now --- .github/workflows/ubuntu.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 95cba76e752053..01a67a08f1c1eb 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -1,11 +1,6 @@ name: Ubuntu CI on: - push: - branches-ignore: - # Exclude the push event for exported diffs, because the CI for export - # should have been covered by GitHub Actions triggered by pull requests. - - "export-D+" pull_request: concurrency: From 3f2f65709f78c7bbf6119c9341157e28604de3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Wed, 25 Jun 2025 13:03:05 +0200 Subject: [PATCH 70/72] Update OPAM deps with too old versions --- hphp/hack/ocaml_deps_data.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hphp/hack/ocaml_deps_data.sh b/hphp/hack/ocaml_deps_data.sh index a3be0abe0da67c..53c3e85192ed06 100644 --- a/hphp/hack/ocaml_deps_data.sh +++ b/hphp/hack/ocaml_deps_data.sh @@ -6,11 +6,11 @@ export HACK_OPAM_DEPS=( base.v0.16.3 base64.3.5.0 camlp-streams.5.0.1 - cmdliner.1.1.1 + cmdliner.1.3.0 core_kernel.v0.16.0 core_unix.v0.16.0 dtoa.0.3.2 - dune.3.6.0 + dune.3.6.2 fileutils.0.6.4 fmt.0.9.0 iomux.0.3 @@ -20,7 +20,7 @@ export HACK_OPAM_DEPS=( lwt_log.1.1.2 lwt_ppx.2.1.0 memtrace.0.2.3 - merlin.5.0-502 + merlin.5.3-502 mtime.1.4.0 ocp-indent.1.8.1 ounit2.2.2.6 From 55ac70f8a3a0025260ff068f5510d91defc8d794 Mon Sep 17 00:00:00 2001 From: hershel-theodore-layton <81193606+hershel-theodore-layton@users.noreply.github.com> Date: Sat, 31 May 2025 21:14:41 +0200 Subject: [PATCH 71/72] dpkg-buildpackage: error: unknown option or argument --no-lintian --- ci/bin/make-debianish-package | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/bin/make-debianish-package b/ci/bin/make-debianish-package index b839d0aff0cc81..eb3dbb8c02d929 100755 --- a/ci/bin/make-debianish-package +++ b/ci/bin/make-debianish-package @@ -80,7 +80,7 @@ if [ -x "$PREBUILD" ]; then #shellcheck disable=SC1090 source $PREBUILD fi -debuild -us -uc +debuild --no-lintian -us -uc cd .. FILES=$(awk '/^Files:/ { files=1; next } /^[^ ]/ { files=0; next } files==1 { print $NF }' ./*.changes) From 7514d73923fe1f86510a0a87f9a2fa53107ad533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Tue, 29 Jul 2025 00:33:32 +0200 Subject: [PATCH 72/72] Raise required CMake version to 3.18 CMake 3.31 deprecates compatibility with CMake < 3.10 and CMake 4.0 removes compatibility with CMake < 3.5 entirely. As the required CMake version hasn't been raised in 12 years, select 3.18 as a reasonably recent minimum CMake version with wide availability (Ubuntu Jammy ships 3.22, Debian oldstable Bullseye ships 3.18). Remove cmake_policy() calls that now default to NEW due to the higher minimum version requirement. A further benefit of this is that CMP0065[1] now also defaults to NEW, which means that the `hhvm` binary is no longer linked with `--export-dynamic`, making the (stripped) binary around 30MiB smaller. OSS could also choose to supply an explicit dynamic list as a followup as done in D2747334 and D67114451, but it doesn't seem to be required just now. [1] https://cmake.org/cmake/help/latest/policy/CMP0065.html --- CMakeLists.txt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2487d03fd2040f..b5738e26bef7d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) -# Make `get_target_property()` on a target that does not exist a fatal error -# https://cmake.org/cmake/help/v3.0/policy/CMP0045.html -cmake_policy(SET CMP0045 NEW) -# ditto for add_dependencies(): https://cmake.org/cmake/help/v3.0/policy/CMP0046.html -cmake_policy(SET CMP0046 NEW) +cmake_minimum_required(VERSION 3.18 FATAL_ERROR) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON)