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:
parent
d3a021bbe0
commit
7e44408fc6
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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) \
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}());
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user