11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci// Flags: --expose-gc 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ciconst { gcUntil, buildType } = require('../../common'); 51cb0ef41Sopenharmony_ciconst assert = require('assert'); 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciconst test_reference = require(`./build/${buildType}/test_reference`); 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci// This test script uses external values with finalizer callbacks 101cb0ef41Sopenharmony_ci// in order to track when values get garbage-collected. Each invocation 111cb0ef41Sopenharmony_ci// of a finalizer callback increments the finalizeCount property. 121cb0ef41Sopenharmony_ciassert.strictEqual(test_reference.finalizeCount, 0); 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ci// Run each test function in sequence, 151cb0ef41Sopenharmony_ci// with an async delay and GC call between each. 161cb0ef41Sopenharmony_ciasync function runTests() { 171cb0ef41Sopenharmony_ci (() => { 181cb0ef41Sopenharmony_ci const symbol = test_reference.createSymbol('testSym'); 191cb0ef41Sopenharmony_ci test_reference.createReference(symbol, 0); 201cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.referenceValue, symbol); 211cb0ef41Sopenharmony_ci })(); 221cb0ef41Sopenharmony_ci test_reference.deleteReference(); 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci (() => { 251cb0ef41Sopenharmony_ci const symbol = test_reference.createSymbolFor('testSymFor'); 261cb0ef41Sopenharmony_ci test_reference.createReference(symbol, 0); 271cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.referenceValue, symbol); 281cb0ef41Sopenharmony_ci })(); 291cb0ef41Sopenharmony_ci test_reference.deleteReference(); 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ci (() => { 321cb0ef41Sopenharmony_ci const symbol = test_reference.createSymbolFor('testSymFor'); 331cb0ef41Sopenharmony_ci test_reference.createReference(symbol, 1); 341cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.referenceValue, symbol); 351cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.referenceValue, Symbol.for('testSymFor')); 361cb0ef41Sopenharmony_ci })(); 371cb0ef41Sopenharmony_ci test_reference.deleteReference(); 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci (() => { 401cb0ef41Sopenharmony_ci const symbol = test_reference.createSymbolForEmptyString(); 411cb0ef41Sopenharmony_ci test_reference.createReference(symbol, 0); 421cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.referenceValue, Symbol.for('')); 431cb0ef41Sopenharmony_ci })(); 441cb0ef41Sopenharmony_ci test_reference.deleteReference(); 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci (() => { 471cb0ef41Sopenharmony_ci const symbol = test_reference.createSymbolForEmptyString(); 481cb0ef41Sopenharmony_ci test_reference.createReference(symbol, 1); 491cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.referenceValue, symbol); 501cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.referenceValue, Symbol.for('')); 511cb0ef41Sopenharmony_ci })(); 521cb0ef41Sopenharmony_ci test_reference.deleteReference(); 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci assert.throws(() => test_reference.createSymbolForIncorrectLength(), 551cb0ef41Sopenharmony_ci /Invalid argument/); 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci (() => { 581cb0ef41Sopenharmony_ci const value = test_reference.createExternal(); 591cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.finalizeCount, 0); 601cb0ef41Sopenharmony_ci assert.strictEqual(typeof value, 'object'); 611cb0ef41Sopenharmony_ci test_reference.checkExternal(value); 621cb0ef41Sopenharmony_ci })(); 631cb0ef41Sopenharmony_ci await gcUntil('External value without a finalizer', 641cb0ef41Sopenharmony_ci () => (test_reference.finalizeCount === 0)); 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci (() => { 671cb0ef41Sopenharmony_ci const value = test_reference.createExternalWithFinalize(); 681cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.finalizeCount, 0); 691cb0ef41Sopenharmony_ci assert.strictEqual(typeof value, 'object'); 701cb0ef41Sopenharmony_ci test_reference.checkExternal(value); 711cb0ef41Sopenharmony_ci })(); 721cb0ef41Sopenharmony_ci await gcUntil('External value with a finalizer', 731cb0ef41Sopenharmony_ci () => (test_reference.finalizeCount === 1)); 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci (() => { 761cb0ef41Sopenharmony_ci const value = test_reference.createExternalWithFinalize(); 771cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.finalizeCount, 0); 781cb0ef41Sopenharmony_ci test_reference.createReference(value, 0); 791cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.referenceValue, value); 801cb0ef41Sopenharmony_ci })(); 811cb0ef41Sopenharmony_ci // Value should be GC'd because there is only a weak ref 821cb0ef41Sopenharmony_ci await gcUntil('Weak reference', 831cb0ef41Sopenharmony_ci () => (test_reference.referenceValue === undefined && 841cb0ef41Sopenharmony_ci test_reference.finalizeCount === 1)); 851cb0ef41Sopenharmony_ci test_reference.deleteReference(); 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci (() => { 881cb0ef41Sopenharmony_ci const value = test_reference.createExternalWithFinalize(); 891cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.finalizeCount, 0); 901cb0ef41Sopenharmony_ci test_reference.createReference(value, 1); 911cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.referenceValue, value); 921cb0ef41Sopenharmony_ci })(); 931cb0ef41Sopenharmony_ci // Value should NOT be GC'd because there is a strong ref 941cb0ef41Sopenharmony_ci await gcUntil('Strong reference', 951cb0ef41Sopenharmony_ci () => (test_reference.finalizeCount === 0)); 961cb0ef41Sopenharmony_ci test_reference.deleteReference(); 971cb0ef41Sopenharmony_ci await gcUntil('Strong reference (cont.d)', 981cb0ef41Sopenharmony_ci () => (test_reference.finalizeCount === 1)); 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci (() => { 1011cb0ef41Sopenharmony_ci const value = test_reference.createExternalWithFinalize(); 1021cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.finalizeCount, 0); 1031cb0ef41Sopenharmony_ci test_reference.createReference(value, 1); 1041cb0ef41Sopenharmony_ci })(); 1051cb0ef41Sopenharmony_ci // Value should NOT be GC'd because there is a strong ref 1061cb0ef41Sopenharmony_ci await gcUntil('Strong reference, increment then decrement to weak reference', 1071cb0ef41Sopenharmony_ci () => (test_reference.finalizeCount === 0)); 1081cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.incrementRefcount(), 2); 1091cb0ef41Sopenharmony_ci // Value should NOT be GC'd because there is a strong ref 1101cb0ef41Sopenharmony_ci await gcUntil( 1111cb0ef41Sopenharmony_ci 'Strong reference, increment then decrement to weak reference (cont.d-1)', 1121cb0ef41Sopenharmony_ci () => (test_reference.finalizeCount === 0)); 1131cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.decrementRefcount(), 1); 1141cb0ef41Sopenharmony_ci // Value should NOT be GC'd because there is a strong ref 1151cb0ef41Sopenharmony_ci await gcUntil( 1161cb0ef41Sopenharmony_ci 'Strong reference, increment then decrement to weak reference (cont.d-2)', 1171cb0ef41Sopenharmony_ci () => (test_reference.finalizeCount === 0)); 1181cb0ef41Sopenharmony_ci assert.strictEqual(test_reference.decrementRefcount(), 0); 1191cb0ef41Sopenharmony_ci // Value should be GC'd because the ref is now weak! 1201cb0ef41Sopenharmony_ci await gcUntil( 1211cb0ef41Sopenharmony_ci 'Strong reference, increment then decrement to weak reference (cont.d-3)', 1221cb0ef41Sopenharmony_ci () => (test_reference.finalizeCount === 1)); 1231cb0ef41Sopenharmony_ci test_reference.deleteReference(); 1241cb0ef41Sopenharmony_ci // Value was already GC'd 1251cb0ef41Sopenharmony_ci await gcUntil( 1261cb0ef41Sopenharmony_ci 'Strong reference, increment then decrement to weak reference (cont.d-4)', 1271cb0ef41Sopenharmony_ci () => (test_reference.finalizeCount === 1)); 1281cb0ef41Sopenharmony_ci} 1291cb0ef41Sopenharmony_cirunTests(); 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci// This test creates a napi_ref on an object that has 1321cb0ef41Sopenharmony_ci// been wrapped by napi_wrap and for which the finalizer 1331cb0ef41Sopenharmony_ci// for the wrap calls napi_delete_ref on that napi_ref. 1341cb0ef41Sopenharmony_ci// 1351cb0ef41Sopenharmony_ci// Since both the wrap and the reference use the same 1361cb0ef41Sopenharmony_ci// object the finalizer for the wrap and reference 1371cb0ef41Sopenharmony_ci// may run in the same gc and in any order. 1381cb0ef41Sopenharmony_ci// 1391cb0ef41Sopenharmony_ci// It does that to validate that napi_delete_ref can be 1401cb0ef41Sopenharmony_ci// called before the finalizer has been run for the 1411cb0ef41Sopenharmony_ci// reference (there is a finalizer behind the scenes even 1421cb0ef41Sopenharmony_ci// though it cannot be passed to napi_create_reference). 1431cb0ef41Sopenharmony_ci// 1441cb0ef41Sopenharmony_ci// Since the order is not guarranteed, run the 1451cb0ef41Sopenharmony_ci// test a number of times maximize the chance that we 1461cb0ef41Sopenharmony_ci// get a run with the desired order for the test. 1471cb0ef41Sopenharmony_ci// 1481cb0ef41Sopenharmony_ci// 1000 reliably recreated the problem without the fix 1491cb0ef41Sopenharmony_ci// required to ensure delete could be called before 1501cb0ef41Sopenharmony_ci// the finalizer in manual testing. 1511cb0ef41Sopenharmony_cifor (let i = 0; i < 1000; i++) { 1521cb0ef41Sopenharmony_ci const wrapObject = new Object(); 1531cb0ef41Sopenharmony_ci test_reference.validateDeleteBeforeFinalize(wrapObject); 1541cb0ef41Sopenharmony_ci global.gc(); 1551cb0ef41Sopenharmony_ci} 156