mirror of
				https://github.com/tc39/test262.git
				synced 2025-10-25 01:33:56 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			412 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			412 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // Copyright 2016 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
 | |
| 
 | |
| function TestMeta() {
 | |
|   assertEquals(1, Object.entries.length);
 | |
|   assertEquals(Function.prototype, Object.getPrototypeOf(Object.entries));
 | |
|   assertEquals("entries", Object.entries.name);
 | |
| 
 | |
|   var descriptor = Object.getOwnPropertyDescriptor(Object, "entries");
 | |
|   assertTrue(descriptor.writable);
 | |
|   assertFalse(descriptor.enumerable);
 | |
|   assertTrue(descriptor.configurable);
 | |
| 
 | |
|   assertThrows(() => new Object.entries({}), TypeError);
 | |
| }
 | |
| TestMeta();
 | |
| 
 | |
| 
 | |
| function TestBasic(withWarmup) {
 | |
|   var x = 16;
 | |
|   var O = {
 | |
|     d: 1,
 | |
|     c: 3,
 | |
|     [Symbol.iterator]: void 0,
 | |
|     0: 123,
 | |
|     1000: 456,
 | |
|     [x * x]: "ducks",
 | |
|     [`0x${(x * x).toString(16)}`]: "quack"
 | |
|   };
 | |
|   O.a = 2;
 | |
|   O.b = 4;
 | |
|   Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN });
 | |
|   if (withWarmup) {
 | |
|     for (const key in O) {}
 | |
|   }
 | |
|   O.c = 6;
 | |
|   const resultEntries = [
 | |
|     ["0", 123],
 | |
|     ["256", "ducks"],
 | |
|     ["1000", 456],
 | |
|     ["d", 1],
 | |
|     ["c", 6],
 | |
|     ["0x100", "quack"],
 | |
|     ["a", 2],
 | |
|     ["b", 4]
 | |
|   ];
 | |
|   assertEquals(resultEntries, Object.entries(O));
 | |
|   assertEquals(resultEntries, Object.entries(O));
 | |
|   assertEquals(Object.entries(O), Object.keys(O).map(key => [key, O[key]]));
 | |
| 
 | |
|   assertTrue(Array.isArray(Object.entries({})));
 | |
|   assertEquals(0, Object.entries({}).length);
 | |
| }
 | |
| TestBasic();
 | |
| TestBasic(true);
 | |
| 
 | |
| 
 | |
| function TestToObject() {
 | |
|   assertThrows(function() { Object.entries(); }, TypeError);
 | |
|   assertThrows(function() { Object.entries(null); }, TypeError);
 | |
|   assertThrows(function() { Object.entries(void 0); }, TypeError);
 | |
| }
 | |
| TestToObject();
 | |
| 
 | |
| 
 | |
| function TestOrder(withWarmup) {
 | |
|   var O = {
 | |
|     a: 1,
 | |
|     [Symbol.iterator]: null
 | |
|   };
 | |
|   O[456] = 123;
 | |
|   Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN });
 | |
|   var priv = %CreatePrivateSymbol("Secret");
 | |
|   O[priv] = 56;
 | |
| 
 | |
|   var log = [];
 | |
