chromium/v8/test/cctest/heap/test-heap.cc

// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * 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.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "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 THE COPYRIGHT
// OWNER 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 <stdlib.h>

#include <utility>

#include "include/v8-function.h"
#include "src/api/api-inl.h"
#include "src/base/strings.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/compilation-cache.h"
#include "src/codegen/compiler.h"
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/script-details.h"
#include "src/common/globals.h"
#include "src/debug/debug.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/execution.h"
#include "src/flags/flags.h"
#include "src/handles/global-handles-inl.h"
#include "src/heap/combined-heap.h"
#include "src/heap/factory.h"
#include "src/heap/gc-tracer.h"
#include "src/heap/heap-inl.h"
#include "src/heap/heap-verifier.h"
#include "src/heap/heap.h"
#include "src/heap/incremental-marking.h"
#include "src/heap/large-page-metadata-inl.h"
#include "src/heap/large-spaces.h"
#include "src/heap/mark-compact-inl.h"
#include "src/heap/mark-compact.h"
#include "src/heap/marking-barrier.h"
#include "src/heap/marking-state-inl.h"
#include "src/heap/memory-reducer.h"
#include "src/heap/mutable-page-metadata.h"
#include "src/heap/parked-scope.h"
#include "src/heap/remembered-set-inl.h"
#include "src/heap/safepoint.h"
#include "src/ic/ic.h"
#include "src/numbers/hash-seed-inl.h"
#include "src/objects/call-site-info-inl.h"
#include "src/objects/elements.h"
#include "src/objects/field-type.h"
#include "src/objects/heap-number-inl.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/js-collection-inl.h"
#include "src/objects/managed-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/slots.h"
#include "src/objects/transitions.h"
#include "src/regexp/regexp.h"
#include "src/snapshot/snapshot.h"
#include "src/tracing/tracing-category-observer.h"
#include "src/utils/ostreams.h"
#include "test/cctest/cctest.h"
#include "test/cctest/feedback-vector-helper.h"
#include "test/cctest/heap/heap-tester.h"
#include "test/cctest/heap/heap-utils.h"
#include "test/cctest/test-transitions.h"

