Classes: Add super support in methods and accessors
authorarv@chromium.org <arv@chromium.org>
Wed, 29 Oct 2014 11:45:57 +0000 (11:45 +0000)
committerarv@chromium.org <arv@chromium.org>
Wed, 29 Oct 2014 11:46:18 +0000 (11:46 +0000)
This is done by installing the [[HomeObject]] on the method and the
accessor functions.

BUG=v8:3330
LOG=Y
R=dslomov@chromium.org

Review URL: https://codereview.chromium.org/683893002

Cr-Commit-Position: refs/heads/master@{#24976}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24976 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/full-codegen-arm.cc
src/arm64/full-codegen-arm64.cc
src/ia32/full-codegen-ia32.cc
src/runtime/runtime-classes.cc
src/runtime/runtime.h
src/x64/full-codegen-x64.cc
test/mjsunit/harmony/classes.js

index 76e6738..bdc68b1 100644 (file)
@@ -2530,34 +2530,22 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
     }
     __ push(scratch);
     VisitForStackValue(key);
+    VisitForStackValue(value);
 
     switch (property->kind()) {
       case ObjectLiteral::Property::CONSTANT:
       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
       case ObjectLiteral::Property::COMPUTED:
       case ObjectLiteral::Property::PROTOTYPE:
-        VisitForStackValue(value);
-        __ mov(scratch, Operand(Smi::FromInt(NONE)));
-        __ push(scratch);
-        __ CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
         break;
 
       case ObjectLiteral::Property::GETTER:
-        VisitForStackValue(value);
-        __ LoadRoot(scratch, Heap::kNullValueRootIndex);
-        __ push(scratch);
-        __ mov(scratch, Operand(Smi::FromInt(NONE)));
-        __ push(scratch);
-        __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
         break;
 
       case ObjectLiteral::Property::SETTER:
-        __ LoadRoot(scratch, Heap::kNullValueRootIndex);
-        __ push(scratch);
-        VisitForStackValue(value);
-        __ mov(scratch, Operand(Smi::FromInt(NONE)));
-        __ push(scratch);
-        __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
         break;
 
       default:
index a318b61..792dc30 100644 (file)
@@ -2202,34 +2202,22 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
     }
     __ Push(scratch);
     VisitForStackValue(key);
+    VisitForStackValue(value);
 
     switch (property->kind()) {
       case ObjectLiteral::Property::CONSTANT:
       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
       case ObjectLiteral::Property::COMPUTED:
       case ObjectLiteral::Property::PROTOTYPE:
-        VisitForStackValue(value);
-        __ Mov(scratch, Smi::FromInt(NONE));
-        __ Push(scratch);
-        __ CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
         break;
 
       case ObjectLiteral::Property::GETTER:
-        VisitForStackValue(value);
-        __ LoadRoot(scratch, Heap::kNullValueRootIndex);
-        __ push(scratch);
-        __ Mov(scratch, Smi::FromInt(NONE));
-        __ Push(scratch);
-        __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
         break;
 
       case ObjectLiteral::Property::SETTER:
-        __ LoadRoot(scratch, Heap::kNullValueRootIndex);
-        __ push(scratch);
-        VisitForStackValue(value);
-        __ Mov(scratch, Smi::FromInt(NONE));
-        __ Push(scratch);
-        __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
         break;
 
       default:
index de08bd1..920d036 100644 (file)
@@ -2444,29 +2444,22 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
       __ push(Operand(esp, 0));  // prototype
     }
     VisitForStackValue(key);
