| // Copyright 2019 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 testIn(obj, key) { |
| return key in obj; |
| } |
| |
| function expectTrue(obj, key) { |
| assertTrue(testIn(obj, key)); |
| } |
| |
| function expectFalse(obj, key) { |
| assertFalse(testIn(obj, key)); |
| } |
| |
| var tests = { |
| TestMonomorphicPackedSMIArray: function() { |
| var a = [0, 1, 2]; |
| expectTrue(a, 0); |
| expectTrue(a, 1); |
| expectTrue(a, 2); |
| expectFalse(a, 3); |
| }, |
| |
| TestMonomorphicPackedArrayPrototypeProperty: function() |
| { |
| var a = [0, 1, 2]; |
| |
| expectTrue(a, 0); |
| expectTrue(a, 1); |
| expectFalse(a, 3); |
| Array.prototype[3] = 3; |
| expectTrue(a, 3); |
| |
| // ensure the prototype change doesn't affect later tests |
| delete Array.prototype[3]; |
| assertFalse((3 in Array.prototype)); |
| expectFalse(a, 3); |
| }, |
| |
| TestMonomorphicPackedDoubleArray: function() { |
| var a = [0.0, 1.1, 2.2]; |
| expectTrue(a, 0); |
| expectTrue(a, 1); |
| expectTrue(a, 2); |
| expectFalse(a, 3); |
| }, |
| |
| TestMonomorphicPackedArray: function() { |
| var a = ["A", "B", {}]; |
| expectTrue(a, 0); |
| expectTrue(a, 1); |
| expectTrue(a, 2); |
| expectFalse(a, 3); |
| }, |
| |
| TestMonomorphicHoleyArray: function() { |
| var a = [0, 1, 2]; |
| a[4] = 4; |
| |
| expectTrue(a, 0); |
| expectTrue(a, 1); |
| expectTrue(a, 2); |
| expectFalse(a, 3); |
| expectTrue(a, 4); |
| }, |
| |
| TestMonomorphicTypedArray: function() { |
| var a = new Int32Array(3); |
| expectTrue(a, 0); |
| expectTrue(a, 1); |
| expectTrue(a, 2); |
| expectFalse(a, 3); |
| expectFalse(a, 4); |
| }, |
| |
| TestPolymorphicPackedArrays: function() { |
| var a = [0, 1, 2]; |
| var b = [0.0, 1.1, 2.2]; |
| var c = ["A", "B", {}]; |
| expectTrue(c, 0); |
| expectTrue(b, 1); |
| expectTrue(a, 2); |
| expectTrue(c, 1); |
| expectTrue(b, 2); |
| expectTrue(a, 0); |
| expectFalse(c, 3); |
| expectFalse(b, 4); |
| expectFalse(a, 5); |
| }, |
| |
| TestPolymorphicMixedArrays: function() { |
| var a = new Array(3); // holey SMI |
| var b = [0.0,1.1,2.2]; // packed double |
| var c = new Int8Array(3); // typed array |
| |
| expectFalse(a, 0); |
| expectTrue(b, 1); |
| expectTrue(c, 2); |
| expectFalse(a, 1); |
| expectTrue(b, 2); |
| expectTrue(c, 0); |
| expectFalse(a, 3); |
| expectFalse(b, 4); |
| expectFalse(c, 5); |
| }, |
| |
| TestMegamorphicArrays: function() { |
| var a = [0,1,2,3] // packed SMI |
| var b = new Array(3); // holey SMI |
| var c = [0.0,1.1,2.2]; // packed double |
| var d = ['a', 'b', 'c'] // packed |
| var e = new Int8Array(3); // typed array |
| var f = new Uint8Array(3); // typed array |
| var g = new Int32Array(3); // typed array |
| |
| expectTrue(a, 0); |
| expectFalse(b, 1); |
| expectTrue(c, 2); |
| expectFalse(d, 3); |
| expectFalse(e, 4); |
| expectFalse(f, 5); |
| expectFalse(g, 6); |
| expectFalse(a, 5); |
| expectFalse(b, 4); |
| expectFalse(c, 3); |
| expectTrue(d, 2); |
| expectTrue(e, 1); |
| expectTrue(f, 0); |
| expectTrue(g, 0); |
| }, |
| |
| TestMonomorphicObject: function() { |
| var a = { a: "A", b: "B" }; |
| |
| expectTrue(a, 'a'); |
| expectTrue(a, 'a'); |
| expectTrue(a, 'a'); |
| }, |
| |
| TestMonomorphicProxyHasPropertyNoTrap: function() { |
| var a = new Proxy({a: 'A'}, {}); |
| |
| expectTrue(a, 'a'); |
| expectTrue(a, 'a'); |
| expectTrue(a, 'a'); |
| }, |
| |
| TestMonomorphicProxyNoPropertyNoTrap: function() { |
| var a = new Proxy({}, {}); |
| |
| expectFalse(a, 'a'); |
| expectFalse(a, 'a'); |
| expectFalse(a, 'a'); |
| }, |
| |
| TestMonomorphicProxyHasPropertyHasTrap: function() { |
| var a = new Proxy({a: 'A'}, { has: function() {return false;}}); |
| |
| expectFalse(a, 'a'); |
| expectFalse(a, 'a'); |
| expectFalse(a, 'a'); |
| }, |
| |
| TestMonomorphicProxyNoPropertyHasTrap: function() { |
| var a = new Proxy({}, { has: function() { return true; }}); |
| |
| expectTrue(a, 'a'); |
| expectTrue(a, 'a'); |
| expectTrue(a, 'a'); |
| }, |
| |
| TestMonomorphicObjectPrototype: function() { |
| var a = { b: "B" }; |
| |
| expectFalse(a, 'a'); |
| expectFalse(a, 'a'); |
| expectFalse(a, 'a'); |
| Object.prototype.a = 'A'; |
| expectTrue(a, 'a'); |
| delete Object.prototype.a; |
| assertFalse((a in Object.prototype)); |
| expectFalse(a, 'a'); |
| }, |
| |
| TestPolymorphicObject: function() { |
| var a = { a: "A" }; |
| var b = { a: "A", b: "B" }; |
| var c = { b: "B", c: "C" }; |
| |
| expectTrue(a, 'a'); |
| expectTrue(a, 'a'); |
| expectTrue(b, 'a'); |
| expectFalse(c, 'a'); |
| expectTrue(a, 'a'); |
| expectTrue(b, 'a'); |
| expectFalse(c, 'a'); |
| }, |
| |
| TestMegamorphicObject: function() { |
| var a = { a: "A" }; |
| var b = { a: "A", b: "B" }; |
| var c = { b: "B", c: "C" }; |
| var d = { b: "A", a: "B" }; |
| var e = { e: "E", a: "A" }; |
| var f = { f: "F", b: "B", c: "C" }; |
| |
| expectTrue(a, 'a'); |
| expectTrue(a, 'a'); |
| expectTrue(b, 'a'); |
| expectFalse(c, 'a'); |
| expectTrue(d, 'a'); |
| expectTrue(e, 'a'); |
| expectFalse(f, 'a'); |
| expectTrue(a, 'a'); |
| expectTrue(b, 'a'); |
| expectFalse(c, 'a'); |
| expectTrue(d, 'a'); |
| expectTrue(e, 'a'); |
| expectFalse(f, 'a'); |
| }, |
| |
| TestPolymorphicKeys: function() { |
| var a = { a: "A", b: "B" }; |
| |
| expectTrue(a, 'a'); |
| expectTrue(a, 'b'); |
| expectFalse(a, 'c'); |
| expectTrue(a, 'a'); |
| expectTrue(a, 'b'); |
| expectFalse(a, 'c'); |
| expectTrue(a, 'a'); |
| expectTrue(a, 'b'); |
| expectFalse(a, 'c'); |
| }, |
| |
| TestPolymorphicMixed: function() { |
| var a = { a: "A" }; |
| var b = new Proxy({}, {}); |
| var c = new Int32Array(3); |
| |
| expectTrue(a, 'a'); |
| expectTrue(a, 'a'); |
| expectFalse(b, 'a'); |
| expectFalse(c, 'a'); |
| expectTrue(a, 'a'); |
| expectFalse(b, 'a'); |
| expectFalse(c, 'a'); |
| }, |
| }; |
| |
| for (test in tests) { |
| %DeoptimizeFunction(testIn); |
| %ClearFunctionFeedback(testIn); |
| %PrepareFunctionForOptimization(testIn); |
| tests[test](); |
| %OptimizeFunctionOnNextCall(testIn); |
| tests[test](); |
| } |
| |
| // test function prototypes. |
| (function() { |
| var o = function() {}; |
| |
| var proto = function() { |
| assertTrue("prototype" in o); |
| o.prototype; |
| }; |
| |
| %PrepareFunctionForOptimization(proto); |
| proto(); |
| proto(); |
| %OptimizeFunctionOnNextCall(proto); |
| proto(); |
| })(); |
| |
| // `in` is not allowed on string |
| (function() { |
| function test() { |
| 0 in "string" |
| }; |
| |
| %PrepareFunctionForOptimization(test); |
| assertThrows(test, TypeError); |
| assertThrows(test, TypeError); |
| %OptimizeFunctionOnNextCall(test); |
| assertThrows(test, TypeError); |
| })(); |
| |
| // `in` is allowed on `this` even when `this` is a string |
| (function() { |
| function test() { |
| assertTrue("length" in this); |
| }; |
| |
| %PrepareFunctionForOptimization(test); |
| test.call(""); |
| test.call(""); |
| %OptimizeFunctionOnNextCall(test); |
| test.call(""); |
| })(); |
| |
| (function() { |
| var index = 0; |
| function test(i) { |
| return index in arguments; |
| }; |
| |
| %PrepareFunctionForOptimization(test); |
| assertFalse(test()) |
| assertFalse(test()) |
| assertTrue(test(0)); |
| assertTrue(test(0,1)); |
| |
| index = 2; |
| assertFalse(test()) |
| assertFalse(test(0)); |
| assertFalse(test(0,1)); |
| assertTrue(test(0,1,2)); |
| |
| %OptimizeFunctionOnNextCall(test); |
| assertFalse(test(0,1)); |
| assertTrue(test(0,1,2)); |
| })(); |
| |
| (function() { |
| function test(a) { |
| arguments[3] = 1; |
| return 2 in arguments; |
| }; |
| |
| %PrepareFunctionForOptimization(test); |
| assertFalse(test(1)); |
| assertFalse(test(1)); |
| %OptimizeFunctionOnNextCall(test); |
| assertFalse(test(1)); |
| })(); |
| |
| (function() { |
| function test(o, k) { |
| try { |
| k in o; |
| } catch (e) { |
| return false; |
| } |
| return true; |
| } |
| %PrepareFunctionForOptimization(test); |
| |
| var str = "string"; |
| // this will place slow_stub in the IC for strings. |
| assertFalse(test(str, "length")); |
| assertFalse(test(str, "length")); |
| |
| // this turns the cache polymorphic, and causes generats LoadElement |
| // handlers for everything in the cache. This test ensures that |
| // KeyedLoadIC::LoadElementHandler can handle seeing string maps. |
| var ary = [0,1,2,3]; |
| assertTrue(test(ary, 1)); |
| assertTrue(test(ary, 1)); |
| |
| assertFalse(test(str, 0)); |
| assertFalse(test(str, 0)); |
| %OptimizeFunctionOnNextCall(test); |
| assertFalse(test(str, 0)); |
| })(); |
| |
| (function() { |
| function test(o, k) { |
| try { |
| k in o; |
| } catch (e) { |
| return false; |
| } |
| return true; |
| } |
| %PrepareFunctionForOptimization(test); |
| |
| var str = "string"; |
| assertFalse(test(str, "length")); |
| assertFalse(test(str, "length")); |
| %OptimizeFunctionOnNextCall(test); |
| assertFalse(test(str, "length")); |
| })(); |
| |
| (function() { |
| function test(o, k) { |
| try { |
| k in o; |
| } catch (e) { |
| return false; |
| } |
| return true; |
| } |
| %PrepareFunctionForOptimization(test); |
| |
| var str = "string"; |
| assertFalse(test(str, 0)); |
| assertFalse(test(str, 0)); |
| %OptimizeFunctionOnNextCall(test); |
| assertFalse(test(str, 0)); |
| })(); |
| |
| (function() { |
| function test(o, k) { |
| try { |
| k in o; |
| } catch (e) { |
| return false; |
| } |
| return true; |
| } |
| %PrepareFunctionForOptimization(test); |
| |
| var ary = [0, 1, 2, '3']; |
| function testArray(ary) { |
| assertTrue(test(ary, 1)); |
| assertTrue(test(ary, 1)); |
| } |
| testArray(ary); |
| // Packed |
| // Non-extensible |
| var b = Object.preventExtensions(ary); |
| testArray(b); |
| |
| // Sealed |
| var c = Object.seal(ary); |
| testArray(c); |
| |
| // Frozen |
| var d = Object.freeze(ary); |
| testArray(d); |
| |
| // Holey |
| var ary = [, 0, 1, 2, '3']; |
| // Non-extensible |
| var b = Object.preventExtensions(ary); |
| testArray(b); |
| |
| // Sealed |
| var c = Object.seal(ary); |
| testArray(c); |
| |
| // Frozen |
| var d = Object.freeze(ary); |
| testArray(d); |
| |
| var str = "string"; |
| assertFalse(test(str, 0)); |
| assertFalse(test(str, 0)); |
| %OptimizeFunctionOnNextCall(test); |
| assertFalse(test(str, 0)); |
| })(); |
| |
| const heap_constant_ary = [0,1,2,'3']; |
| |
| function testHeapConstantArray(heap_constant_ary) { |
| |
| function test() { |
| return 1 in heap_constant_ary; |
| } |
| %PrepareFunctionForOptimization(test); |
| |
| assertTrue(test()); |
| assertTrue(test()); |
| %OptimizeFunctionOnNextCall(test); |
| assertTrue(test()); |
| |
| heap_constant_ary[1] = 2; |
| assertTrue(test()); |
| %PrepareFunctionForOptimization(test); |
| %OptimizeFunctionOnNextCall(test); |
| assertTrue(test()); |
| } |
| testHeapConstantArray(heap_constant_ary); |
| |
| // Packed |
| // Non-extensible |
| var b = Object.preventExtensions(heap_constant_ary); |
| testHeapConstantArray(b); |
| |
| // Sealed |
| var c = Object.seal(heap_constant_ary); |
| testHeapConstantArray(c); |
| |
| // Frozen |
| var d = Object.freeze(heap_constant_ary); |
| testHeapConstantArray(d); |
| |
| // Holey |
| const holey_heap_constant_ary = [,0,1,2,'3']; |
| // Non-extensible |
| var b = Object.preventExtensions(holey_heap_constant_ary); |
| testHeapConstantArray(b); |
| |
| // Sealed |
| var c = Object.seal(holey_heap_constant_ary); |
| testHeapConstantArray(c); |
| |
| // Frozen |
| var d = Object.freeze(holey_heap_constant_ary); |
| testHeapConstantArray(d); |