Files
ladybird/Libraries/LibJS/CMakeLists.txt
Timothy Flynn 86c8a57794 LibJS+LibUnicode: Use icu4x for Temporal calendar operations
Replace the icu4c-based calendar implementation with one built on the
icu4x Rust crate (icu_calendar).

The icu4c API does not expose the píngqì month-assignment algorithm
used by the Chinese and Dangi lunisolar calendars. Our old code had to
approximate this by walking months via epoch millisecond arithmetic and
manually tracking leap month positions, which produced incorrect month
codes and ordinal month numbers for certain years. The icu4x calendar
crate handles píngqì natively.

With this patch, which is almost a 1-to-1 mapping of ICU invocations, we
pass 100% of all Temporal test262 tests.

The end goal might be to use icu4x for all of our ICU needs. But it does
not yet provide the APIs needed for all ECMA-402 prototypes.
2026-03-11 07:09:57 -04:00

423 lines
15 KiB
CMake

include(libjs_generators)
set(SOURCES
AST.cpp
ASTDump.cpp
Bytecode/AsmInterpreter/AsmInterpreter.cpp
Bytecode/ASTCodegen.cpp
Bytecode/BasicBlock.cpp
Bytecode/Builtins.cpp
Bytecode/Executable.cpp
Bytecode/Generator.cpp
Bytecode/IdentifierTable.cpp
Bytecode/Instruction.cpp
Bytecode/Interpreter.cpp
Bytecode/Label.cpp
Bytecode/PropertyKeyTable.cpp
Bytecode/RegexTable.cpp
Bytecode/ScopedOperand.cpp
Bytecode/StringTable.cpp
Console.cpp
Contrib/Test262/262Object.cpp
Contrib/Test262/AgentObject.cpp
Contrib/Test262/GlobalObject.cpp
Contrib/Test262/IsHTMLDDA.cpp
CyclicModule.cpp
Heap/Cell.cpp
Lexer.cpp
Module.cpp
Parser.cpp
ParserError.cpp
PipelineComparison.cpp
Print.cpp
RustIntegration.cpp
Runtime/AbstractOperations.cpp
Runtime/Accessor.cpp
Runtime/Agent.cpp
Runtime/AggregateError.cpp
Runtime/AggregateErrorConstructor.cpp
Runtime/AggregateErrorPrototype.cpp
Runtime/ArgumentsObject.cpp
Runtime/Array.cpp
Runtime/ArrayBuffer.cpp
Runtime/ArrayBufferConstructor.cpp
Runtime/ArrayBufferPrototype.cpp
Runtime/ArrayConstructor.cpp
Runtime/ArrayIterator.cpp
Runtime/ArrayIteratorPrototype.cpp
Runtime/ArrayPrototype.cpp
Runtime/AsyncDisposableStack.cpp
Runtime/AsyncDisposableStackConstructor.cpp
Runtime/AsyncDisposableStackPrototype.cpp
Runtime/AsyncFromSyncIterator.cpp
Runtime/AsyncFromSyncIteratorPrototype.cpp
Runtime/AsyncFunctionConstructor.cpp
Runtime/AsyncFunctionDriverWrapper.cpp
Runtime/AsyncFunctionPrototype.cpp
Runtime/AsyncGenerator.cpp
Runtime/AsyncGeneratorFunctionConstructor.cpp
Runtime/AsyncGeneratorFunctionPrototype.cpp
Runtime/AsyncGeneratorPrototype.cpp
Runtime/AsyncIteratorPrototype.cpp
Runtime/AtomicsObject.cpp
Runtime/BigInt.cpp
Runtime/BigIntConstructor.cpp
Runtime/BigIntObject.cpp
Runtime/BigIntPrototype.cpp
Runtime/BooleanConstructor.cpp
Runtime/BooleanObject.cpp
Runtime/BooleanPrototype.cpp
Runtime/BoundFunction.cpp
Runtime/ClassConstruction.cpp
Runtime/ClassFieldDefinition.cpp
Runtime/Completion.cpp
Runtime/CompletionCell.cpp
Runtime/ConsoleObjectPrototype.cpp
Runtime/ConsoleObject.cpp
Runtime/DataView.cpp
Runtime/DataViewConstructor.cpp
Runtime/DataViewPrototype.cpp
Runtime/Date.cpp
Runtime/DateConstructor.cpp
Runtime/DatePrototype.cpp
Runtime/DeclarativeEnvironment.cpp
Runtime/DisposableStack.cpp
Runtime/DisposableStackConstructor.cpp
Runtime/DisposableStackPrototype.cpp
Runtime/ECMAScriptFunctionObject.cpp
Runtime/Environment.cpp
Runtime/Error.cpp
Runtime/ErrorConstructor.cpp
Runtime/ErrorPrototype.cpp
Runtime/ErrorTypes.cpp
Runtime/ExecutionContext.cpp
Runtime/InterpreterStack.cpp
Runtime/FinalizationRegistry.cpp
Runtime/FinalizationRegistryConstructor.cpp
Runtime/FinalizationRegistryPrototype.cpp
Runtime/FunctionConstructor.cpp
Runtime/FunctionEnvironment.cpp
Runtime/FunctionObject.cpp
Runtime/FunctionPrototype.cpp
Runtime/GeneratorFunctionConstructor.cpp
Runtime/GeneratorFunctionPrototype.cpp
Runtime/GeneratorObject.cpp
Runtime/GeneratorPrototype.cpp
Runtime/GeneratorResult.cpp
Runtime/GlobalEnvironment.cpp
Runtime/GlobalObject.cpp
Runtime/IndexedProperties.cpp
Runtime/Intl/AbstractOperations.cpp
Runtime/Intl/Collator.cpp
Runtime/Intl/CollatorCompareFunction.cpp
Runtime/Intl/CollatorConstructor.cpp
Runtime/Intl/CollatorPrototype.cpp
Runtime/Intl/DateTimeFormat.cpp
Runtime/Intl/DateTimeFormatConstructor.cpp
Runtime/Intl/DateTimeFormatFunction.cpp
Runtime/Intl/DateTimeFormatPrototype.cpp
Runtime/Intl/DisplayNames.cpp
Runtime/Intl/DisplayNamesConstructor.cpp
Runtime/Intl/DisplayNamesPrototype.cpp
Runtime/Intl/DurationFormat.cpp
Runtime/Intl/DurationFormatConstructor.cpp
Runtime/Intl/DurationFormatPrototype.cpp
Runtime/Intl/Intl.cpp
Runtime/Intl/ListFormat.cpp
Runtime/Intl/ListFormatConstructor.cpp
Runtime/Intl/ListFormatPrototype.cpp
Runtime/Intl/Locale.cpp
Runtime/Intl/LocaleConstructor.cpp
Runtime/Intl/LocalePrototype.cpp
Runtime/Intl/MathematicalValue.cpp
Runtime/Intl/NumberFormat.cpp
Runtime/Intl/NumberFormatConstructor.cpp
Runtime/Intl/NumberFormatFunction.cpp
Runtime/Intl/NumberFormatPrototype.cpp
Runtime/Intl/PluralRules.cpp
Runtime/Intl/PluralRulesConstructor.cpp
Runtime/Intl/PluralRulesPrototype.cpp
Runtime/Intl/RelativeTimeFormat.cpp
Runtime/Intl/RelativeTimeFormatConstructor.cpp
Runtime/Intl/RelativeTimeFormatPrototype.cpp
Runtime/Intl/Segmenter.cpp
Runtime/Intl/SegmenterConstructor.cpp
Runtime/Intl/SegmenterPrototype.cpp
Runtime/Intl/Segments.cpp
Runtime/Intl/SegmentIterator.cpp
Runtime/Intl/SegmentIteratorPrototype.cpp
Runtime/Intl/SegmentsPrototype.cpp
Runtime/Intrinsics.cpp
Runtime/Iterator.cpp
Runtime/IteratorConstructor.cpp
Runtime/IteratorHelper.cpp
Runtime/IteratorHelperPrototype.cpp
Runtime/IteratorPrototype.cpp
Runtime/JSONObject.cpp
Runtime/JobCallback.cpp
Runtime/KeyedCollections.cpp
Runtime/Map.cpp
Runtime/MapConstructor.cpp
Runtime/MapIterator.cpp
Runtime/MapIteratorPrototype.cpp
Runtime/MapPrototype.cpp
Runtime/MathObject.cpp
Runtime/ModuleEnvironment.cpp
Runtime/ModuleNamespaceObject.cpp
Runtime/NativeFunction.cpp
Runtime/NativeJavaScriptBackedFunction.cpp
Runtime/NumberConstructor.cpp
Runtime/NumberObject.cpp
Runtime/NumberPrototype.cpp
Runtime/Object.cpp
Runtime/ObjectConstructor.cpp
Runtime/ObjectEnvironment.cpp
Runtime/ObjectPrototype.cpp
Runtime/PrimitiveString.cpp
Runtime/PrivateEnvironment.cpp
Runtime/Promise.cpp
Runtime/PromiseCapability.cpp
Runtime/PromiseConstructor.cpp
Runtime/PromiseJobs.cpp
Runtime/PromisePrototype.cpp
Runtime/PromiseReaction.cpp
Runtime/PromiseResolvingElementFunctions.cpp
Runtime/PromiseResolvingFunction.cpp
Runtime/PropertyDescriptor.cpp
Runtime/ProxyConstructor.cpp
Runtime/ProxyObject.cpp
Runtime/RawJSONObject.cpp
Runtime/Realm.cpp
Runtime/Reference.cpp
Runtime/ReflectObject.cpp
Runtime/RegExpConstructor.cpp
Runtime/RegExpLegacyStaticProperties.cpp
Runtime/RegExpObject.cpp
Runtime/RegExpPrototype.cpp
Runtime/RegExpStringIterator.cpp
Runtime/RegExpStringIteratorPrototype.cpp
Runtime/Set.cpp
Runtime/SetConstructor.cpp
Runtime/SetIterator.cpp
Runtime/SetIteratorPrototype.cpp
Runtime/SetPrototype.cpp
Runtime/ShadowRealm.cpp
Runtime/ShadowRealmConstructor.cpp
Runtime/ShadowRealmPrototype.cpp
Runtime/Shape.cpp
Runtime/SharedArrayBufferConstructor.cpp
Runtime/SharedArrayBufferPrototype.cpp
Runtime/SharedFunctionInstanceData.cpp
Runtime/StringConstructor.cpp
Runtime/StringIterator.cpp
Runtime/StringIteratorPrototype.cpp
Runtime/StringObject.cpp
Runtime/StringPrototype.cpp
Runtime/SuppressedError.cpp
Runtime/SuppressedErrorConstructor.cpp
Runtime/SuppressedErrorPrototype.cpp
Runtime/Symbol.cpp
Runtime/SymbolConstructor.cpp
Runtime/SymbolObject.cpp
Runtime/SymbolPrototype.cpp
Runtime/Temporal/AbstractOperations.cpp
Runtime/Temporal/Calendar.cpp
Runtime/Temporal/DateEquations.cpp
Runtime/Temporal/Duration.cpp
Runtime/Temporal/DurationConstructor.cpp
Runtime/Temporal/DurationPrototype.cpp
Runtime/Temporal/Instant.cpp
Runtime/Temporal/InstantConstructor.cpp
Runtime/Temporal/InstantPrototype.cpp
Runtime/Temporal/ISO8601.cpp
Runtime/Temporal/Now.cpp
Runtime/Temporal/PlainDate.cpp
Runtime/Temporal/PlainDateConstructor.cpp
Runtime/Temporal/PlainDatePrototype.cpp
Runtime/Temporal/PlainDateTime.cpp
Runtime/Temporal/PlainDateTimeConstructor.cpp
Runtime/Temporal/PlainDateTimePrototype.cpp
Runtime/Temporal/PlainMonthDay.cpp
Runtime/Temporal/PlainMonthDayConstructor.cpp
Runtime/Temporal/PlainMonthDayPrototype.cpp
Runtime/Temporal/PlainTime.cpp
Runtime/Temporal/PlainTimeConstructor.cpp
Runtime/Temporal/PlainTimePrototype.cpp
Runtime/Temporal/PlainYearMonth.cpp
Runtime/Temporal/PlainYearMonthConstructor.cpp
Runtime/Temporal/PlainYearMonthPrototype.cpp
Runtime/Temporal/Temporal.cpp
Runtime/Temporal/TimeZone.cpp
Runtime/Temporal/ZonedDateTime.cpp
Runtime/Temporal/ZonedDateTimeConstructor.cpp
Runtime/Temporal/ZonedDateTimePrototype.cpp
Runtime/TypedArray.cpp
Runtime/TypedArrayConstructor.cpp
Runtime/TypedArrayPrototype.cpp
Runtime/Uint8Array.cpp
Runtime/Value.cpp
Runtime/VM.cpp
Runtime/WeakMap.cpp
Runtime/WeakMapConstructor.cpp
Runtime/WeakMapPrototype.cpp
Runtime/WeakRef.cpp
Runtime/WeakRefConstructor.cpp
Runtime/WeakRefPrototype.cpp
Runtime/WeakSet.cpp
Runtime/WeakSetConstructor.cpp
Runtime/WeakSetPrototype.cpp
Runtime/WrapForValidIteratorPrototype.cpp
Runtime/WrappedFunction.cpp
ScopeCollector.cpp
Script.cpp
SourceCode.cpp
SourceTextModule.cpp
SyntaxHighlighter.cpp
SyntheticModule.cpp
Token.cpp
)
generate_bytecode_def_derived()
set(GENERATED_SOURCES Bytecode/Op.cpp)
ladybird_lib(LibJS js EXPLICIT_SYMBOL_EXPORT)
find_package(simdjson CONFIG REQUIRED)
target_link_libraries(LibJS PRIVATE simdjson::simdjson)
target_link_libraries(LibJS PRIVATE LibCore LibCrypto LibFileSystem LibRegex LibSyntax LibGC)
# Link LibUnicode publicly to ensure ICU data (which is in libicudata.a) is available in any process using LibJS.
target_link_libraries(LibJS PUBLIC LibUnicode)
# TODO: This is probably also needed on RISC-V.
if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "i.86.*")
target_link_libraries(LibJS PRIVATE atomic)
endif()
if (WIN32)
# FIXME: Windows on ARM
target_link_libraries(LibJS PRIVATE clang_rt.builtins-x86_64.lib kernel32 ntdll Ws2_32 userenv)
else()
# This flag has no effect on Windows
target_compile_options(LibJS PRIVATE -fno-omit-frame-pointer)
endif()
target_link_libraries(LibJS PUBLIC JSClangPlugin)
if (ENABLE_RUST)
corrosion_import_crate(MANIFEST_PATH Rust/Cargo.toml CRATES libjs_rust)
target_link_libraries(LibJS PRIVATE libjs_rust)
target_compile_definitions(LibJS PRIVATE ENABLE_RUST)
install(TARGETS libjs_rust EXPORT LagomTargets
ARCHIVE COMPONENT Lagom_Development
)
# The Rust library and LibJS have a circular dependency (C++ calls Rust
# entry points, Rust calls C++ callbacks). For static builds, merge the
# Rust archive into the LibJS archive so all symbols are in one place.
if(NOT BUILD_SHARED_LIBS)
add_custom_command(TARGET LibJS POST_BUILD
COMMAND ${CMAKE_AR} -x $<TARGET_FILE:libjs_rust-static>
COMMAND ${CMAKE_AR} -qS $<TARGET_FILE:LibJS> *.o
COMMAND ${CMAKE_RANLIB} $<TARGET_FILE:LibJS>
COMMAND ${CMAKE_COMMAND} -E remove -f *.o
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/rust_merge_tmp
COMMENT "Merging Rust archive into LibJS"
)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/rust_merge_tmp)
endif()
endif()
# AsmInterpreter: generate platform-specific assembly from DSL
# NB: Win64 uses a different ABI (shadow space, different arg registers)
# from SysV AMD64, and the x86_64 backend only supports SysV for now.
if (NOT WIN32 AND ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64"))
set(ASMINT_ARCH "x86_64")
elseif ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "arm64")
set(ASMINT_ARCH "aarch64")
endif()
if (DEFINED ASMINT_ARCH)
enable_language(ASM)
set(ASMINTGEN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/AsmIntGen")
set(ASMINTGEN_BIN "${ASMINTGEN_DIR}/target/release/asmintgen")
set(ASMINT_DSL "${CMAKE_CURRENT_SOURCE_DIR}/Bytecode/AsmInterpreter/asmint.asm")
set(ASMINT_GENERATED_S "${CMAKE_CURRENT_BINARY_DIR}/Bytecode/AsmInterpreter/asmint_${ASMINT_ARCH}.S")
set(ASM_OFFSETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/Bytecode/AsmInterpreter/asm_offsets.conf")
# Build-time offset generator: compiles a small C++ program that uses
# offsetof() to emit struct field offsets as DSL constants.
add_executable(gen_asm_offsets "${CMAKE_CURRENT_SOURCE_DIR}/Bytecode/AsmInterpreter/gen_asm_offsets.cpp")
target_link_libraries(gen_asm_offsets PRIVATE AK)
target_compile_definitions(gen_asm_offsets PRIVATE private=public protected=public)
# NB: Strip fuzzer sanitizer flags so gen_asm_offsets can define its own main().
if (ENABLE_FUZZERS_LIBFUZZER)
target_compile_options(gen_asm_offsets PRIVATE -fno-sanitize=fuzzer)
target_link_options(gen_asm_offsets PRIVATE -fno-sanitize=fuzzer)
endif()
# NB: gen_asm_offsets no longer depends on Op.h since opcode field
# offsets are now computed from Bytecode.def by asmintgen directly.
add_custom_command(
OUTPUT "${ASM_OFFSETS_FILE}"
COMMAND "$<TARGET_FILE:gen_asm_offsets>" > "${ASM_OFFSETS_FILE}"
DEPENDS gen_asm_offsets
COMMENT "Generating asm struct offsets"
)
file(GLOB ASMINTGEN_SOURCES "${ASMINTGEN_DIR}/src/*.rs" "${ASMINTGEN_DIR}/Cargo.toml")
# NB: Clear linker-related env vars so cargo uses the default host
# linker. The CI may set CC/CXX or CARGO_TARGET_*_LINKER to a
# compiler that isn't available in all build configurations (e.g.
# clang-21 in GNU builds). asmintgen is a pure Rust host tool.
add_custom_command(
OUTPUT "${ASMINTGEN_BIN}"
COMMAND ${CMAKE_COMMAND} -E env
--unset=CC
--unset=CXX
--unset=CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER
--unset=CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER
cargo build --release
WORKING_DIRECTORY "${ASMINTGEN_DIR}"
DEPENDS ${ASMINTGEN_SOURCES}
COMMENT "Building asmintgen"
)
set(BYTECODE_DEF "${CMAKE_CURRENT_SOURCE_DIR}/Bytecode/Bytecode.def")
if (APPLE)
set(ASMINT_OBJ_FORMAT "macho")
else()
set(ASMINT_OBJ_FORMAT "elf")
endif()
set(ASMINT_EXTRA_FLAGS "")
# All Apple Silicon chips are ARMv8.5+ which includes FEAT_JSCVT.
if ("${ASMINT_ARCH}" STREQUAL "aarch64" AND APPLE)
list(APPEND ASMINT_EXTRA_FLAGS "--has-jscvt")
endif()
add_custom_command(
OUTPUT "${ASMINT_GENERATED_S}"
COMMAND "${ASMINTGEN_BIN}" --arch ${ASMINT_ARCH}
--object-format ${ASMINT_OBJ_FORMAT}
--constants "${ASM_OFFSETS_FILE}"
--bytecode-def "${BYTECODE_DEF}"
--input "${ASMINT_DSL}"
--output "${ASMINT_GENERATED_S}"
${ASMINT_EXTRA_FLAGS}
DEPENDS "${ASMINTGEN_BIN}" "${ASMINT_DSL}" "${ASM_OFFSETS_FILE}" "${BYTECODE_DEF}"
COMMENT "Generating asmint_${ASMINT_ARCH}.S from DSL"
)
target_sources(LibJS PRIVATE "${ASMINT_GENERATED_S}")
endif()
if (WIN32 AND ENABLE_ADDRESS_SANITIZER)
# FIXME: Fix address sanitizer stack-overflow error when running test-js.
# Even tripling the stack size for this target to 24MB didn't fix it, so it is most likely some ASAN related bug/quirk given test-js passes using the 8MB stack without ASAN
# ==9948==ERROR: AddressSanitizer: stack-overflow on address 0x7ffd983a6f47 (pc 0x7ffd983a6f47 bp 0x004e514053e0 sp 0x004e51405348 T0)
target_compile_options(LibJS PRIVATE -fno-sanitize=address)
endif()