// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Flags: --allow-natives-syntax const MIN_DICTIONARY_INDEX = 8192; (function ToStringThrows() { function TestError() {} let callCount = 0; const a = [1, 2]; assertThrows(() => a.join({ toString() { callCount++; throw new TestError; } }), TestError); assertSame(1, callCount); // Verifies cycle detection still works properly after thrown error. assertSame('1,2', a.join()); })(); (function RecursiveJoinCall() { const a = [1,2,3]; let callCount = 0; const sep = { toString() { callCount++; return a.join('-'); } }; assertSame('11-2-321-2-33', a.join(sep)); assertSame(1, callCount); // Verify cycle detection works properly after nested call assertSame('1,2,3', a.join()); })(); (function ArrayLengthIncreased() { const a = [1,2,3]; let callCount = 0; assertSame('1,2,3', a.join({ toString() { callCount++; a.push(4); return ','; } })); assertSame(1, callCount); assertSame('1,2,3,4', a.join()); })(); (function ArrayLengthDecreased() { const a = [1,2,3]; let callCount = 0; assertSame('1,2,', a.join({ toString() { callCount++; a.pop(); return ','; } })); assertSame(1, callCount); assertSame('1,2', a.join()); })(); (function ArrayEmptied() { const a = [1,2,3]; let callCount = 0; assertSame(',,', a.join({ toString() { callCount++; a.length = 0; return ','; } })); assertSame(1, callCount); })(); (function NumberDictionaryEmptied() { const a = []; a[0] = 1; a[MIN_DICTIONARY_INDEX] = 2; assertTrue(%HasDictionaryElements(a)); let callCount = 0; assertSame('-'.repeat(MIN_DICTIONARY_INDEX), a.join({ toString() { callCount++; a.length = 0; return '-'; } })); assertSame(1, callCount); })(); (function NumberDictionaryEmptiedEmptySeparator() { const a = []; a[0] = 1; a[MIN_DICTIONARY_INDEX] = 2; assertTrue(%HasDictionaryElements(a)); let callCount = 0; assertSame(''.repeat(MIN_DICTIONARY_INDEX), a.join({ toString() { callCount++; a.length = 0; return ''; } })); assertSame(1, callCount); })(); (function ElementsKindSmiToDoubles() { const a = [1,2,3]; let callCount = 0; assertTrue(%HasSmiElements(a)); assertSame('1.5,2,3', a.join({ toString() { callCount++; a[0] = 1.5; assertTrue(%HasDoubleElements(a)); return ','; } })); assertSame(1, callCount); assertSame('1.5,2,3', a.join()); })(); (function ElementsKindDoublesToObjects() { const a = [1.5, 2.5, 3.5]; let callCount = 0; assertTrue(%HasDoubleElements(a)); assertSame('one,2.5,3.5', a.join({ toString() { callCount++; a[0] = 'one'; assertTrue(%HasObjectElements(a)); return ','; } })); assertSame(1, callCount); assertSame('one,2.5,3.5', a.join()); })(); (function ArrayIsNoLongerFast() { const a = [1,2,3]; let callCount = 0; assertSame('666,2,3', a.join({ toString() { callCount++; Object.defineProperty(a, '0', { get(){ return 666; } }); return ','; } })); assertSame(1, callCount); assertSame('666,2,3', a.join()); })(); (function ArrayPrototypeUnset() { const a = [1,2]; a.length = 3; let callCount = 0; assertSame('1,2,4', a.join({ toString() { callCount++; a.__proto__ = { '2': 4 }; return ','; } })); assertSame(1, callCount); a.__proto__ = Array.prototype; assertSame('1,2,', a.join()); })(); (function ArrayPrototypeIsNoLongerFast() { const a = [1,2,3]; let callCount = 0; assertSame('1,2,777', a.join({ toString() { callCount++; a.pop(); Object.defineProperty(Array.prototype, '2', { get(){ return 777; } }); return ','; } })); assertSame(1, callCount); assertSame('1,2', a.join()); })();