Stores and compound assignments for named super properties.

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
This commit is contained in:
dslomov@chromium.org 2014-09-29 08:16:24 +00:00
parent d3a021bbe0
commit 7e44408fc6
10 changed files with 429 additions and 64 deletions

View 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.

View 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.

View 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.

View 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.

View 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);
}

View 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,

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

View 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) \

View 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.

View 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();
@ -65,12 +68,17 @@
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 = {
@ -92,36 +100,135 @@
_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);
}());
*/