+    VisitForStackValue(value);
 
     switch (property->kind()) {
       case ObjectLiteral::Property::CONSTANT:
       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
       case ObjectLiteral::Property::COMPUTED:
       case ObjectLiteral::Property::PROTOTYPE:
-        VisitForStackValue(value);
-        __ push(Immediate(Smi::FromInt(NONE)));
-        __ CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
         break;
 
       case ObjectLiteral::Property::GETTER:
-        VisitForStackValue(value);
-        __ push(Immediate(isolate()->factory()->null_value()));
-        __ push(Immediate(Smi::FromInt(NONE)));
-        __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
         break;
 
       case ObjectLiteral::Property::SETTER:
-        __ push(Immediate(isolate()->factory()->null_value()));
-        VisitForStackValue(value);
-        __ push(Immediate(Smi::FromInt(NONE)));
-        __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
         break;
 
       default:
index 15a08b0..cc4e09b 100644 (file)
@@ -153,6 +153,84 @@ RUNTIME_FUNCTION(Runtime_DefineClass) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_DefineClassMethod) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 2);
+
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+                   function, isolate->factory()->home_object_symbol(), object,
+                   DONT_ENUM));
+
+  uint32_t index;
+  if (key->ToArrayIndex(&index)) {
+    RETURN_FAILURE_ON_EXCEPTION(
+        isolate, JSObject::SetOwnElement(object, index, function, STRICT));
+  }
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Runtime::ToName(isolate, key));
+  if (name->AsArrayIndex(&index)) {
+    RETURN_FAILURE_ON_EXCEPTION(
+        isolate, JSObject::SetOwnElement(object, index, function, STRICT));
+  } else {
+    RETURN_FAILURE_ON_EXCEPTION(
+        isolate,
+        JSObject::SetOwnPropertyIgnoreAttributes(object, name, function, NONE));
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DefineClassGetter) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, getter, 2);
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Runtime::ToName(isolate, key));
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate,
+      JSObject::SetOwnPropertyIgnoreAttributes(
+          getter, isolate->factory()->home_object_symbol(), object, DONT_ENUM));
+
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate,
+      JSObject::DefineAccessor(object, name, getter,
+                               isolate->factory()->null_value(), NONE));
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DefineClassSetter) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, setter, 2);
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Runtime::ToName(isolate, key));
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate,
+      JSObject::SetOwnPropertyIgnoreAttributes(
+          setter, isolate->factory()->home_object_symbol(), object, DONT_ENUM));
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate,
+      JSObject::DefineAccessor(object, name, isolate->factory()->null_value(),
+                               setter, NONE));
+  return isolate->heap()->undefined_value();
+}
+
+
 RUNTIME_FUNCTION(Runtime_ClassGetSourceCode) {
   HandleScope shs(isolate);
   DCHECK(args.length() == 1);
index 5217f62..599a024 100644 (file)
@@ -188,6 +188,9 @@ namespace internal {
   F(ToMethod, 2, 1)                                        \
   F(HomeObjectSymbol, 0, 1)                                \
   F(DefineClass, 6, 1)                                     \
+  F(DefineClassMethod, 3, 1)                               \
+  F(DefineClassGetter, 3, 1)                               \
+  F(DefineClassSetter, 3, 1)                               \
   F(ClassGetSourceCode, 1, 1)                              \
   F(ThrowNonMethodError, 0, 1)                             \
   F(ThrowUnsupportedSuperError, 0, 1)                      \
index fe06fc7..085a55d 100644 (file)
@@ -2443,29 +2443,22 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
       __ Push(Operand(rsp, 0));  // prototype
     }
     VisitForStackValue(key);
+    VisitForStackValue(value);
 
     switch (property->kind()) {
       case ObjectLiteral::Property::CONSTANT:
       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
       case ObjectLiteral::Property::COMPUTED:
       case ObjectLiteral::Property::PROTOTYPE:
-        VisitForStackValue(value);
-        __ Push(Smi::FromInt(NONE));
-        __ CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
         break;
 
       case ObjectLiteral::Property::GETTER:
-        VisitForStackValue(value);
-        __ Push(isolate()->factory()->null_value());
-        __ Push(Smi::FromInt(NONE));
-        __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
         break;
 
       case ObjectLiteral::Property::SETTER:
-        __ Push(isolate()->factory()->null_value());
-        VisitForStackValue(value);
-        __ Push(Smi::FromInt(NONE));
-        __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
         break;
 
       default:
index 9302b29..c5c2b72 100644 (file)
@@ -439,6 +439,156 @@ function assertAccessorDescriptor(object, name) {
 })();
 
 
+(function TestSuperInMethods() {
+  class B {
+    method() {
+      return 1;
+    }
+    get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    method() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, new C().method());
+})();
+
+
+(function TestSuperInGetter() {
+  class B {
+    method() {
+      return 1;
+    }
+    get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    get y() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, new C().y);
+})();
+
+
+(function TestSuperInSetter() {
+  class B {
+    method() {
+      return 1;
+    }
+    get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    set y(v) {
+      assertEquals(3, v);
+      assertEquals(2, super.x);
+      assertEquals(1, super.method());
+    }
+  }
+  assertEquals(3, new C().y = 3);
+})();
+
+
+(function TestSuperInStaticMethods() {
+  class B {
+    static method() {
+      return 1;
+    }
+    static get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    static method() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, C.method());
+})();
+
+
+(function TestSuperInStaticGetter() {
+  class B {
+    static method() {
+      return 1;
+    }
+    static get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    static get x() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, C.x);
+})();
+
+
+(function TestSuperInStaticSetter() {
+  class B {
+    static method() {
+      return 1;
+    }
+    static get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    static set x(v) {
+      assertEquals(3, v);
+      assertEquals(2, super.x);
+      assertEquals(1, super.method());
+    }
+  }
+  assertEquals(3, C.x = 3);
+})();
+
+
+(function TestNumericPropertyNames() {
+  class B {
+    1() { return 1; }
+    get 2() { return 2; }
+    set 3(_) {}
+
+    static 4() { return 4; }
+    static get 5() { return 5; }
+    static set 6(_) {}
+  }
+
+  assertMethodDescriptor(B.prototype, '1');
+  assertGetterDescriptor(B.prototype, '2');
+  assertSetterDescriptor(B.prototype, '3');
+
+  assertMethodDescriptor(B, '4');
+  assertGetterDescriptor(B, '5');
+  assertSetterDescriptor(B, '6');
+
+  class C extends B {
+    1() { return super[1](); }
+    get 2() { return super[2]; }
+
+    static 4() { return super[4](); }
+    static get 5() { return super[5]; }
+  }
+
+  assertEquals(1, new C()[1]());
+  assertEquals(2, new C()[2]);
+  assertEquals(4, C[4]());
+  assertEquals(5, C[5]);
+})();
+
+
 /* TODO(arv): Implement
 (function TestNameBindingInConstructor() {
   class C {