[class] fix super access in private methods

This patch stores the home objects in private methods that
access super properties.

Bug: v8:8330
Change-Id: I2507fda0bd70183f02d162ec50a5be76c248f0ff
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1724900
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Sathya Gunasekaran  <gsathya@chromium.org>
Commit-Queue: Joyee Cheung <joyee@igalia.com>
Cr-Commit-Position: refs/heads/master@{#63113}
diff --git a/src/ast/ast.h b/src/ast/ast.h
index eda618e..c3eb139 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -2424,6 +2424,11 @@
     return private_or_computed_name_var_;
   }
 
+  bool NeedsHomeObjectOnClassPrototype() const {
+    return is_private() && kind_ == METHOD &&
+           FunctionLiteral::NeedsHomeObject(value_);
+  }
+
  private:
   friend class AstNodeFactory;
 
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
index 3091111..7202ffe 100644
--- a/src/interpreter/bytecode-generator.cc
+++ b/src/interpreter/bytecode-generator.cc
@@ -2124,6 +2124,22 @@
         .CallRuntime(Runtime::kCreatePrivateNameSymbol, brand);
     BuildVariableAssignment(expr->scope()->brand(), Token::INIT,
                             HoleCheckMode::kElided);
+
+    // Store the home object for any private methods or accessors that need
+    // them. We do this here once the prototype and brand symbol has
+    // been created.
+    for (int i = 0; i < expr->properties()->length(); i++) {
+      RegisterAllocationScope register_scope(this);
+      ClassLiteral::Property* property = expr->properties()->at(i);
+      // TODO(joyee): do the same for private accessors when they are
+      // implemented.
+      if (property->NeedsHomeObjectOnClassPrototype()) {
+        Register func = register_allocator()->NewRegister();
+        BuildVariableLoad(property->private_name_var(), HoleCheckMode::kElided);
+        builder()->StoreAccumulatorInRegister(func);
+        VisitSetHomeObject(func, prototype, property);
+      }
+    }
   }
 
   if (expr->instance_members_initializer_function() != nullptr) {
diff --git a/test/cctest/interpreter/bytecode_expectations/PrivateAccessors.golden b/test/cctest/interpreter/bytecode_expectations/PrivateAccessors.golden
new file mode 100644
index 0000000..3038f0b
--- /dev/null
+++ b/test/cctest/interpreter/bytecode_expectations/PrivateAccessors.golden
@@ -0,0 +1,208 @@
+#
+# Autogenerated by generate-bytecode-expectations.
+#
+
+---
+wrap: yes
+private methods: yes
+
+---
+snippet: "
+  {
+    class A {
+      get #a() { return 1; }
+      set #a(val) { }
+    }
+  }
+"
+frame size: 7
+parameter count: 1
+bytecode array length: 49
+bytecodes: [
+  /*   30 E> */ B(StackCheck),
+                B(CreateBlockContext), U8(0),
+                B(PushContext), R(2),
+                B(LdaTheHole),
+                B(Star), R(6),
+                B(CreateClosure), U8(2), U8(0), U8(2),
+                B(Star), R(3),
+                B(LdaConstant), U8(1),
+                B(Star), R(4),
+                B(Mov), R(3), R(5),
+                B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
+                B(Star), R(4),
+                B(Mov), R(5), R(1),
+                B(LdaConstant), U8(3),
+                B(Star), R(5),
+                B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
+                B(StaCurrentContextSlot), U8(5),
+                B(PopContext), R(2),
+                B(Mov), R(1), R(0),
+                B(LdaUndefined),
+  /*  101 S> */ B(Return),
+]
+constant pool: [
+  SCOPE_INFO_TYPE,
+  FIXED_ARRAY_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
+]
+handlers: [
+]
+
+---
+snippet: "
+  {
+    class B {
+      get #b() { return 1; }
+    }
+  }
+"
+frame size: 7
+parameter count: 1
+bytecode array length: 49
+bytecodes: [
+  /*   30 E> */ B(StackCheck),
+                B(CreateBlockContext), U8(0),
+                B(PushContext), R(2),
+                B(LdaTheHole),
+                B(Star), R(6),
+                B(CreateClosure), U8(2), U8(0), U8(2),
+                B(Star), R(3),
+                B(LdaConstant), U8(1),
+                B(Star), R(4),
+                B(Mov), R(3), R(5),
+                B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
+                B(Star), R(4),
+                B(Mov), R(5), R(1),
+                B(LdaConstant), U8(3),
+                B(Star), R(5),
+                B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
+                B(StaCurrentContextSlot), U8(5),
+                B(PopContext), R(2),
+                B(Mov), R(1), R(0),
+                B(LdaUndefined),
+  /*   81 S> */ B(Return),
+]
+constant pool: [
+  SCOPE_INFO_TYPE,
+  FIXED_ARRAY_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  ONE_BYTE_INTERNALIZED_STRING_TYPE ["B"],
+]
+handlers: [
+]
+
+---
+snippet: "
+  {
+    class C {
+      set #c(val) { }
+    }
+  }
+"
+frame size: 7
+parameter count: 1
+bytecode array length: 49
+bytecodes: [
+  /*   30 E> */ B(StackCheck),
+                B(CreateBlockContext), U8(0),
+                B(PushContext), R(2),
+                B(LdaTheHole),
+                B(Star), R(6),
+                B(CreateClosure), U8(2), U8(0), U8(2),
+                B(Star), R(3),
+                B(LdaConstant), U8(1),
+                B(Star), R(4),
+                B(Mov), R(3), R(5),
+                B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
+                B(Star), R(4),
+                B(Mov), R(5), R(1),
+                B(LdaConstant), U8(3),
+                B(Star), R(5),
+                B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
+                B(StaCurrentContextSlot), U8(5),
+                B(PopContext), R(2),
+                B(Mov), R(1), R(0),
+                B(LdaUndefined),
+  /*   74 S> */ B(Return),
+]
+constant pool: [
+  SCOPE_INFO_TYPE,
+  FIXED_ARRAY_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
+]
+handlers: [
+]
+
+---
+snippet: "
+  {
+    class D {
+      get #d() { return 1; }
+      set #d(val) { }
+    }
+  
+    class E extends D {
+      get #e() { return 2; }
+      set #e(val) { }
+    }
+  }
+"
+frame size: 9
+parameter count: 1
+bytecode array length: 95
+bytecodes: [
+  /*   30 E> */ B(StackCheck),
+                B(CreateBlockContext), U8(0),
+                B(PushContext), R(4),
+                B(LdaTheHole),
+                B(Star), R(8),
+                B(CreateClosure), U8(2), U8(0), U8(2),
+                B(Star), R(5),
+                B(LdaConstant), U8(1),
+                B(Star), R(6),
+                B(Mov), R(5), R(7),
+                B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
+                B(Star), R(6),
+                B(Mov), R(7), R(3),
+                B(LdaConstant), U8(3),
+                B(Star), R(7),
+                B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
+                B(StaCurrentContextSlot), U8(5),
+                B(PopContext), R(4),
+                B(Mov), R(3), R(0),
+  /*   38 E> */ B(CreateBlockContext), U8(4),
+                B(PushContext), R(4),
+  /*  118 E> */ B(CreateClosure), U8(6), U8(1), U8(2),
+                B(Star), R(5),
+                B(LdaConstant), U8(5),
+                B(Star), R(6),
+                B(Mov), R(5), R(7),
+                B(Mov), R(3), R(8),
+                B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
+                B(Star), R(6),
+                B(Mov), R(7), R(2),
+                B(LdaConstant), U8(7),
+                B(Star), R(7),
+                B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
+                B(StaCurrentContextSlot), U8(5),
+                B(PopContext), R(4),
+                B(Mov), R(2), R(1),
+                B(LdaUndefined),
+  /*  175 S> */ B(Return),
+]
+constant pool: [
+  SCOPE_INFO_TYPE,
+  FIXED_ARRAY_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  ONE_BYTE_INTERNALIZED_STRING_TYPE ["D"],
+  SCOPE_INFO_TYPE,
+  FIXED_ARRAY_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  ONE_BYTE_INTERNALIZED_STRING_TYPE ["E"],
+]
+handlers: [
+]
+
diff --git a/test/cctest/interpreter/bytecode_expectations/PrivateMethods.golden b/test/cctest/interpreter/bytecode_expectations/PrivateMethods.golden
index 5821a20..18dd92d 100644
--- a/test/cctest/interpreter/bytecode_expectations/PrivateMethods.golden
+++ b/test/cctest/interpreter/bytecode_expectations/PrivateMethods.golden
@@ -158,3 +158,86 @@
 handlers: [
 ]
 
+---
+snippet: "
+  {
+    class A { foo() {} }
+    class C extends A {
+      #m() { return super.foo; }
+      fn() { return this.#m(); }
+    }
+    new C().fn();
+  }
+"
+frame size: 10
+parameter count: 1
+bytecode array length: 131
+bytecodes: [
+  /*   30 E> */ B(StackCheck),
+                B(CreateBlockContext), U8(0),
+                B(PushContext), R(4),
+                B(LdaTheHole),
+                B(Star), R(8),
+                B(CreateClosure), U8(2), U8(0), U8(2),
+                B(Star), R(5),
+                B(LdaConstant), U8(1),
+                B(Star), R(6),
+                B(CreateClosure), U8(3), U8(1), U8(2),
+                B(Star), R(9),
+                B(Mov), R(5), R(7),
+                B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(4),
+                B(Star), R(6),
+                B(Mov), R(7), R(3),
+                B(PopContext), R(4),
+                B(Mov), R(3), R(0),
+  /*   38 E> */ B(CreateBlockContext), U8(4),
+                B(PushContext), R(4),
+  /*   77 E> */ B(CreateClosure), U8(6), U8(2), U8(2),
+                B(Star), R(5),
+                B(LdaConstant), U8(5),
+                B(Star), R(6),
+                B(CreateClosure), U8(7), U8(3), U8(2),
+                B(StaCurrentContextSlot), U8(4),
+                B(CreateClosure), U8(8), U8(4), U8(2),
+                B(Star), R(9),
+                B(Mov), R(5), R(7),
+                B(Mov), R(3), R(8),
+                B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(4),
+                B(Star), R(6),
+                B(Mov), R(7), R(2),
+                B(LdaConstant), U8(9),
+                B(Star), R(7),
+                B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
+                B(StaCurrentContextSlot), U8(5),
+                B(LdaCurrentContextSlot), U8(4),
+                B(Star), R(8),
+                B(Ldar), R(6),
+                B(StaNamedProperty), R(8), U8(10), U8(0),
+                B(PopContext), R(4),
+                B(Mov), R(2), R(1),
+  /*  149 S> */ B(Ldar), R(1),
+  /*  149 E> */ B(Construct), R(5), R(0), U8(0), U8(2),
+                B(Star), R(5),
+  /*  157 E> */ B(LdaNamedProperty), R(5), U8(11), U8(4),
+                B(Star), R(4),
+  /*  157 E> */ B(CallProperty0), R(4), R(5), U8(6),
+                B(LdaUndefined),
+  /*  165 S> */ B(Return),
+]
+constant pool: [
+  SCOPE_INFO_TYPE,
+  FIXED_ARRAY_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  SCOPE_INFO_TYPE,
+  FIXED_ARRAY_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
+  SYMBOL_TYPE,
+  ONE_BYTE_INTERNALIZED_STRING_TYPE ["fn"],
+]
+handlers: [
+]
+
diff --git a/test/cctest/interpreter/test-bytecode-generator.cc b/test/cctest/interpreter/test-bytecode-generator.cc
index e1601d4..8afa187 100644
--- a/test/cctest/interpreter/test-bytecode-generator.cc
+++ b/test/cctest/interpreter/test-bytecode-generator.cc
@@ -2788,6 +2788,15 @@
       "\n"
       "  const e = new E;\n"
       "  e.callE();\n"
+      "}\n",
+
+      "{\n"
+      "  class A { foo() {} }\n"
+      "  class C extends A {\n"
+      "    #m() { return super.foo; }\n"
+      "    fn() { return this.#m(); }\n"
+      "  }\n"
+      "  new C().fn();\n"
       "}\n"};
 
   CHECK(CompareTexts(BuildActual(printer, snippets),
diff --git a/test/mjsunit/harmony/private-methods.js b/test/mjsunit/harmony/private-methods.js
index 360b065..fcd8082 100644
--- a/test/mjsunit/harmony/private-methods.js
+++ b/test/mjsunit/harmony/private-methods.js
@@ -281,3 +281,17 @@
   new D;
   new E;
 }
+
+// Super access within private methods.
+{
+  class A {
+    foo() { return 1; }
+  }
+
+  class C extends A {
+    #m() { return super.foo; }
+    fn() { return this.#m()(); }
+  }
+
+  assertEquals(1, new C().fn());
+}