|   var P = new Proxy(O, {
 | |
|     ownKeys(target) {
 | |
|       log.push("[[OwnPropertyKeys]]");
 | |
|       return Reflect.ownKeys(target);
 | |
|     },
 | |
|     get(target, name) {
 | |
|       log.push(`[[Get]](${JSON.stringify(name)})`);
 | |
|       return Reflect.get(target, name);
 | |
|     },
 | |
|     getOwnPropertyDescriptor(target, name) {
 | |
|       log.push(`[[GetOwnProperty]](${JSON.stringify(name)})`);
 | |
|       return Reflect.getOwnPropertyDescriptor(target, name);
 | |
|     },
 | |
|     set(target, name, value) {
 | |
|       assertUnreachable();
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   if (withWarmup) {
 | |
|     for (const key in P) {}
 | |
|   }
 | |
|   log = [];
 | |
| 
 | |
|   assertEquals([["456", 123], ["a", 1]], Object.entries(P));
 | |
|   assertEquals([
 | |
|     "[[OwnPropertyKeys]]",
 | |
|     "[[GetOwnProperty]](\"456\")",
 | |
|     "[[Get]](\"456\")",
 | |
|     "[[GetOwnProperty]](\"a\")",
 | |
|     "[[Get]](\"a\")",
 | |
|     "[[GetOwnProperty]](\"HIDDEN\")"
 | |
|   ], log);
 | |
| }
 | |
| TestOrder();
 | |
| TestOrder(true);
 | |
| 
 | |
| 
 | |
| function TestOrderWithDuplicates(withWarmup) {
 | |
|   var O = {
 | |
|     a: 1,
 | |
|     [Symbol.iterator]: null
 | |
|   };
 | |
|   O[456] = 123;
 | |
|   Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN });
 | |
|   var priv = %CreatePrivateSymbol("Secret");
 | |
|   O[priv] = 56;
 | |
| 
 | |
|   var log = [];
 | |
|   var P = new Proxy(O, {
 | |
|     ownKeys(target) {
 | |
|       log.push("[[OwnPropertyKeys]]");
 | |
|       return ["a", Symbol.iterator, "a", "456", "HIDDEN", "HIDDEN", "456"];
 | |
|     },
 | |
|     get(target, name) {
 | |
|       log.push(`[[Get]](${JSON.stringify(name)})`);
 | |
|       return Reflect.get(target, name);
 | |
|     },
 | |
|     getOwnPropertyDescriptor(target, name) {
 | |
|       log.push(`[[GetOwnProperty]](${JSON.stringify(name)})`);
 | |
|       return Reflect.getOwnPropertyDescriptor(target, name);
 | |
|     },
 | |
|     set(target, name, value) {
 | |
|       assertUnreachable();
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   if (withWarmup) {
 | |
|     for (const key in O) {};
 | |
|     try { for (const key in P) {} } catch {};
 | |
|   }
 | |
| 
 | |
|   assertThrows(() => Object.entries(P), TypeError);
 | |
| }
 | |
| TestOrderWithDuplicates();
 | |
| TestOrderWithDuplicates(true);
 | |
| 
 | |
| function TestDescriptorProperty() {
 | |
|   function f() {};
 | |
|   const o = {};
 | |
|   o.a = f;
 | |
| 
 | |
|   for (const key in o) {};
 | |
|   const entries = Object.entries(o);
 | |
|   assertEquals([['a', f]], entries);
 | |
| }
 | |
| TestDescriptorProperty();
 | |
| 
 | |
| function TestPropertyFilter(withWarmup) {
 | |
|   var object = { prop3: 30 };
 | |
|   object[2] = 40;
 | |
|   object["prop4"] = 50;
 | |
|   Object.defineProperty(object, "prop5", { value: 60, enumerable: true });
 | |
|   Object.defineProperty(object, "prop6", { value: 70, enumerable: false });
 | |
|   Object.defineProperty(object, "prop7", {
 | |
|       enumerable: true, get() { return 80; }});
 | |
|   var sym = Symbol("prop8");
 | |
|   object[sym] = 90;
 | |
| 
 | |
|   if (withWarmup) {
 | |
|     for (const key in object) {}
 | |
|   }
 | |
| 
 | |
|   values = Object.entries(object);
 | |
|   assertEquals(5, values.length);
 | |
|   assertEquals([
 | |
|     [ "2", 40 ],
 | |
|     [ "prop3", 30 ],
 | |
|     [ "prop4", 50 ],
 | |
|     [ "prop5", 60 ],
 | |
|     [ "prop7", 80 ]
 | |
|   ], values);
 | |
| }
 | |
| TestPropertyFilter();
 | |
| TestPropertyFilter(true);
 | |
| 
 | |
| function TestPropertyFilter2(withWarmup) {
 | |
|   var object = { };
 | |
|   Object.defineProperty(object, "prop1", { value: 10 });
 | |
|   Object.defineProperty(object, "prop2", { value: 20 });
 | |
|   object.prop3 = 30;
 | |
| 
 | |
|   if (withWarmup) {
 | |
|     for (const key in object) {}
 | |
|   }
 | |
| 
 | |
|   values = Object.entries(object);
 | |
|   assertEquals(1, values.length);
 | |
|   assertEquals([
 | |
|     [ "prop3", 30 ],
 | |
|   ], values);
 | |
| }
 | |
| TestPropertyFilter2();
 | |
| TestPropertyFilter2(true);
 | |
| 
 | |
| function TestWithProxy(withWarmup) {
 | |
|   var obj1 = {prop1:10};
 | |
|   var proxy1 = new Proxy(obj1, { });
 | |
|   if (withWarmup) {
 | |
|     for (const key in proxy1) {}
 | |
|   }
 | |
|   assertEquals([ [ "prop1", 10 ] ], Object.entries(proxy1));
 | |
| 
 | |
|   var obj2 = {};
 | |
|   Object.defineProperty(obj2, "prop2", { value: 20, enumerable: true });
 | |
|   Object.defineProperty(obj2, "prop3", {
 | |
|       get() { return 30; }, enumerable: true });
 | |
|   var proxy2 = new Proxy(obj2, {
 | |
|     getOwnPropertyDescriptor(target, name) {
 | |
|       return Reflect.getOwnPropertyDescriptor(target, name);
 | |
|     }
 | |
|   });
 | |
|   if (withWarmup) {
 | |
|     for (const key in proxy2) {}
 | |
|   }
 | |
|   assertEquals([ [ "prop2", 20 ], [ "prop3", 30 ] ], Object.entries(proxy2));
 | |
| 
 | |
|   var obj3 = {};
 | |
|   var count = 0;
 | |
|   var proxy3 = new Proxy(obj3, {
 | |
|     get(target, property, receiver) {
 | |
|       return count++ * 5;
 | |
|     },
 | |
|     getOwnPropertyDescriptor(target, property) {
 | |
|       return { configurable: true, enumerable: true };
 | |
|     },
 | |
|     ownKeys(target) {
 | |
|       return [ "prop0", "prop1", Symbol("prop2"), Symbol("prop5") ];
 | |
|     }
 | |
|   });
 | |
|   if (withWarmup) {
 | |
|     for (const key in proxy3) {}
 | |
|   }
 | |
|   assertEquals([ [ "prop0", 0 ], [ "prop1", 5 ] ], Object.entries(proxy3));
 | |
| }
 | |
| TestWithProxy();
 | |
| TestWithProxy(true);
 | |
| 
 | |
| 
 | |
| function TestMutateDuringEnumeration(withWarmup) {
 | |
|   var aDeletesB = {
 | |
|     get a() {
 | |
|       delete this.b;
 | |
|       return 1;
 | |
|     },
 | |
|     b: 2
 | |
|   };
 | |
|   if (withWarmup) {
 | |
|     for (const key in aDeletesB) {}
 | |
|   }
 | |
|   assertEquals([ [ "a", 1 ] ], Object.entries(aDeletesB));
 | |
| 
 | |
|   var aRemovesB = {
 | |
|     get a() {
 | |
|       Object.defineProperty(this, "b", { enumerable: false });
 | |
|       return 1;
 | |
|     },
 | |
|     b: 2
 | |
|   };
 | |
|   if (withWarmup) {
 | |
|     for (const key in aRemovesB) {}
 | |
|   }
 | |
|   assertEquals([ [ "a", 1 ] ], Object.entries(aRemovesB));
 | |
| 
 | |
|   var aAddsB = { get a() { this.b = 2; return 1; } };
 | |
|   if (withWarmup) {
 | |
|     for (const key in aAddsB) {}
 | |
|   }
 | |
|   assertEquals([ [ "a", 1 ] ], Object.entries(aAddsB));
 | |
| 
 | |
|   var aMakesBEnumerable = {};
 | |
|   Object.defineProperty(aMakesBEnumerable, "a", {
 | |
|     get() {
 | |
|       Object.defineProperty(this, "b", { enumerable: true });
 | |
|       return 1;
 | |
|     },
 | |
|     enumerable: true
 | |
|   });
 | |
|   Object.defineProperty(aMakesBEnumerable, "b", {
 | |
|       value: 2, configurable:true, enumerable: false });
 | |
|   if (withWarmup) {
 | |
|     for (const key in aMakesBEnumerable) {}
 | |
|   }
 | |
|   assertEquals([ [ "a", 1 ], [ "b", 2 ] ], Object.entries(aMakesBEnumerable));
 | |
| }
 | |
| TestMutateDuringEnumeration();
 | |
| TestMutateDuringEnumeration(true);
 | |
| 
 | |
| 
 | |
| function TestElementKinds(withWarmup) {
 | |
|   var O1 = { name: "1" }, O2 = { name: "2" }, O3 = { name: "3" };
 | |
|   var PI = 3.141592653589793;
 | |
|   var E = 2.718281828459045;
 | |
|   function fastSloppyArguments(a, b, c) {
 | |
|     delete arguments[0];
 | |
|     arguments[0] = a;
 | |
|     return arguments;
 | |
|   }
 | |
| 
 | |
|   function slowSloppyArguments(a, b, c) {
 | |
|     delete arguments[0];
 | |
|     arguments[0] = a;
 | |
|     Object.defineProperties(arguments, {
 | |
|       0: {
 | |
|         enumerable: true,
 | |
|         value: a
 | |
|       },
 | |
|       9999: {
 | |
|         enumerable: false,
 | |
|         value: "Y"
 | |
|       }
 | |
|     });
 | |
|     arguments[10000] = "X";
 | |
|     return arguments;
 | |
|   }
 | |
| 
 | |
|   var element_kinds = {
 | |
|     PACKED_SMI_ELEMENTS: [ [1, 2, 3], [ ["0", 1], ["1", 2], ["2", 3] ] ],
 | |
|     HOLEY_SMI_ELEMENTS: [ [, , 3], [ ["2", 3] ] ],
 | |
|     PACKED_ELEMENTS: [ [O1, O2, O3], [ ["0", O1], ["1", O2], ["2", O3] ] ],
 | |
|     HOLEY_ELEMENTS: [ [, , O3], [ ["2", O3] ] ],
 | |
|     PACKED_DOUBLE_ELEMENTS: [ [E, NaN, PI], [ ["0", E], ["1", NaN], ["2", PI] ] ],
 | |
|     HOLEY_DOUBLE_ELEMENTS: [ [, , NaN], [ ["2", NaN] ] ],
 | |
| 
 | |
|     DICTIONARY_ELEMENTS: [ Object.defineProperties({ 10000: "world" }, {
 | |
|        100: { enumerable: true, value: "hello", configurable: true},
 | |
|         99: { enumerable: false, value: "nope", configurable: true}
 | |
|       }), [ ["100", "hello"], ["10000", "world" ] ] ],
 | |
|     FAST_SLOPPY_ARGUMENTS_ELEMENTS: [
 | |
|         fastSloppyArguments("a", "b", "c"),
 | |
|         [ ["0", "a"], ["1", "b"], ["2", "c"] ] ],
 | |
|     SLOW_SLOPPY_ARGUMENTS_ELEMENTS: [
 | |
|         slowSloppyArguments("a", "b", "c"),
 | |
|         [ ["0", "a"], ["1", "b"], ["2", "c"], ["10000", "X"] ] ],
 | |
| 
 | |
|     FAST_STRING_WRAPPER_ELEMENTS: [ new String("str"),
 | |
|         [ ["0", "s"], ["1", "t"], ["2", "r"]] ],
 | |
|     SLOW_STRING_WRAPPER_ELEMENTS: [
 | |
|         Object.defineProperties(new String("str"), {
 | |
|           10000: { enumerable: false, value: "X", configurable: true},
 | |
|           9999: { enumerable: true, value: "Y", configurable: true}
 | |
|         }), [["0", "s"], ["1", "t"], ["2", "r"], ["9999", "Y"]] ],
 | |
|   };
 | |
| 
 | |
|   if (withWarmup) {
 | |
|     for (const key in element_kinds) {}
 | |
|   }
 | |
|   for (let [kind, [object, expected]] of Object.entries(element_kinds)) {
 | |
|     if (withWarmup) {
 | |
|       for (const key in object) {}
 | |
|     }
 | |
|     let result1 = Object.entries(object);
 | |
|     %HeapObjectVerify(object);
 | |
|     %HeapObjectVerify(result1);
 | |
|     assertEquals(expected, result1, `fast Object.entries() with ${kind}`);
 | |
| 
 | |
|     let proxy = new Proxy(object, {});
 | |
|     if (withWarmup) {
 | |
|       for (const key in proxy) {}
 | |
|     }
 | |
|     let result2 = Object.entries(proxy);
 | |
|     %HeapObjectVerify(result2);
 | |
|     assertEquals(result1, result2, `slow Object.entries() with ${kind}`);
 | |
|   }
 | |
| 
 | |
|   function makeFastElements(array) {
 | |
|     // Remove all possible getters.
 | |
|     for (let k of Object.getOwnPropertyNames(this)) {
 | |
|       if (k == "length") continue;
 | |
|       delete this[k];
 | |
|     }
 | |
|     // Make the array large enough to trigger re-checking for compaction.
 | |
|     this[1000] = 1;
 | |
|     // Make the elements fast again.
 | |
|     Array.prototype.unshift.call(this, 1.1);
 | |
|   }
 | |
| 
 | |
|   // Test that changing the elements kind is supported.
 | |
|   for (let [kind, [object, expected]] of Object.entries(element_kinds)) {
 | |
|     if (kind == "FAST_STRING_WRAPPER_ELEMENTS") break;
 | |
|     object.__defineGetter__(1, makeFastElements);
 | |
|     if (withWarmup) {
 | |
|       for (const key in object) {}
 | |
|     }
 | |
|     let result1 = Object.entries(object).toString();
 | |
|     %HeapObjectVerify(object);
 | |
|     %HeapObjectVerify(result1);
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| TestElementKinds();
 | |
| TestElementKinds(true);
 |