|  | // 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); |