diff --git a/js/public/GCAPI.h b/js/public/GCAPI.h index 2c978b932b69..00d6da5001e6 100644 --- a/js/public/GCAPI.h +++ b/js/public/GCAPI.h @@ -323,7 +323,7 @@ typedef enum JSGCParamKey { /* * The current size of the nursery. * - * read-only. + * This parameter is read-only. */ JSGC_NURSERY_BYTES = 34, @@ -348,6 +348,13 @@ typedef enum JSGCParamKey { * Default: IncrementalWeakMarkEnabled */ JSGC_INCREMENTAL_WEAKMAP_ENABLED = 37, + + /** + * The chunk size in bytes for this system. + * + * This parameter is read-only. + */ + JSGC_CHUNK_BYTES = 38, } JSGCParamKey; /* diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index c547c56e7615..4759a9331901 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -585,7 +585,8 @@ static bool MinorGC(JSContext* cx, unsigned argc, Value* vp) { _("pretenureGroupThreshold", JSGC_PRETENURE_GROUP_THRESHOLD, true) \ _("zoneAllocDelayKB", JSGC_ZONE_ALLOC_DELAY_KB, true) \ _("mallocThresholdBase", JSGC_MALLOC_THRESHOLD_BASE, true) \ - _("mallocGrowthFactor", JSGC_MALLOC_GROWTH_FACTOR, true) + _("mallocGrowthFactor", JSGC_MALLOC_GROWTH_FACTOR, true) \ + _("chunkBytes", JSGC_CHUNK_BYTES, false) static const struct ParamInfo { const char* name; diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index 76dad76f777b..bbb01927e1f0 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -1502,6 +1502,8 @@ uint32_t GCRuntime::getParameter(JSGCParamKey key, const AutoLockGC& lock) { return tunables.mallocThresholdBase() / 1024 / 1024; case JSGC_MALLOC_GROWTH_FACTOR: return uint32_t(tunables.mallocGrowthFactor() * 100); + case JSGC_CHUNK_BYTES: + return ChunkSize; default: MOZ_CRASH("Unknown parameter key"); } diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index acbf6f633cff..bf2580647d78 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -1543,13 +1543,15 @@ size_t js::Nursery::targetSize(JS::GCReason reason) { /* static */ size_t js::Nursery::roundSize(size_t size) { - if (size >= ChunkSize) { - size = Round(size, ChunkSize); - } else { - size = std::min(Round(size, SubChunkStep), - RoundDown(NurseryChunkUsableSize, SubChunkStep)); - } + static_assert(SubChunkStep > gc::ChunkTrailerSize, + "Don't allow the nursery to overwrite the trailer when using " + "less than a chunk"); + + size_t step = size >= ChunkSize ? ChunkSize : SubChunkStep; + size = Round(size, step); + MOZ_ASSERT(size >= ArenaSize); + return size; } diff --git a/js/src/jit-test/tests/gc/bug-1531626.js b/js/src/jit-test/tests/gc/bug-1531626.js index 637bebbfa5c0..c0d0af8ebdf0 100644 --- a/js/src/jit-test/tests/gc/bug-1531626.js +++ b/js/src/jit-test/tests/gc/bug-1531626.js @@ -6,7 +6,9 @@ load(libdir + "asserts.js"); -var testSizesKB = [128, 129, 255, 256, 1023, 1024, 3*1024, 4*1024+1, 16*1024]; +const chunkSizeKB = gcparam('chunkBytes') / 1024; + +var testSizesKB = [128, 129, 255, 256, 516, 1023, 1024, 3*1024, 4*1024+1, 16*1024]; // Valid maximum sizes must be >= 1MB. var testMaxSizesKB = testSizesKB.filter(x => x >= 1024); @@ -33,8 +35,8 @@ function setMinMax(min, max) { // Set the maximum first so that we don't hit a case where max < min. gcparam('maxNurseryBytes', max * 1024); gcparam('minNurseryBytes', min * 1024); - assertEq(nearestLegalSize(max) * 1024, gcparam('maxNurseryBytes')); - assertEq(nearestLegalSize(min) * 1024, gcparam('minNurseryBytes')); + assertEq(gcparam('maxNurseryBytes'), nearestLegalSize(max) * 1024); + assertEq(gcparam('minNurseryBytes'), nearestLegalSize(min) * 1024); allocateSomeThings(); gc(); } @@ -46,11 +48,8 @@ function allocateSomeThings() { } function nearestLegalSize(sizeKB) { - if (sizeKB >= 1024) { - return round(sizeKB, 1024); - } - - return Math.min(round(sizeKB, 4), 1020); + let step = sizeKB >= chunkSizeKB ? chunkSizeKB : 4; + return round(sizeKB, step); } function round(x, y) {