Stores and compound assignments for named super properties.
authordslomov@chromium.org <dslomov@chromium.org>
Mon, 29 Sep 2014 08:16:24 +0000 (08:16 +0000)
committerdslomov@chromium.org <dslomov@chromium.org>
Mon, 29 Sep 2014 08:16:24 +0000 (08:16 +0000)
R=ishell@chromium.org, arv@chromium.org, verwaest@chromium.org
BUG=v8:3330
LOG=N

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24268 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

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

index 6108c0b..42a605c 100644 (file)
@@ -1885,13 +1885,19 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
 
   // Left-hand side can only be a property, a global or a (parameter or local)
   // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
+  enum LhsKind {
+    VARIABLE,
+    NAMED_PROPERTY,
+    KEYED_PROPERTY,
+    NAMED_SUPER_PROPERTY
+  };
   LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
   if (property != NULL) {
     assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
+                      ? (property->IsSuperAccess() ? NAMED_SUPER_PROPERTY
+                                                   : NAMED_PROPERTY)
+                      : KEYED_PROPERTY;
   }
 
   // Evaluate LHS expression.
@@ -1908,6 +1914,17 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
         VisitForStackValue(property->obj());
       }
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        const Register scratch = r1;
+        __ ldr(scratch, MemOperand(sp, kPointerSize));
+        __ Push(scratch);
+        __ Push(result_register());
+      }
+      break;
     case KEYED_PROPERTY:
       if (expr->is_compound()) {
         VisitForStackValue(property->obj());
@@ -1935,6 +1952,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case KEYED_PROPERTY:
           EmitKeyedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1981,6 +2002,9 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyAssignment(expr);
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -2319,6 +2343,7 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
+  DCHECK(!prop->IsSuperAccess());
 
   __ mov(LoadDescriptor::NameRegister(), Operand(key->value()));
   if (FLAG_vector_ics) {
@@ -2332,15 +2357,12 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object.
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ Push(r0);
-  VisitForStackValue(super_ref->this_var());
   __ Push(key->value());
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -2612,6 +2634,24 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyAssignment(Assignment* expr) {
+  // Assignment to named property of super.
+  // r0 : value
+  // stack : receiver ('this'), home_object
+  Property* prop = expr->target()->AsProperty();
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ Push(r0);
+  __ Push(key->value());
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+  context()->Plug(r0);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   // Assignment to a property, using a keyed store IC.
 
@@ -2638,6 +2678,9 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
       __ Move(LoadDescriptor::ReceiverRegister(), r0);
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
@@ -2712,16 +2755,16 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
   __ Push(r0);
   VisitForAccumulatorValue(super_ref->this_var());
   __ Push(r0);
-  __ ldr(scratch, MemOperand(sp, kPointerSize));
-  __ Push(scratch);
   __ Push(r0);
+  __ ldr(scratch, MemOperand(sp, kPointerSize * 2));
+  __ Push(scratch);
   __ Push(key->value());
 
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -4339,6 +4382,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   if (prop != NULL) {
     assign_type =
         (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
+    if (prop->IsSuperAccess()) {
+      // throw exception.
+      VisitSuperReference(prop->obj()->AsSuperReference());
+      return;
+    }
   }
 
   // Evaluate expression and get value.
index 619568f..9d54482 100644 (file)
@@ -1864,13 +1864,19 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
 
   // Left-hand side can only be a property, a global or a (parameter or local)
   // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
+  enum LhsKind {
+    VARIABLE,
+    NAMED_PROPERTY,
+    KEYED_PROPERTY,
+    NAMED_SUPER_PROPERTY
+  };
   LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
   if (property != NULL) {
     assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
+                      ? (property->IsSuperAccess() ? NAMED_SUPER_PROPERTY
+                                                   : NAMED_PROPERTY)
+                      : KEYED_PROPERTY;
   }
 
   // Evaluate LHS expression.
@@ -1887,6 +1893,16 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
         VisitForStackValue(property->obj());
       }
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        const Register scratch = x10;
+        __ Peek(scratch, kPointerSize);
+        __ Push(scratch, result_register());
+      }
+      break;
     case KEYED_PROPERTY:
       if (expr->is_compound()) {
         VisitForStackValue(property->obj());
@@ -1913,6 +1929,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case KEYED_PROPERTY:
           EmitKeyedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1959,6 +1979,9 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyAssignment(expr);
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -1983,15 +2006,12 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object.
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ Push(x0);
-  VisitForStackValue(super_ref->this_var());
   __ Push(key->value());
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -2277,6 +2297,24 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyAssignment(Assignment* expr) {
+  // Assignment to named property of super.
+  // x0 : value
+  // stack : receiver ('this'), home_object
+  Property* prop = expr->target()->AsProperty();
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ Push(x0);
+  __ Push(key->value());
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+  context()->Plug(x0);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   ASM_LOCATION("FullCodeGenerator::EmitKeyedPropertyAssignment");
   // Assignment to a property, using a keyed store IC.
@@ -2305,6 +2343,9 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
       __ Move(LoadDescriptor::ReceiverRegister(), x0);
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
@@ -2379,14 +2420,14 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
   VisitForAccumulatorValue(super_ref->this_var());
   __ Push(x0);
   __ Peek(scratch, kPointerSize);
-  __ Push(scratch, x0);
+  __ Push(x0, scratch);
   __ Push(key->value());
 
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -4006,6 +4047,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   if (prop != NULL) {
     assign_type =
         (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
+    if (prop->IsSuperAccess()) {
+      // throw exception.
+      VisitSuperReference(prop->obj()->AsSuperReference());
+      return;
+    }
   }
 
   // Evaluate expression and get value.
index 71e1b60..fdb3293 100644 (file)
@@ -521,6 +521,8 @@ class FullCodeGenerator: public AstVisitor {
   // The receiver is left on the stack by the IC.
   void EmitNamedPropertyLoad(Property* expr);
 
+  // Load a value from super.named prroperty.
+  // Expect receiver ('this' value) and home_object on the stack.
   void EmitNamedSuperPropertyLoad(Property* expr);
 
   // Load a value from a keyed property.
@@ -558,6 +560,10 @@ class FullCodeGenerator: public AstVisitor {
   // of the stack and the right-hand-side value in the accumulator.
   void EmitNamedPropertyAssignment(Assignment* expr);
 
+  // Complete a super named property assignment. The right-hand-side value
+  // is expected in accumulator.
+  void EmitNamedSuperPropertyAssignment(Assignment* expr);
+
   // Complete a keyed property assignment.  The receiver and key are
   // expected on top of the stack and the right-hand-side value in the
   // accumulator.
index a5065aa..a382dad 100644 (file)
@@ -1816,13 +1816,19 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
 
   // Left-hand side can only be a property, a global or a (parameter or local)
   // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
+  enum LhsKind {
+    VARIABLE,
+    NAMED_PROPERTY,
+    KEYED_PROPERTY,
+    NAMED_SUPER_PROPERTY
+  };
   LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
   if (property != NULL) {
     assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
+                      ? (property->IsSuperAccess() ? NAMED_SUPER_PROPERTY
+                                                   : NAMED_PROPERTY)
+                      : KEYED_PROPERTY;
   }
 
   // Evaluate LHS expression.
@@ -1830,6 +1836,15 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
     case VARIABLE:
       // Nothing to do here.
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ push(result_register());
+      if (expr->is_compound()) {
+        __ push(MemOperand(esp, kPointerSize));
+        __ push(result_register());
+      }
+      break;
     case NAMED_PROPERTY:
       if (expr->is_compound()) {
         // We need the receiver both on the stack and in the register.
@@ -1863,6 +1878,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
           EmitVariableLoad(expr->target()->AsVariableProxy());
           PrepareForBailout(expr->target(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case NAMED_PROPERTY:
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1912,6 +1931,9 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyAssignment(expr);
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -2239,6 +2261,8 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
+  DCHECK(!prop->IsSuperAccess());
+
   __ mov(LoadDescriptor::NameRegister(), Immediate(key->value()));
   if (FLAG_vector_ics) {
     __ mov(VectorLoadICDescriptor::SlotRegister(),
@@ -2251,15 +2275,12 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object.
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ push(eax);
-  VisitForStackValue(super_ref->this_var());
   __ push(Immediate(key->value()));
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -2530,6 +2551,24 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyAssignment(Assignment* expr) {
+  // Assignment to named property of super.
+  // eax : value
+  // stack : receiver ('this'), home_object
+  Property* prop = expr->target()->AsProperty();
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ push(eax);
+  __ push(Immediate(key->value()));
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+  context()->Plug(eax);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   // Assignment to a property, using a keyed store IC.
   // eax               : value
@@ -2559,6 +2598,9 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
       __ Move(LoadDescriptor::ReceiverRegister(), result_register());
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
@@ -2627,14 +2669,14 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
   __ push(eax);
   VisitForAccumulatorValue(super_ref->this_var());
   __ push(eax);
-  __ push(Operand(esp, kPointerSize));
   __ push(eax);
+  __ push(Operand(esp, kPointerSize * 2));
   __ push(Immediate(key->value()));
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -4298,6 +4340,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   if (prop != NULL) {
     assign_type =
         (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
+    if (prop->IsSuperAccess()) {
+      // throw exception.
+      VisitSuperReference(prop->obj()->AsSuperReference());
+      return;
+    }
   }
 
   // Evaluate expression and get value.
index bea2792..0ff5973 100644 (file)
@@ -2807,7 +2807,8 @@ MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
 MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
                                         Handle<Object> value,
                                         StrictMode strict_mode,
-                                        StoreFromKeyed store_mode) {
+                                        StoreFromKeyed store_mode,
+                                        StorePropertyMode data_store_mode) {
   // Make sure that the top context does not change when doing callbacks or
   // interceptor calls.
   AssertNoContextChange ncc(it->isolate());
@@ -2902,6 +2903,16 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
                     Object);
   }
 
+  if (data_store_mode == SUPER_PROPERTY) {
+    if (strict_mode == STRICT) {
+      Handle<Object> args[1] = {it->name()};
+      THROW_NEW_ERROR(it->isolate(),
+                      NewReferenceError("not_defined", HandleVector(args, 1)),
+                      Object);
+    }
+    return value;
+  }
+
   return AddDataProperty(it, value, NONE, strict_mode, store_mode);
 }
 
index e232197..f2e17d3 100644 (file)
@@ -1007,6 +1007,8 @@ class Object {
     CERTAINLY_NOT_STORE_FROM_KEYED
   };
 
+  enum StorePropertyMode { NORMAL_PROPERTY, SUPER_PROPERTY };
+
   INLINE(bool IsFixedArrayBase() const);
   INLINE(bool IsExternal() const);
   INLINE(bool IsAccessorInfo() const);
@@ -1116,7 +1118,8 @@ class Object {
 
   MUST_USE_RESULT static MaybeHandle<Object> SetProperty(
       LookupIterator* it, Handle<Object> value, StrictMode strict_mode,
-      StoreFromKeyed store_mode);
+      StoreFromKeyed store_mode,
+      StorePropertyMode data_store_mode = NORMAL_PROPERTY);
   MUST_USE_RESULT static MaybeHandle<Object> WriteToReadOnlyProperty(
       LookupIterator* it, Handle<Object> value, StrictMode strict_mode);
   static Handle<Object> SetDataProperty(LookupIterator* it,
index 15a5680..0cafc3e 100644 (file)
@@ -1948,8 +1948,8 @@ RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
 RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
   CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
 
   if (home_object->IsAccessCheckNeeded() &&
@@ -1969,6 +1969,54 @@ RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
 }
 
 
+static Object* StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
+                            Handle<Object> receiver, Handle<Name> name,
+                            Handle<Object> value, StrictMode strict_mode) {
+  if (home_object->IsAccessCheckNeeded() &&
+      !isolate->MayNamedAccess(home_object, name, v8::ACCESS_SET)) {
+    isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_SET);
+    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+  }
+
+  PrototypeIterator iter(isolate, home_object);
+  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
+  if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
+
+  LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto));
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Object::SetProperty(&it, value, strict_mode,
+                          Object::CERTAINLY_NOT_STORE_FROM_KEYED,
+                          Object::SUPER_PROPERTY));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 3);
+
+  return StoreToSuper(isolate, home_object, receiver, name, value, STRICT);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 3);
+
+  return StoreToSuper(isolate, home_object, receiver, name, value, SLOPPY);
+}
+
+
 RUNTIME_FUNCTION(Runtime_IsExtensible) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
index 0d66f69..da8511b 100644 (file)
@@ -186,7 +186,9 @@ namespace internal {
   F(HomeObjectSymbol, 0, 1)                                \
   F(ThrowNonMethodError, 0, 1)                             \
   F(ThrowUnsupportedSuperError, 0, 1)                      \
-  F(LoadFromSuper, 3, 1)
+  F(LoadFromSuper, 3, 1)                                   \
+  F(StoreToSuper_Strict, 4, 1)                             \
+  F(StoreToSuper_Sloppy, 4, 1)
 
 
 #define RUNTIME_FUNCTION_LIST_ALWAYS_2(F)              \
index 1c7f095..02c2d9c 100644 (file)
@@ -1849,13 +1849,19 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
 
   // Left-hand side can only be a property, a global or a (parameter or local)
   // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
+  enum LhsKind {
+    VARIABLE,
+    NAMED_PROPERTY,
+    KEYED_PROPERTY,
+    NAMED_SUPER_PROPERTY
+  };
   LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
   if (property != NULL) {
     assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
+                      ? (property->IsSuperAccess() ? NAMED_SUPER_PROPERTY
+                                                   : NAMED_PROPERTY)
+                      : KEYED_PROPERTY;
   }
 
   // Evaluate LHS expression.
@@ -1872,6 +1878,15 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
         VisitForStackValue(property->obj());
       }
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        __ Push(MemOperand(rsp, kPointerSize));
+        __ Push(result_register());
+      }
+      break;
     case KEYED_PROPERTY: {
       if (expr->is_compound()) {
         VisitForStackValue(property->obj());
@@ -1899,6 +1914,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case KEYED_PROPERTY:
           EmitKeyedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1944,6 +1963,9 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyAssignment(expr);
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -2271,6 +2293,8 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
+  DCHECK(!prop->IsSuperAccess());
+
   __ Move(LoadDescriptor::NameRegister(), key->value());
   if (FLAG_vector_ics) {
     __ Move(VectorLoadICDescriptor::SlotRegister(),
@@ -2283,15 +2307,12 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ Push(rax);
-  VisitForStackValue(super_ref->this_var());
   __ Push(key->value());
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -2526,6 +2547,24 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyAssignment(Assignment* expr) {
+  // Assignment to named property of super.
+  // rax : value
+  // stack : receiver ('this'), home_object
+  Property* prop = expr->target()->AsProperty();
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ Push(rax);
+  __ Push(key->value());
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+  context()->Plug(rax);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   // Assignment to a property, using a keyed store IC.
 
@@ -2553,6 +2592,9 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
       __ movp(LoadDescriptor::ReceiverRegister(), rax);
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
@@ -2621,15 +2663,15 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
   __ Push(rax);
   VisitForAccumulatorValue(super_ref->this_var());
   __ Push(rax);
-  __ Push(Operand(rsp, kPointerSize));
   __ Push(rax);
+  __ Push(Operand(rsp, kPointerSize * 2));
   __ Push(key->value());
 
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -4311,6 +4353,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   if (prop != NULL) {
     assign_type =
         (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
+    if (prop->IsSuperAccess()) {
+      // throw exception.
+      VisitSuperReference(prop->obj()->AsSuperReference());
+      return;
+    }
   }
 
   // Evaluate expression and get value.
index 89fb4b1..809ba10 100644 (file)
@@ -18,6 +18,8 @@
 
   function fDerived() {
      assertEquals("Base this is Derived", super.f());
+     var a = super.x;
+     assertEquals(15, a);
      assertEquals(15, super.x);
      assertEquals(27, this.x);
 
@@ -34,6 +36,7 @@
   assertEquals("Derived", new Derived().f());
 }());
 
+
 (function TestSuperKeywordNonMethod() {
   function f() {
     super.unknown();
   Derived.prototype.testGetter = function() {
     return super.x;
   }.toMethod(Derived.prototype);
+  Derived.prototype.testGetterStrict = function() {
+    'use strict';
+    return super.x;
+  }.toMethod(Derived.prototype);
   derived = new Derived();
   assertEquals('derived', derived.testGetter());
+  derived = new Derived();
+  assertEquals('derived', derived.testGetterStrict());
 }());
 
-/*
- * TODO[dslomov]: named stores and keyed loads/stores not implemented yet.
+
 (function TestSetter() {
   function Base() {}
   Base.prototype = {
     _x: 'derived'
   };
   Derived.prototype.testSetter = function() {
-      super.x = 'foobar';
-    }.toMethod(Derived.prototype);
+    assertEquals('foobar', super.x = 'foobar');
+    assertEquals('foobarabc', super.x += 'abc');
+  }.toMethod(Derived.prototype);
   var d = new Derived();
   d.testSetter();
   assertEquals('base', Base.prototype._x);
-  assertEquals('foobar', d._x);
+  assertEquals('foobarabc', d._x);
+  d._x = '';
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    assertEquals('foobar', super.x = 'foobar');
+    assertEquals('foobarabc', super.x += 'abc');
+  }.toMethod(Derived.prototype);
+  d.testSetterStrict();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
 }());
 
 
-(function TestKeyedGetter() {
+(function TestAccessorsOnPrimitives() {
+  var getCalled = false;
+  var setCalled = false;
   function Base() {}
   Base.prototype = {
     constructor: Base,
-    _x: 'base'
+    get x() {
+      getCalled = true;
+      return 1;
+    },
+    set x(v) {
+      setCalled = true;
+      return v;
+    },
   };
 
-  Object.defineProperty(Base.prototype, '0',
-        { get: function() { return this._x; } });
-
   function Derived() {}
-  Derived.__proto__ = Base;
   Derived.prototype = {
     __proto__: Base.prototype,
     constructor: Derived,
-    _x: 'derived'
   };
-  Derived.prototype.testGetter = function() {
-      return super[0];
-    }.toMethod(Derived.prototype);
-  assertEquals('derived', new Derived()[0]);
-  // assertEquals('derived', new Derived().testGetter());
+  Derived.prototype.testSetter = function() {
+    assertTrue(42 == this);
+    getCalled = false;
+    setCalled = false;
+    assertEquals(1, super.x);
+    assertTrue(getCalled);
+    assertFalse(setCalled);
+
+    setCalled = false;
+    getCalled = false;
+    assertEquals(5, super.x = 5);
+    assertFalse(getCalled);
+    assertTrue(setCalled);
+
+    getCalled = false;
+    setCalled = false;
+    assertEquals(6, super.x += 5);
+    assertTrue(getCalled);
+    assertTrue(setCalled);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    assertTrue(42 == this);
+    getCalled = false;
+    setCalled = false;
+    assertEquals(1, super.x);
+    assertTrue(getCalled);
+    assertFalse(setCalled);
+
+    setCalled = false;
+    getCalled = false;
+    assertEquals(5, super.x = 5);
+    assertFalse(getCalled);
+    assertTrue(setCalled);
+
+    getCalled = false;
+    setCalled = false;
+    assertEquals(6, super.x += 5);
+    assertTrue(getCalled);
+    assertTrue(setCalled);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetter.call(42);
+  Derived.prototype.testSetterStrict.call(42);
+
+  function DerivedFromString() {}
+  DerivedFromString.prototype = Object.create(String.prototype);
+
+  function f() {
+    'use strict';
+    assertTrue(42 == this);
+    assertEquals(String.prototype.toString, super.toString);
+    var except = false;
+    try {
+      super.toString();
+    } catch(e) { except = true; }
+    assertTrue(except);
+  }
+  f.toMethod(DerivedFromString.prototype).call(42);
+}());
+
+
+(function TestSetterFailures() {
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  Derived.prototype.mSloppy = function () {
+    super.x = 10;
+    assertEquals(undefined, super.x);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function () {
+    "use strict";
+    super.x = 10;
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.mSloppy();
+  assertEquals(undefined, d.x);
+  var d1 = new Derived();
+  assertThrows(function() { d.mStrict(); }, ReferenceError);
+  assertEquals(undefined, d.x);
+}());
+
+
+(function TestUnsupportedCases() {
+  function f1(x) { return super[x]; }
+  var o = {}
+  assertThrows(function(){f1.toMethod(o)(x);}, ReferenceError);
+  function f2() { super.x++; }
+  assertThrows(function(){f2.toMethod(o)();}, ReferenceError);
 }());
-*/