Optimize hasOwnProperty for sealed, frozen objects.

Extend CodeStubAssembler::TryLookupElement() to handle frozen/sealed elements.
Also add some tests.

~2x perf improvement in micro-benchmark ObjectFreeze
Before:
TaggedTemplate
TaggedTemplate-Numbers(Score): 2.43
HasOwnProperty
HasOwnProperty-Numbers(Score): 2.94

After:
TaggedTemplate
TaggedTemplate-Numbers(Score): 4.77
HasOwnProperty
HasOwnProperty-Numbers(Score): 4.68

Bug: v8:6831
Change-Id: I6ce057fd812cd6a01e627125a51eefa439710274
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1650633
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62096}
diff --git a/src/codegen/code-stub-assembler.cc b/src/codegen/code-stub-assembler.cc
index 35ab78c..2454d9d 100644
--- a/src/codegen/code-stub-assembler.cc
+++ b/src/codegen/code-stub-assembler.cc
@@ -9666,8 +9666,9 @@
   // clang-format off
   int32_t values[] = {
       // Handled by {if_isobjectorsmi}.
-      PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_ELEMENTS,
-          HOLEY_ELEMENTS,
+      PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_ELEMENTS, HOLEY_ELEMENTS,
+      PACKED_SEALED_ELEMENTS, HOLEY_SEALED_ELEMENTS, PACKED_FROZEN_ELEMENTS,
+      HOLEY_FROZEN_ELEMENTS,
       // Handled by {if_isdouble}.
       PACKED_DOUBLE_ELEMENTS, HOLEY_DOUBLE_ELEMENTS,
       // Handled by {if_isdictionary}.
@@ -9693,7 +9694,8 @@
   };
   Label* labels[] = {
       &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi,
-          &if_isobjectorsmi,
+      &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi,
+      &if_isobjectorsmi, &if_isobjectorsmi,
       &if_isdouble, &if_isdouble,
       &if_isdictionary,
       &if_isfaststringwrapper,
diff --git a/test/mjsunit/has-own-property.js b/test/mjsunit/has-own-property.js
index 5ff8db5..b009b7d 100644
--- a/test/mjsunit/has-own-property.js
+++ b/test/mjsunit/has-own-property.js
@@ -25,6 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Normal objects.
 // Check for objects.
 assertTrue({x:12}.hasOwnProperty('x'));
 assertFalse({x:12}.hasOwnProperty('y'));
@@ -36,3 +37,135 @@
 // Check for numbers.
 assertFalse((123).hasOwnProperty('length'));
 assertFalse(Object.prototype.hasOwnProperty.call(123, 'length'));
+
+// Frozen object.
+// Check for objects.
+assertTrue(Object.freeze({x:12}).hasOwnProperty('x'));
+assertFalse(Object.freeze({x:12}).hasOwnProperty('y'));
+
+// Check for strings.
+assertTrue(Object.freeze('').hasOwnProperty('length'));
+assertTrue(Object.prototype.hasOwnProperty.call(Object.freeze(''), 'length'));
+
+// Check for numbers.
+assertFalse(Object.freeze(123).hasOwnProperty('length'));
+assertFalse(Object.prototype.hasOwnProperty.call(Object.freeze(123), 'length'));
+
+// Direct vs. inherited properties.
+var o = ['exist'];
+Object.freeze(o);
+assertTrue(o.hasOwnProperty('0'));
+assertFalse(o.hasOwnProperty('toString'));
+assertFalse(o.hasOwnProperty('hasOwnProperty'));
+
+// Using hasOwnProperty as a property name.
+var foo = ['a'];
+foo.hasOwnProperty = function() { return false; };
+Object.freeze(foo);
+assertFalse(foo.hasOwnProperty('0')); // always returns false.
+
+// Use another Object's hasOwnProperty
+// and call it with 'this' set to foo.
+assertTrue(({}).hasOwnProperty.call(foo, '0'));
+
+// It's also possible to use the hasOwnProperty property
+// from the Object prototype for this purpose.
+assertTrue(Object.prototype.hasOwnProperty.call(foo, '0'));
+
+// Check for null or undefined
+var o = Object.freeze([, null, undefined, 'a', 1, Symbol('2')]);
+assertFalse(o.hasOwnProperty('0')); // hole
+assertTrue(o.hasOwnProperty('1'));
+assertTrue(o.hasOwnProperty('2'));
+assertTrue(o.hasOwnProperty('3'));
+assertTrue(o.hasOwnProperty('4'));
+assertTrue(o.hasOwnProperty('5'));
+assertFalse(o.hasOwnProperty('6')); // out of bounds
+
+// Sealed object.
+// Check for objects.
+assertTrue(Object.seal({x:12}).hasOwnProperty('x'));
+assertFalse(Object.seal({x:12}).hasOwnProperty('y'));
+
+// Check for strings.
+assertTrue(Object.seal('').hasOwnProperty('length'));
+assertTrue(Object.prototype.hasOwnProperty.call(Object.seal(''), 'length'));
+
+// Check for numbers.
+assertFalse(Object.seal(123).hasOwnProperty('length'));
+assertFalse(Object.prototype.hasOwnProperty.call(Object.seal(123), 'length'));
+
+// Direct vs. inherited properties.
+var o = ['exist'];
+Object.seal(o);
+assertTrue(o.hasOwnProperty('0'));
+assertFalse(o.hasOwnProperty('toString'));
+assertFalse(o.hasOwnProperty('hasOwnProperty'));
+
+// Using hasOwnProperty as a property name.
+var foo = ['a'];
+foo.hasOwnProperty = function() { return false; };
+Object.seal(foo);
+assertFalse(foo.hasOwnProperty('0')); // always returns false.
+
+// Use another Object's hasOwnProperty
+// and call it with 'this' set to foo.
+assertTrue(({}).hasOwnProperty.call(foo, '0'));
+
+// It's also possible to use the hasOwnProperty property
+// from the Object prototype for this purpose.
+assertTrue(Object.prototype.hasOwnProperty.call(foo, '0'));
+
+// Check for null or undefined
+var o = Object.seal([, null, undefined, 'a', 1, Symbol('2')]);
+assertFalse(o.hasOwnProperty('0')); // hole.
+assertTrue(o.hasOwnProperty('1'));
+assertTrue(o.hasOwnProperty('2'));
+assertTrue(o.hasOwnProperty('3'));
+assertTrue(o.hasOwnProperty('4'));
+assertTrue(o.hasOwnProperty('5'));
+assertFalse(o.hasOwnProperty('6')); // out of bounds.
+
+// Non-extensible object.
+// Check for objects.
+assertTrue(Object.preventExtensions({x:12}).hasOwnProperty('x'));
+assertFalse(Object.preventExtensions({x:12}).hasOwnProperty('y'));
+
+// Check for strings.
+assertTrue(Object.preventExtensions('').hasOwnProperty('length'));
+assertTrue(Object.prototype.hasOwnProperty.call(Object.preventExtensions(''), 'length'));
+
+// Check for numbers.
+assertFalse(Object.preventExtensions(123).hasOwnProperty('length'));
+assertFalse(Object.prototype.hasOwnProperty.call(Object.preventExtensions(123), 'length'));
+
+// Direct vs. inherited properties.
+var o = ['exist'];
+Object.preventExtensions(o);
+assertTrue(o.hasOwnProperty('0'));
+assertFalse(o.hasOwnProperty('toString'));
+assertFalse(o.hasOwnProperty('hasOwnProperty'));
+
+// Using hasOwnProperty as a property name.
+var foo = ['a'];
+foo.hasOwnProperty = function() { return false; };
+Object.preventExtensions(foo);
+assertFalse(foo.hasOwnProperty('0')); // always returns false.
+
+// Use another Object's hasOwnProperty
+// and call it with 'this' set to foo.
+assertTrue(({}).hasOwnProperty.call(foo, '0'));
+
+// It's also possible to use the hasOwnProperty property
+// from the Object prototype for this purpose.
+assertTrue(Object.prototype.hasOwnProperty.call(foo, '0'));
+
+// Check for null or undefined.
+var o = Object.preventExtensions([, null, undefined, 'a', 1, Symbol('2')]);
+assertFalse(o.hasOwnProperty('0')); // hole.
+assertTrue(o.hasOwnProperty('1'));
+assertTrue(o.hasOwnProperty('2'));
+assertTrue(o.hasOwnProperty('3'));
+assertTrue(o.hasOwnProperty('4'));
+assertTrue(o.hasOwnProperty('5'));
+assertFalse(o.hasOwnProperty('6')); // out of bounds.