From 491e7dba5234d228eebfcb6b2286bbeaf6620b4a Mon Sep 17 00:00:00 2001 From: Mark Lam Date: Sat, 25 May 2024 22:39:03 -0700 Subject: [PATCH] Refactor LLInt::Data::performAssertions() into assertInvariants(). https://bugs.webkit.org/show_bug.cgi?id=274723 rdar://128746336 Reviewed by Yusuke Suzuki. The intent of LLInt::Data::performAssertions() was to assert some invariants that cannot be expressed as static_asserts, or did not have a convenient place to express the static_asserts because they are about constants used in the LLInt asm files. These asserts need only be executed once. At the time, I added a call to performAssertions() from the VM constructor. The better place to call it would be from JSC::initialize(), which is only executed once per process. Additionally, over time, we started using this function to assert other invariants. Hence, we should rename it and put it in a place not associated with the LLInt specifically. Lastly, replace all uses of the antiquated STATIC_ASSERT macro with static_assert. * Source/JavaScriptCore/CMakeLists.txt: * Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj: * Source/JavaScriptCore/Sources.txt: * Source/JavaScriptCore/interpreter/CallFrame.h: (JSC::CallFrame::argumentOffset): (JSC::CallFrame::argumentOffsetIncludingThis): * Source/JavaScriptCore/llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): Deleted. * Source/JavaScriptCore/llint/LLIntData.h: * Source/JavaScriptCore/runtime/AssertInvariants.cpp: Added. (JSC::assertInvariants): * Source/JavaScriptCore/runtime/AssertInvariants.h: Added. * Source/JavaScriptCore/runtime/InitializeThreading.cpp: (JSC::initialize): * Source/JavaScriptCore/runtime/VM.cpp: (JSC::VM::VM): Canonical link: https://commits.webkit.org/279327@main --- Source/JavaScriptCore/CMakeLists.txt | 1 + .../JavaScriptCore.xcodeproj/project.pbxproj | 6 + Source/JavaScriptCore/Sources.txt | 1 + Source/JavaScriptCore/interpreter/CallFrame.h | 6 +- Source/JavaScriptCore/llint/LLIntData.cpp | 122 +-------------- Source/JavaScriptCore/llint/LLIntData.h | 7 +- .../runtime/AssertInvariants.cpp | 145 ++++++++++++++++++ .../JavaScriptCore/runtime/AssertInvariants.h | 39 +++++ .../runtime/InitializeThreading.cpp | 3 + Source/JavaScriptCore/runtime/VM.cpp | 4 +- 10 files changed, 201 insertions(+), 133 deletions(-) create mode 100644 Source/JavaScriptCore/runtime/AssertInvariants.cpp create mode 100644 Source/JavaScriptCore/runtime/AssertInvariants.h diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index af40dd0bc7ee..3c0295bc0b5f 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -932,6 +932,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS runtime/ArrayPrototype.h runtime/ArrayStorage.h runtime/ArrayStorageInlines.h + runtime/AssertInvariants.h runtime/AsyncIteratorPrototype.h runtime/AuxiliaryBarrier.h runtime/AuxiliaryBarrierInlines.h diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 36232f6e6b8a..318fb0e2cb2e 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -2109,6 +2109,7 @@ FE1E2C3F2240DD5800F6B729 /* MacroAssemblerARM64E.h in Headers */ = {isa = PBXBuildFile; fileRef = FE1E2C3E2240D30B00F6B729 /* MacroAssemblerARM64E.h */; settings = {ATTRIBUTES = (Private, ); }; }; FE1E2C402240DD6200F6B729 /* ARM64EAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = FE1E2C3D2240D2F600F6B729 /* ARM64EAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */; settings = {ATTRIBUTES = (Private, ); }; }; + FE265F202C02D39100997B07 /* AssertInvariants.h in Headers */ = {isa = PBXBuildFile; fileRef = FE265F1E2C02D39100997B07 /* AssertInvariants.h */; }; FE287D02252FB2E800D723F9 /* VerifierSlotVisitor.h in Headers */ = {isa = PBXBuildFile; fileRef = FE287D01252FB2E800D723F9 /* VerifierSlotVisitor.h */; settings = {ATTRIBUTES = (Private, ); }; }; FE2A87601F02381600EB31B2 /* MinimumReservedZoneSize.h in Headers */ = {isa = PBXBuildFile; fileRef = FE2A875F1F02381600EB31B2 /* MinimumReservedZoneSize.h */; }; FE2CC9302756B2B9003F5AB8 /* HeapSubspaceTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = FE2CC92F2756B2B9003F5AB8 /* HeapSubspaceTypes.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -5887,6 +5888,8 @@ FE1E2C3E2240D30B00F6B729 /* MacroAssemblerARM64E.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerARM64E.h; sourceTree = ""; }; FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntCLoop.cpp; path = llint/LLIntCLoop.cpp; sourceTree = ""; }; FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntCLoop.h; path = llint/LLIntCLoop.h; sourceTree = ""; }; + FE265F1E2C02D39100997B07 /* AssertInvariants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AssertInvariants.h; sourceTree = ""; }; + FE265F1F2C02D39100997B07 /* AssertInvariants.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AssertInvariants.cpp; sourceTree = ""; }; FE287D01252FB2E800D723F9 /* VerifierSlotVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VerifierSlotVisitor.h; sourceTree = ""; }; FE2A875F1F02381600EB31B2 /* MinimumReservedZoneSize.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MinimumReservedZoneSize.h; sourceTree = ""; }; FE2BD66E25C0DC8200999D3B /* VerifierSlotVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VerifierSlotVisitor.cpp; sourceTree = ""; }; @@ -7899,6 +7902,8 @@ E3443E3028E9711700C0020C /* ArrayPrototypeInlines.h */, 0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */, FE1D6D7023625AB0007A5C26 /* ArrayStorageInlines.h */, + FE265F1F2C02D39100997B07 /* AssertInvariants.cpp */, + FE265F1E2C02D39100997B07 /* AssertInvariants.h */, 8B6016F31F3E3CC000F9DE6A /* AsyncFromSyncIteratorPrototype.cpp */, 8B6016F41F3E3CC000F9DE6A /* AsyncFromSyncIteratorPrototype.h */, 276B385A2A71D0B500252F4E /* AsyncFromSyncIteratorPrototypeInlines.h */, @@ -10264,6 +10269,7 @@ 4BDF3004289324AC00AE1DE3 /* AssemblyComments.h in Headers */, 0F24E54117EA9F5900ABB217 /* AssemblyHelpers.h in Headers */, 6B767E7B26791F270017F8D1 /* AssemblyHelpersSpoolers.h in Headers */, + FE265F202C02D39100997B07 /* AssertInvariants.h in Headers */, A784A26111D16622005776AC /* ASTBuilder.h in Headers */, 8B6016F61F3E3CC000F9DE6A /* AsyncFromSyncIteratorPrototype.h in Headers */, 276B38692A71D0B600252F4E /* AsyncFromSyncIteratorPrototypeInlines.h in Headers */, diff --git a/Source/JavaScriptCore/Sources.txt b/Source/JavaScriptCore/Sources.txt index 78af32557117..b28a58f12000 100644 --- a/Source/JavaScriptCore/Sources.txt +++ b/Source/JavaScriptCore/Sources.txt @@ -756,6 +756,7 @@ runtime/ArrayConstructor.cpp runtime/ArrayConventions.cpp runtime/ArrayIteratorPrototype.cpp runtime/ArrayPrototype.cpp +runtime/AssertInvariants.cpp runtime/AsyncFromSyncIteratorPrototype.cpp runtime/AsyncGeneratorFunctionConstructor.cpp runtime/AsyncGeneratorFunctionPrototype.cpp diff --git a/Source/JavaScriptCore/interpreter/CallFrame.h b/Source/JavaScriptCore/interpreter/CallFrame.h index 364097025c5a..9f58d1eda312 100644 --- a/Source/JavaScriptCore/interpreter/CallFrame.h +++ b/Source/JavaScriptCore/interpreter/CallFrame.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003-2022 Apple Inc. All rights reserved. + * Copyright (C) 2003-2024 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -259,8 +259,8 @@ using JSInstruction = BaseInstruction; // Access to arguments as passed. (After capture, arguments may move to a different location.) size_t argumentCount() const { return argumentCountIncludingThis() - 1; } size_t argumentCountIncludingThis() const { return this[static_cast(CallFrameSlot::argumentCountIncludingThis)].payload(); } - static int argumentOffset(int argument) { return (CallFrameSlot::firstArgument + argument); } - static int argumentOffsetIncludingThis(int argument) { return (CallFrameSlot::thisArgument + argument); } + static constexpr int argumentOffset(int argument) { return (CallFrameSlot::firstArgument + argument); } + static constexpr int argumentOffsetIncludingThis(int argument) { return (CallFrameSlot::thisArgument + argument); } // In the following (argument() and setArgument()), the 'argument' // parameter is the index of the arguments of the target function of diff --git a/Source/JavaScriptCore/llint/LLIntData.cpp b/Source/JavaScriptCore/llint/LLIntData.cpp index c7abd7a67f6c..933a81e4294b 100644 --- a/Source/JavaScriptCore/llint/LLIntData.cpp +++ b/Source/JavaScriptCore/llint/LLIntData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2023 Apple Inc. All rights reserved. + * Copyright (C) 2011-2024 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,20 +26,12 @@ #include "config.h" #include "LLIntData.h" -#include "ArithProfile.h" -#include "BaselineJITCode.h" -#include "CodeBlock.h" -#include "DFGJITCode.h" #include "JSCConfig.h" #include "LLIntCLoop.h" #include "LLIntEntrypoint.h" -#include "LLIntPCRanges.h" #include "LLIntSlowPaths.h" #include "LLIntThunks.h" #include "Opcode.h" -#include "WriteBarrier.h" - -#define STATIC_ASSERT(cond) static_assert(cond, "LLInt assumes " #cond) namespace JSC { @@ -266,116 +258,4 @@ void initialize() g_jscConfig.defaultCallThunk = defaultCall().code().taggedPtr(); } -IGNORE_WARNINGS_BEGIN("missing-noreturn") -void Data::performAssertions(VM& vm) -{ - UNUSED_PARAM(vm); - - // Assertions to match LowLevelInterpreter.asm. If you change any of this code, be - // prepared to change LowLevelInterpreter.asm as well!! - -#if USE(JSVALUE64) - const ptrdiff_t CallFrameHeaderSlots = 5; -#else // USE(JSVALUE64) // i.e. 32-bit version - const ptrdiff_t CallFrameHeaderSlots = 4; -#endif - const ptrdiff_t MachineRegisterSize = sizeof(CPURegister); - const ptrdiff_t SlotSize = 8; - - STATIC_ASSERT(sizeof(Register) == SlotSize); - STATIC_ASSERT(CallFrame::headerSizeInRegisters == CallFrameHeaderSlots); - - ASSERT(!CallFrame::callerFrameOffset()); - STATIC_ASSERT(CallerFrameAndPC::sizeInRegisters == (MachineRegisterSize * 2) / SlotSize); - static_assert(CallFrame::returnPCOffset() == CallFrame::callerFrameOffset() + MachineRegisterSize); - static_assert(static_cast>(CallFrameSlot::codeBlock) * sizeof(Register) == CallFrame::returnPCOffset() + MachineRegisterSize); - STATIC_ASSERT(CallFrameSlot::callee * sizeof(Register) == CallFrameSlot::codeBlock * sizeof(Register) + SlotSize); - STATIC_ASSERT(CallFrameSlot::argumentCountIncludingThis * sizeof(Register) == CallFrameSlot::callee * sizeof(Register) + SlotSize); - STATIC_ASSERT(CallFrameSlot::thisArgument * sizeof(Register) == CallFrameSlot::argumentCountIncludingThis * sizeof(Register) + SlotSize); - STATIC_ASSERT(CallFrame::headerSizeInRegisters == CallFrameSlot::thisArgument); - - ASSERT(CallFrame::argumentOffsetIncludingThis(0) == CallFrameSlot::thisArgument); - -#if CPU(BIG_ENDIAN) - STATIC_ASSERT(TagOffset == 0); - STATIC_ASSERT(PayloadOffset == 4); -#else - STATIC_ASSERT(TagOffset == 4); - STATIC_ASSERT(PayloadOffset == 0); -#endif - -#if ENABLE(C_LOOP) - ASSERT(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters() == 1); -#elif USE(JSVALUE32_64) - ASSERT(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters() == 1); -#elif (CPU(X86_64) && !OS(WINDOWS)) || CPU(ARM64) - ASSERT(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters() == 4); -#elif (CPU(X86_64) && OS(WINDOWS)) - ASSERT(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters() == 4); -#endif - - ASSERT(!(reinterpret_cast((reinterpret_cast*>(0x4000)->slot())) - 0x4000)); - - // FIXME: make these assertions less horrible. -#if ASSERT_ENABLED - Vector testVector; - testVector.resize(42); - ASSERT(bitwise_cast(&testVector)[sizeof(void*)/sizeof(uint32_t) + 1] == 42); - ASSERT(bitwise_cast(&testVector)[0] == testVector.begin()); -#endif - - { - UnaryArithProfile arithProfile; - arithProfile.argSawInt32(); - ASSERT(arithProfile.bits() == UnaryArithProfile::observedIntBits()); - ASSERT(arithProfile.argObservedType().isOnlyInt32()); - } - { - UnaryArithProfile arithProfile; - arithProfile.argSawNumber(); - ASSERT(arithProfile.bits() == UnaryArithProfile::observedNumberBits()); - ASSERT(arithProfile.argObservedType().isOnlyNumber()); - } - - { - BinaryArithProfile arithProfile; - arithProfile.lhsSawInt32(); - arithProfile.rhsSawInt32(); - ASSERT(arithProfile.bits() == BinaryArithProfile::observedIntIntBits()); - ASSERT(arithProfile.lhsObservedType().isOnlyInt32()); - ASSERT(arithProfile.rhsObservedType().isOnlyInt32()); - } - { - BinaryArithProfile arithProfile; - arithProfile.lhsSawNumber(); - arithProfile.rhsSawInt32(); - ASSERT(arithProfile.bits() == BinaryArithProfile::observedNumberIntBits()); - ASSERT(arithProfile.lhsObservedType().isOnlyNumber()); - ASSERT(arithProfile.rhsObservedType().isOnlyInt32()); - } - { - BinaryArithProfile arithProfile; - arithProfile.lhsSawNumber(); - arithProfile.rhsSawNumber(); - ASSERT(arithProfile.bits() == BinaryArithProfile::observedNumberNumberBits()); - ASSERT(arithProfile.lhsObservedType().isOnlyNumber()); - ASSERT(arithProfile.rhsObservedType().isOnlyNumber()); - } - { - BinaryArithProfile arithProfile; - arithProfile.lhsSawInt32(); - arithProfile.rhsSawNumber(); - ASSERT(arithProfile.bits() == BinaryArithProfile::observedIntNumberBits()); - ASSERT(arithProfile.lhsObservedType().isOnlyInt32()); - ASSERT(arithProfile.rhsObservedType().isOnlyNumber()); - } - -#if ENABLE(DFG_JIT) - // We share the same layout for particular fields in all JITData to make our data IC assume this. - RELEASE_ASSERT(BaselineJITData::offsetOfGlobalObject() == DFG::JITData::offsetOfGlobalObject()); - RELEASE_ASSERT(BaselineJITData::offsetOfStackOffset() == DFG::JITData::offsetOfStackOffset()); -#endif -} -IGNORE_WARNINGS_END - } } // namespace JSC::LLInt diff --git a/Source/JavaScriptCore/llint/LLIntData.h b/Source/JavaScriptCore/llint/LLIntData.h index 6934771eb978..4ff49e18b0e7 100644 --- a/Source/JavaScriptCore/llint/LLIntData.h +++ b/Source/JavaScriptCore/llint/LLIntData.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 Apple Inc. All rights reserved. + * Copyright (C) 2011-2024 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,11 +48,6 @@ extern "C" JS_EXPORT_PRIVATE JSC::Opcode g_opcodeMapWide16[numOpcodeIDs + numWas extern "C" JS_EXPORT_PRIVATE JSC::Opcode g_opcodeMapWide32[numOpcodeIDs + numWasmOpcodeIDs]; class Data { - -public: - static void performAssertions(VM&); - -private: friend void initialize(); friend JSInstruction* exceptionInstructions(); diff --git a/Source/JavaScriptCore/runtime/AssertInvariants.cpp b/Source/JavaScriptCore/runtime/AssertInvariants.cpp new file mode 100644 index 000000000000..983ac0617d25 --- /dev/null +++ b/Source/JavaScriptCore/runtime/AssertInvariants.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2024 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AssertInvariants.h" + +#include "ArithProfile.h" +#include "BaselineJITCode.h" +#include "CodeBlock.h" +#include "DFGJITCode.h" + +namespace JSC { + +void assertInvariants() +{ + // Assertions to match LowLevelInterpreter.asm. If you change any of this code, be + // prepared to change LowLevelInterpreter.asm as well!! + { +#if USE(JSVALUE64) + const ptrdiff_t CallFrameHeaderSlots = 5; +#else // USE(JSVALUE64) // i.e. 32-bit version + const ptrdiff_t CallFrameHeaderSlots = 4; +#endif + const ptrdiff_t MachineRegisterSize = sizeof(CPURegister); + const ptrdiff_t SlotSize = 8; + + static_assert(sizeof(Register) == SlotSize); + static_assert(CallFrame::headerSizeInRegisters == CallFrameHeaderSlots); + + static_assert(!CallFrame::callerFrameOffset()); + static_assert(CallerFrameAndPC::sizeInRegisters == (MachineRegisterSize * 2) / SlotSize); + static_assert(CallFrame::returnPCOffset() == CallFrame::callerFrameOffset() + MachineRegisterSize); + static_assert(static_cast>(CallFrameSlot::codeBlock) * sizeof(Register) == CallFrame::returnPCOffset() + MachineRegisterSize); + static_assert(CallFrameSlot::callee * sizeof(Register) == CallFrameSlot::codeBlock * sizeof(Register) + SlotSize); + static_assert(CallFrameSlot::argumentCountIncludingThis * sizeof(Register) == CallFrameSlot::callee * sizeof(Register) + SlotSize); + static_assert(CallFrameSlot::thisArgument * sizeof(Register) == CallFrameSlot::argumentCountIncludingThis * sizeof(Register) + SlotSize); + static_assert(CallFrame::headerSizeInRegisters == CallFrameSlot::thisArgument); + + static_assert(CallFrame::argumentOffsetIncludingThis(0) == CallFrameSlot::thisArgument); + +#if CPU(BIG_ENDIAN) + static_assert(TagOffset == 0); + static_assert(PayloadOffset == 4); +#else + static_assert(TagOffset == 4); + static_assert(PayloadOffset == 0); +#endif + +#if ENABLE(C_LOOP) + ASSERT(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters() == 1); +#elif USE(JSVALUE32_64) + ASSERT(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters() == 1); +#elif (CPU(X86_64) && !OS(WINDOWS)) || CPU(ARM64) + ASSERT(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters() == 4); +#elif (CPU(X86_64) && OS(WINDOWS)) + ASSERT(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters() == 4); +#endif + + ASSERT(!(reinterpret_cast((reinterpret_cast*>(0x4000)->slot())) - 0x4000)); + } + + // FIXME: make these assertions less horrible. +#if ASSERT_ENABLED + Vector testVector; + testVector.resize(42); + ASSERT(bitwise_cast(&testVector)[sizeof(void*) / sizeof(uint32_t) + 1] == 42); + ASSERT(bitwise_cast(&testVector)[0] == testVector.begin()); +#endif + + { + UnaryArithProfile arithProfile; + arithProfile.argSawInt32(); + ASSERT(arithProfile.bits() == UnaryArithProfile::observedIntBits()); + ASSERT(arithProfile.argObservedType().isOnlyInt32()); + } + { + UnaryArithProfile arithProfile; + arithProfile.argSawNumber(); + ASSERT(arithProfile.bits() == UnaryArithProfile::observedNumberBits()); + ASSERT(arithProfile.argObservedType().isOnlyNumber()); + } + + { + BinaryArithProfile arithProfile; + arithProfile.lhsSawInt32(); + arithProfile.rhsSawInt32(); + ASSERT(arithProfile.bits() == BinaryArithProfile::observedIntIntBits()); + ASSERT(arithProfile.lhsObservedType().isOnlyInt32()); + ASSERT(arithProfile.rhsObservedType().isOnlyInt32()); + } + { + BinaryArithProfile arithProfile; + arithProfile.lhsSawNumber(); + arithProfile.rhsSawInt32(); + ASSERT(arithProfile.bits() == BinaryArithProfile::observedNumberIntBits()); + ASSERT(arithProfile.lhsObservedType().isOnlyNumber()); + ASSERT(arithProfile.rhsObservedType().isOnlyInt32()); + } + { + BinaryArithProfile arithProfile; + arithProfile.lhsSawNumber(); + arithProfile.rhsSawNumber(); + ASSERT(arithProfile.bits() == BinaryArithProfile::observedNumberNumberBits()); + ASSERT(arithProfile.lhsObservedType().isOnlyNumber()); + ASSERT(arithProfile.rhsObservedType().isOnlyNumber()); + } + { + BinaryArithProfile arithProfile; + arithProfile.lhsSawInt32(); + arithProfile.rhsSawNumber(); + ASSERT(arithProfile.bits() == BinaryArithProfile::observedIntNumberBits()); + ASSERT(arithProfile.lhsObservedType().isOnlyInt32()); + ASSERT(arithProfile.rhsObservedType().isOnlyNumber()); + } + +#if ENABLE(DFG_JIT) + // We share the same layout for particular fields in all JITData to make our data IC assume this. + static_assert(BaselineJITData::offsetOfGlobalObject() == DFG::JITData::offsetOfGlobalObject()); + static_assert(BaselineJITData::offsetOfStackOffset() == DFG::JITData::offsetOfStackOffset()); +#endif +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/AssertInvariants.h b/Source/JavaScriptCore/runtime/AssertInvariants.h new file mode 100644 index 000000000000..54e94368de3f --- /dev/null +++ b/Source/JavaScriptCore/runtime/AssertInvariants.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +namespace JSC { + +// The design of many subsystems in JSC are dependent on certain invariants being +// correct in order for the subsystems to work correctly. Sometimes these invariants +// can be expressed as static_asserts, but sometimes, they can onlybe expressed with +// runtime checks. These checks only need to be run once to ensure correctness. +// This function provides a centralized place to put these checks so that they will +// be run once and only once (per process) during initialization before the rest of +// the system runs. +void assertInvariants(); + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp index 124e92a831e0..fdba217efde3 100644 --- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp +++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp @@ -30,6 +30,7 @@ #include "InitializeThreading.h" #include "AssemblyComments.h" +#include "AssertInvariants.h" #include "ExecutableAllocator.h" #include "InPlaceInterpreter.h" #include "JITOperationList.h" @@ -142,6 +143,8 @@ void initialize() Wasm::prepareSignalingMemory(); } + assertInvariants(); + WTF::compilerFence(); RELEASE_ASSERT(!g_jscConfig.initializeHasBeenCalled); g_jscConfig.initializeHasBeenCalled = true; diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp index d5f3d35ec5b4..130e4575d6da 100644 --- a/Source/JavaScriptCore/runtime/VM.cpp +++ b/Source/JavaScriptCore/runtime/VM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2023 Apple Inc. All rights reserved. + * Copyright (C) 2008-2024 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -352,8 +352,6 @@ VM::VM(VMType vmType, HeapType heapType, WTF::RunLoop* runLoop, bool* success) heap.notifyIsSafeToCollect(); - LLInt::Data::performAssertions(*this); - if (UNLIKELY(Options::useProfiler())) { m_perBytecodeProfiler = makeUnique(*this);