namespace v8 {
namespace internal {
namespace heap {

// We only start allocation-site tracking with the second instantiation.
static const int kPretenureCreationCount =;

static void CheckMap(Tagged<Map> map, int type, int instance_size) {}

TEST(HeapMaps) {}

static void VerifyStoredPrototypeMap(Isolate* isolate,
                                     int stored_map_context_index,
                                     int stored_ctor_context_index) {}

// Checks that critical maps stored on the context (mostly used for fast-path
// checks) are unchanged after initialization.
TEST(ContextMaps) {}

TEST(InitialObjects) {}

static void CheckOddball(Isolate* isolate, Tagged<Object> obj,
                         const char* string) {}

static void CheckSmi(Isolate* isolate, int value, const char* string) {}

static void CheckNumber(Isolate* isolate, double value, const char* string) {}

void CheckEmbeddedObjectsAreEqual(Isolate* isolate, DirectHandle<Code> lhs,
                                  DirectHandle<Code> rhs) {}

static void CheckGcSafeFindCodeForInnerPointer(Isolate* isolate) {}

TEST(HandleNull) {}

TEST(HeapObjects) {}

TEST(Tagging) {}

TEST(GarbageCollection) {}

static void VerifyStringAllocation(Isolate* isolate, const char* string) {}

TEST(String) {}

TEST(LocalHandles) {}

TEST(GlobalHandles) {}

static bool WeakPointerCleared =;

static void TestWeakGlobalHandleCallback(
    const v8::WeakCallbackInfo<void>& data) {}

TEST(WeakGlobalUnmodifiedApiHandlesScavenge) {}

TEST(WeakGlobalHandlesMark) {}

TEST(DeleteWeakGlobalHandle) {}

TEST(BytecodeArray) {}

static const char* not_so_random_string_table[] =;

static void CheckInternalizedStrings(const char** strings) {}

TEST(StringTable) {}

TEST(FunctionAllocation) {}

TEST(ObjectProperties) {}

TEST(JSObjectMaps) {}

TEST(JSArray) {}

TEST(JSObjectCopy) {}

TEST(StringAllocation) {}

static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {}

TEST(Iteration) {}

TEST(TestBytecodeFlushing) {}

static void TestMultiReferencedBytecodeFlushing(bool sparkplug_compile) {}

TEST(TestMultiReferencedBytecodeFlushing) {}

TEST(TestMultiReferencedBytecodeFlushingWithSparkplug) {}

HEAP_TEST(Regress10560) {}

UNINITIALIZED_TEST(Regress10843) {}

size_t near_heap_limit_invocation_count =;
size_t InvokeGCNearHeapLimitCallback(void* data, size_t current_heap_limit,
                                     size_t initial_heap_limit) {}

UNINITIALIZED_TEST(Regress12777) {}

#if !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN)
TEST(TestOptimizeAfterBytecodeFlushingCandidate) {}
#endif  // !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN)

TEST(TestUseOfIncrementalBarrierOnCompileLazy) {}

void CompilationCacheCachingBehavior(bool retain_script) {}

TEST(CompilationCacheCachingBehaviorDiscardScript) {}

TEST(CompilationCacheCachingBehaviorRetainScript) {}

namespace {

template <typename T>
Handle<SharedFunctionInfo> GetSharedFunctionInfo(
    v8::Local<T> function_or_script) {}

template <typename T>
void AgeBytecode(v8::Local<T> function_or_script) {}

void CompilationCacheRegeneration(bool retain_root_sfi, bool flush_root_sfi,
                                  bool flush_eager_sfi) {}

}  // namespace

TEST(CompilationCacheRegeneration0) {}
TEST(CompilationCacheRegeneration1) {}
TEST(CompilationCacheRegeneration2) {}
TEST(CompilationCacheRegeneration3) {}
TEST(CompilationCacheRegeneration4) {}
TEST(CompilationCacheRegeneration5) {}
TEST(CompilationCacheRegeneration6) {}
TEST(CompilationCacheRegeneration7) {}

static void OptimizeEmptyFunction(const char* name) {}

// Count the number of native contexts in the weak list of native contexts.
int CountNativeContexts() {}

TEST(TestInternalWeakLists) {}

TEST(TestSizeOfRegExpCode) {}

HEAP_TEST(TestSizeOfObjects) {}

TEST(TestAlignmentCalculations) {}

static Tagged<HeapObject> AllocateAligned(MainAllocator* allocator, int size,
                                          AllocationAlignment alignment) {}

TEST(TestAlignedAllocation) {}

static Tagged<HeapObject> OldSpaceAllocateAligned(
    int size, AllocationAlignment alignment) {}

// Get old space allocation into the desired alignment.
static Address AlignOldSpace(AllocationAlignment alignment, int offset) {}

// Test the case where allocation must be done from the free list, so filler
// may precede or follow the object.
TEST(TestAlignedOverAllocation) {}

TEST(HeapNumberAlignment) {}

TEST(TestSizeOfObjectsVsHeapObjectIteratorPrecision) {}

static int NumberOfGlobalObjects() {}

// Test that we don't embed maps from foreign contexts into
// optimized code.
TEST(LeakNativeContextViaMap) {}

// Test that we don't embed functions from foreign contexts into
// optimized code.
TEST(LeakNativeContextViaFunction) {}

TEST(LeakNativeContextViaMapKeyed) {}

TEST(LeakNativeContextViaMapProto) {}

TEST(InstanceOfStubWriteBarrier) {}

HEAP_TEST(GCFlags) {}

HEAP_TEST(Regress845060) {}

TEST(OptimizedPretenuringAllocationFolding) {}

TEST(OptimizedPretenuringObjectArrayLiterals) {}

TEST(OptimizedPretenuringNestedInObjectProperties) {}

TEST(OptimizedPretenuringMixedInObjectProperties) {}

TEST(OptimizedPretenuringDoubleArrayProperties) {}

TEST(OptimizedPretenuringDoubleArrayLiterals) {}

TEST(OptimizedPretenuringNestedMixedArrayLiterals) {}

TEST(OptimizedPretenuringNestedObjectLiterals) {}

TEST(OptimizedPretenuringNestedDoubleLiterals) {}

// Test regular array literals allocation.
TEST(OptimizedAllocationArrayLiterals) {}

static int CountMapTransitions(i::Isolate* isolate, Tagged<Map> map) {}

// Test that map transitions are cleared and maps are collected with
// incremental marking as well.
TEST(Regress1465) {}

static i::Handle<JSObject> GetByName(const char* name) {}

#ifdef DEBUG
static void AddTransitions(int transitions_count) {}

static void AddPropertyTo(int gc_count, Handle<JSObject> object,
                          const char* property_name) {}

TEST(TransitionArrayShrinksDuringAllocToZero) {}

TEST(TransitionArrayShrinksDuringAllocToOne) {}

TEST(TransitionArrayShrinksDuringAllocToOnePropertyFound) {}
#endif  // DEBUG

TEST(ReleaseOverReservedPages) {}

static int forced_gc_counter =;

void MockUseCounterCallback(v8::Isolate* isolate,
                            v8::Isolate::UseCounterFeature feature) {}

TEST(CountForcedGC) {}

#ifdef OBJECT_PRINT
TEST(PrintSharedFunctionInfo) {}
#endif  // OBJECT_PRINT

TEST(IncrementalMarkingPreservesMonomorphicCallIC) {}

static void CheckVectorIC(DirectHandle<JSFunction> f, int slot_index,
                          InlineCacheState desired_state) {}

TEST(IncrementalMarkingPreservesMonomorphicConstructor) {}

TEST(IncrementalMarkingPreservesMonomorphicIC) {}

TEST(IncrementalMarkingPreservesPolymorphicIC) {}

TEST(ContextDisposeDoesntClearPolymorphicIC) {}

class SourceResource : public v8::String::ExternalOneByteStringResource {};

void ReleaseStackTraceDataTest(v8::Isolate* isolate, const char* source,
                               const char* accessor) {}

UNINITIALIZED_TEST(ReleaseStackTraceData) {}

// TODO(mmarchini) also write tests for async/await and Promise.all
void DetailedErrorStackTraceTest(const char* src,
                                 std::function<void(Handle<FixedArray>)> test) {}

Tagged<FixedArray> ParametersOf(DirectHandle<FixedArray> stack_trace,
                                int frame_index) {}

// * Test interpreted function error
TEST(DetailedErrorStackTrace) {}

// * Test optimized function with inline frame error
TEST(DetailedErrorStackTraceInline) {}

// * Test builtin exit error
TEST(DetailedErrorStackTraceBuiltinExit) {}

TEST(Regress169928) {}

TEST(LargeObjectSlotRecording) {}

class DummyVisitor : public RootVisitor {};

TEST(PersistentHandles) {}

static void TestFillersFromPersistentHandles(bool promote) {}

TEST(DoNotEvacuateFillersFromPersistentHandles) {}

TEST(DoNotPromoteFillersFromPersistentHandles) {}

TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) {}

TEST(DisableInlineAllocation) {}

static int AllocationSitesCount(Heap* heap) {}

static int SlimAllocationSiteCount(Heap* heap) {}

TEST(EnsureAllocationSiteDependentCodesProcessed) {}

void CheckNumberOfAllocations(Heap* heap, const char* source,
                              int expected_full_alloc,
                              int expected_slim_alloc) {}

TEST(AllocationSiteCreation) {}

TEST(CellsInOptimizedCodeAreWeak) {}

TEST(ObjectsInOptimizedCodeAreWeak) {}

TEST(NewSpaceObjectsInOptimizedCode) {}

TEST(ObjectsInEagerlyDeoptimizedCodeAreWeak) {}

static Handle<InstructionStream> DummyOptimizedCode(Isolate* isolate) {}

static bool weak_ic_cleared =;

static void ClearWeakIC(
    const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {}

TEST(WeakFunctionInConstructor) {}

// Checks that the value returned by execution of the source is weak.
void CheckWeakness(const char* source) {}

// Each of the following "weak IC" tests creates an IC that embeds a map with
// the prototype pointing to _proto_ and checks that the _proto_ dies on GC.
TEST(WeakMapInMonomorphicLoadIC) {}

TEST(WeakMapInPolymorphicLoadIC) {}

TEST(WeakMapInMonomorphicKeyedLoadIC) {}

TEST(WeakMapInPolymorphicKeyedLoadIC) {}

TEST(WeakMapInMonomorphicStoreIC) {}

TEST(WeakMapInPolymorphicStoreIC) {}

TEST(WeakMapInMonomorphicKeyedStoreIC) {}

TEST(WeakMapInPolymorphicKeyedStoreIC) {}

TEST(WeakMapInMonomorphicCompareNilIC) {}

Handle<JSFunction> GetFunctionByName(Isolate* isolate, const char* name) {}

void CheckIC(DirectHandle<JSFunction> function, int slot_index,
             InlineCacheState state) {}

TEST(MonomorphicStaysMonomorphicAfterGC) {}

TEST(PolymorphicStaysPolymorphicAfterGC) {}

#ifdef DEBUG
TEST(AddInstructionChangesNewSpacePromotion) {}

void OnFatalErrorExpectOOM(const char* location, const char* message) {}

TEST(CEntryStubOOM) {}

#endif  // DEBUG

static void InterruptCallback357137(v8::Isolate* isolate, void* data) {}

static void RequestInterrupt(const v8::FunctionCallbackInfo<v8::Value>& info) {}

HEAP_TEST(Regress538257) {}

TEST(Regress357137) {}

TEST(Regress507979) {}

TEST(Regress388880) {}

TEST(Regress3631) {}

TEST(Regress442710) {}

HEAP_TEST(NumberStringCacheSize) {}

TEST(Regress3877) {}

Handle<WeakFixedArray> AddRetainedMap(Isolate* isolate,
                                      DirectHandle<NativeContext> context) {}

void CheckMapRetainingFor(int n) {}

TEST(MapRetaining) {}

TEST(RetainedMapsCleanup) {}

TEST(PreprocessStackTrace) {}

void AllocateInSpace(Isolate* isolate, size_t bytes, AllocationSpace space) {}

TEST(NewSpaceAllocationCounter) {}

TEST(OldSpaceAllocationCounter) {}

static void CheckLeak(const v8::FunctionCallbackInfo<v8::Value>& info) {}

TEST(MessageObjectLeak) {}

static void CheckEqualSharedFunctionInfos(
    const v8::FunctionCallbackInfo<v8::Value>& info) {}

static void RemoveCodeAndGC(const v8::FunctionCallbackInfo<v8::Value>& info) {}

TEST(CanonicalSharedFunctionInfo) {}

TEST(ScriptIterator) {}

// This is the same as Factory::NewByteArray, except it doesn't retry on
// allocation failure.
AllocationResult HeapTester::AllocateByteArrayForTest(
    Heap* heap, int length, AllocationType allocation_type) {}

bool HeapTester::CodeEnsureLinearAllocationArea(Heap* heap, int size_in_bytes) {}

HEAP_TEST(Regress587004) {}

HEAP_TEST(Regress589413) {}

TEST(Regress598319) {}

Handle<FixedArray> ShrinkArrayAndCheckSize(Heap* heap, int length) {}

TEST(Regress609761) {}

TEST(LiveBytes) {}

TEST(Regress615489) {}

class StaticOneByteResource : public v8::String::ExternalOneByteStringResource {};

TEST(Regress631969) {}

TEST(ContinuousRightTrimFixedArrayInBlackArea) {}

TEST(Regress618958) {}

TEST(YoungGenerationLargeObjectAllocationScavenge) {}

TEST(YoungGenerationLargeObjectAllocationMarkCompact) {}

TEST(YoungGenerationLargeObjectAllocationReleaseScavenger) {}

TEST(UncommitUnusedLargeObjectMemory) {}

template <RememberedSetType direction>
static size_t GetRememberedSetSize(Tagged<HeapObject> obj) {}

TEST(RememberedSet_InsertOnWriteBarrier) {}

TEST(RememberedSet_InsertInLargePage) {}

TEST(RememberedSet_RemoveStaleOnScavenge) {}

// The OLD_TO_OLD remembered set is created temporary by GC and is cleared at
// the end of the pass. There is no way to observe it so the test only checks
// that compaction has happened and otherwise relies on code's self-validation.
TEST(RememberedSet_OldToOld) {}

TEST(RememberedSetRemoveRange) {}

HEAP_TEST(Regress670675) {}

HEAP_TEST(RegressMissingWriteBarrierInAllocate) {}

HEAP_TEST(MarkCompactEpochCounter) {}

UNINITIALIZED_TEST(ReinitializeStringHashSeed) {}

const int kHeapLimit =;
Isolate* oom_isolate =;

void OOMCallback(const char* location, const OOMDetails&) {}

UNINITIALIZED_TEST(OutOfMemory) {}

UNINITIALIZED_TEST(OutOfMemoryIneffectiveGC) {}

UNINITIALIZED_TEST(OutOfMemoryIneffectiveGCRunningJS) {}

HEAP_TEST(Regress779503) {}

struct OutOfMemoryState {};

size_t NearHeapLimitCallback(void* raw_state, size_t current_heap_limit,
                             size_t initial_heap_limit) {}

size_t MemoryAllocatorSizeFromHeapCapacity(size_t capacity) {}

UNINITIALIZED_TEST(OutOfMemorySmallObjects) {}

UNINITIALIZED_TEST(OutOfMemoryLargeObjects) {}

UNINITIALIZED_TEST(RestoreHeapLimit) {}

void HeapTester::UncommitUnusedMemory(Heap* heap) {}

class DeleteNative {};

TEST(Regress8014) {}

TEST(Regress8617) {}

HEAP_TEST(MemoryReducerActivationForSmallHeaps) {}

TEST(AllocateExternalBackingStore) {}

TEST(CodeObjectRegistry) {}

TEST(Regress9701) {}

#if defined(V8_TARGET_ARCH_64_BIT) && !defined(V8_OS_ANDROID)
UNINITIALIZED_TEST(HugeHeapLimit) {}
#endif

UNINITIALIZED_TEST(HeapLimit) {}

TEST(NoCodeRangeInJitlessMode) {}

TEST(GarbageCollectionWithLocalHeap) {}

TEST(Regress10698) {}

class TestAllocationTracker : public HeapObjectAllocationTracker {};

HEAP_TEST(CodeLargeObjectSpace) {}

UNINITIALIZED_HEAP_TEST(CodeLargeObjectSpace64k) {}

TEST(IsPendingAllocationNewSpace) {}

TEST(IsPendingAllocationNewLOSpace) {}

TEST(IsPendingAllocationOldSpace) {}

TEST(IsPendingAllocationLOSpace) {}

TEST(Regress10900) {}

namespace {
void GenerateGarbage() {}

}  // anonymous namespace

TEST(Regress11181) {}

TEST(LongTaskStatsFullAtomic) {}

TEST(LongTaskStatsFullIncremental) {}

TEST(LongTaskStatsYoung) {}

}  // namespace heap
}  // namespace internal
}  // namespace v8

#undef __