Keyed stores to super where key is a name.
R=arv@chromium.org, ishell@chromium.org BUG=v:3330 LOG=N Review URL: https://codereview.chromium.org/638623002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24490 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
61b68155c3
commit
53c9f0bb3d
@ -1889,22 +1889,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
|
|
||||||
Comment cmnt(masm_, "[ Assignment");
|
Comment cmnt(masm_, "[ Assignment");
|
||||||
|
|
||||||
// Left-hand side can only be a property, a global or a (parameter or local)
|
|
||||||
// slot.
|
|
||||||
enum LhsKind {
|
|
||||||
VARIABLE,
|
|
||||||
NAMED_PROPERTY,
|
|
||||||
KEYED_PROPERTY,
|
|
||||||
NAMED_SUPER_PROPERTY
|
|
||||||
};
|
|
||||||
LhsKind assign_type = VARIABLE;
|
|
||||||
Property* property = expr->target()->AsProperty();
|
Property* property = expr->target()->AsProperty();
|
||||||
if (property != NULL) {
|
LhsKind assign_type = GetAssignType(property);
|
||||||
assign_type = (property->key()->IsPropertyName())
|
|
||||||
? (property->IsSuperAccess() ? NAMED_SUPER_PROPERTY
|
|
||||||
: NAMED_PROPERTY)
|
|
||||||
: KEYED_PROPERTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate LHS expression.
|
// Evaluate LHS expression.
|
||||||
switch (assign_type) {
|
switch (assign_type) {
|
||||||
@ -1931,6 +1917,21 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
__ Push(result_register());
|
__ Push(result_register());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||||
|
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||||
|
__ Push(result_register());
|
||||||
|
VisitForAccumulatorValue(property->key());
|
||||||
|
__ Push(result_register());
|
||||||
|
if (expr->is_compound()) {
|
||||||
|
const Register scratch = r1;
|
||||||
|
__ ldr(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||||
|
__ Push(scratch);
|
||||||
|
__ ldr(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||||
|
__ Push(scratch);
|
||||||
|
__ Push(result_register());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
if (expr->is_compound()) {
|
if (expr->is_compound()) {
|
||||||
VisitForStackValue(property->obj());
|
VisitForStackValue(property->obj());
|
||||||
@ -1962,6 +1963,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
EmitNamedSuperPropertyLoad(property);
|
EmitNamedSuperPropertyLoad(property);
|
||||||
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
EmitKeyedSuperPropertyLoad(property);
|
||||||
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
EmitKeyedPropertyLoad(property);
|
EmitKeyedPropertyLoad(property);
|
||||||
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
@ -2012,6 +2017,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
EmitNamedSuperPropertyStore(property);
|
EmitNamedSuperPropertyStore(property);
|
||||||
context()->Plug(r0);
|
context()->Plug(r0);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
EmitKeyedSuperPropertyStore(property);
|
||||||
|
context()->Plug(r0);
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
EmitKeyedPropertyAssignment(expr);
|
EmitKeyedPropertyAssignment(expr);
|
||||||
break;
|
break;
|
||||||
@ -2657,14 +2666,27 @@ void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
|
|||||||
Literal* key = prop->key()->AsLiteral();
|
Literal* key = prop->key()->AsLiteral();
|
||||||
DCHECK(key != NULL);
|
DCHECK(key != NULL);
|
||||||
|
|
||||||
__ Push(r0);
|
|
||||||
__ Push(key->value());
|
__ Push(key->value());
|
||||||
|
__ Push(r0);
|
||||||
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
|
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
|
||||||
: Runtime::kStoreToSuper_Sloppy),
|
: Runtime::kStoreToSuper_Sloppy),
|
||||||
4);
|
4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
|
||||||
|
// Assignment to named property of super.
|
||||||
|
// r0 : value
|
||||||
|
// stack : receiver ('this'), home_object, key
|
||||||
|
DCHECK(prop != NULL);
|
||||||
|
|
||||||
|
__ Push(r0);
|
||||||
|
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
|
||||||
|
: Runtime::kStoreKeyedToSuper_Sloppy),
|
||||||
|
4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
||||||
// Assignment to a property, using a keyed store IC.
|
// Assignment to a property, using a keyed store IC.
|
||||||
|
|
||||||
@ -4436,24 +4458,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
Comment cmnt(masm_, "[ CountOperation");
|
Comment cmnt(masm_, "[ CountOperation");
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
|
|
||||||
// Expression can only be a property, a global or a (parameter or local)
|
|
||||||
// slot.
|
|
||||||
enum LhsKind {
|
|
||||||
VARIABLE,
|
|
||||||
NAMED_PROPERTY,
|
|
||||||
KEYED_PROPERTY,
|
|
||||||
NAMED_SUPER_PROPERTY
|
|
||||||
};
|
|
||||||
LhsKind assign_type = VARIABLE;
|
|
||||||
Property* prop = expr->expression()->AsProperty();
|
Property* prop = expr->expression()->AsProperty();
|
||||||
// In case of a property we use the uninitialized expression context
|
LhsKind assign_type = GetAssignType(prop);
|
||||||
// of the key to detect a named property.
|
|
||||||
if (prop != NULL) {
|
|
||||||
assign_type =
|
|
||||||
(prop->key()->IsPropertyName())
|
|
||||||
? (prop->IsSuperAccess() ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY)
|
|
||||||
: KEYED_PROPERTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate expression and get value.
|
// Evaluate expression and get value.
|
||||||
if (assign_type == VARIABLE) {
|
if (assign_type == VARIABLE) {
|
||||||
@ -4466,27 +4472,55 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
__ mov(ip, Operand(Smi::FromInt(0)));
|
__ mov(ip, Operand(Smi::FromInt(0)));
|
||||||
__ push(ip);
|
__ push(ip);
|
||||||
}
|
}
|
||||||
if (assign_type == NAMED_PROPERTY) {
|
switch (assign_type) {
|
||||||
// Put the object both on the stack and in the register.
|
case NAMED_PROPERTY: {
|
||||||
VisitForStackValue(prop->obj());
|
// Put the object both on the stack and in the register.
|
||||||
__ ldr(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
|
VisitForStackValue(prop->obj());
|
||||||
EmitNamedPropertyLoad(prop);
|
__ ldr(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
|
||||||
} else if (assign_type == NAMED_SUPER_PROPERTY) {
|
EmitNamedPropertyLoad(prop);
|
||||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
break;
|
||||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
}
|
||||||
__ Push(result_register());
|
|
||||||
const Register scratch = r1;
|
case NAMED_SUPER_PROPERTY: {
|
||||||
__ ldr(scratch, MemOperand(sp, kPointerSize));
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||||
__ Push(scratch);
|
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||||
__ Push(result_register());
|
__ Push(result_register());
|
||||||
EmitNamedSuperPropertyLoad(prop);
|
const Register scratch = r1;
|
||||||
} else {
|
__ ldr(scratch, MemOperand(sp, kPointerSize));
|
||||||
VisitForStackValue(prop->obj());
|
__ Push(scratch);
|
||||||
VisitForStackValue(prop->key());
|
__ Push(result_register());
|
||||||
__ ldr(LoadDescriptor::ReceiverRegister(),
|
EmitNamedSuperPropertyLoad(prop);
|
||||||
MemOperand(sp, 1 * kPointerSize));
|
break;
|
||||||
__ ldr(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
|
}
|
||||||
EmitKeyedPropertyLoad(prop);
|
|
||||||
|
case KEYED_SUPER_PROPERTY: {
|
||||||
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||||
|
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||||
|
__ Push(result_register());
|
||||||
|
VisitForAccumulatorValue(prop->key());
|
||||||
|
__ Push(result_register());
|
||||||
|
const Register scratch = r1;
|
||||||
|
__ ldr(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||||
|
__ Push(scratch);
|
||||||
|
__ ldr(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||||
|
__ Push(scratch);
|
||||||
|
__ Push(result_register());
|
||||||
|
EmitKeyedSuperPropertyLoad(prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KEYED_PROPERTY: {
|
||||||
|
VisitForStackValue(prop->obj());
|
||||||
|
VisitForStackValue(prop->key());
|
||||||
|
__ ldr(LoadDescriptor::ReceiverRegister(),
|
||||||
|
MemOperand(sp, 1 * kPointerSize));
|
||||||
|
__ ldr(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
|
||||||
|
EmitKeyedPropertyLoad(prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VARIABLE:
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4526,6 +4560,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
__ str(r0, MemOperand(sp, 2 * kPointerSize));
|
__ str(r0, MemOperand(sp, 2 * kPointerSize));
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
__ str(r0, MemOperand(sp, 3 * kPointerSize));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4559,6 +4596,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
__ str(r0, MemOperand(sp, 2 * kPointerSize));
|
__ str(r0, MemOperand(sp, 2 * kPointerSize));
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
__ str(r0, MemOperand(sp, 3 * kPointerSize));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4625,6 +4665,17 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case KEYED_SUPER_PROPERTY: {
|
||||||
|
EmitKeyedSuperPropertyStore(prop);
|
||||||
|
if (expr->is_postfix()) {
|
||||||
|
if (!context()->IsEffect()) {
|
||||||
|
context()->PlugTOS();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context()->Plug(r0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case KEYED_PROPERTY: {
|
case KEYED_PROPERTY: {
|
||||||
__ Pop(StoreDescriptor::ReceiverRegister(),
|
__ Pop(StoreDescriptor::ReceiverRegister(),
|
||||||
StoreDescriptor::NameRegister());
|
StoreDescriptor::NameRegister());
|
||||||
|
@ -1868,22 +1868,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
|
|
||||||
Comment cmnt(masm_, "[ Assignment");
|
Comment cmnt(masm_, "[ Assignment");
|
||||||
|
|
||||||
// Left-hand side can only be a property, a global or a (parameter or local)
|
|
||||||
// slot.
|
|
||||||
enum LhsKind {
|
|
||||||
VARIABLE,
|
|
||||||
NAMED_PROPERTY,
|
|
||||||
KEYED_PROPERTY,
|
|
||||||
NAMED_SUPER_PROPERTY
|
|
||||||
};
|
|
||||||
LhsKind assign_type = VARIABLE;
|
|
||||||
Property* property = expr->target()->AsProperty();
|
Property* property = expr->target()->AsProperty();
|
||||||
if (property != NULL) {
|
LhsKind assign_type = GetAssignType(property);
|
||||||
assign_type = (property->key()->IsPropertyName())
|
|
||||||
? (property->IsSuperAccess() ? NAMED_SUPER_PROPERTY
|
|
||||||
: NAMED_PROPERTY)
|
|
||||||
: KEYED_PROPERTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate LHS expression.
|
// Evaluate LHS expression.
|
||||||
switch (assign_type) {
|
switch (assign_type) {
|
||||||
@ -1909,6 +1895,20 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
__ Push(scratch, result_register());
|
__ Push(scratch, result_register());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||||
|
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||||
|
__ Push(result_register());
|
||||||
|
VisitForAccumulatorValue(property->key());
|
||||||
|
__ Push(result_register());
|
||||||
|
if (expr->is_compound()) {
|
||||||
|
const Register scratch1 = x10;
|
||||||
|
const Register scratch2 = x11;
|
||||||
|
__ Peek(scratch1, 2 * kPointerSize);
|
||||||
|
__ Peek(scratch2, kPointerSize);
|
||||||
|
__ Push(scratch1, scratch2, result_register());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
if (expr->is_compound()) {
|
if (expr->is_compound()) {
|
||||||
VisitForStackValue(property->obj());
|
VisitForStackValue(property->obj());
|
||||||
@ -1939,6 +1939,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
EmitNamedSuperPropertyLoad(property);
|
EmitNamedSuperPropertyLoad(property);
|
||||||
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
EmitKeyedSuperPropertyLoad(property);
|
||||||
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
EmitKeyedPropertyLoad(property);
|
EmitKeyedPropertyLoad(property);
|
||||||
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
@ -1989,6 +1993,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
EmitNamedSuperPropertyStore(property);
|
EmitNamedSuperPropertyStore(property);
|
||||||
context()->Plug(x0);
|
context()->Plug(x0);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
EmitKeyedSuperPropertyStore(property);
|
||||||
|
context()->Plug(x0);
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
EmitKeyedPropertyAssignment(expr);
|
EmitKeyedPropertyAssignment(expr);
|
||||||
break;
|
break;
|
||||||
@ -2320,14 +2328,27 @@ void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
|
|||||||
Literal* key = prop->key()->AsLiteral();
|
Literal* key = prop->key()->AsLiteral();
|
||||||
DCHECK(key != NULL);
|
DCHECK(key != NULL);
|
||||||
|
|
||||||
__ Push(x0);
|
|
||||||
__ Push(key->value());
|
__ Push(key->value());
|
||||||
|
__ Push(x0);
|
||||||
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
|
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
|
||||||
: Runtime::kStoreToSuper_Sloppy),
|
: Runtime::kStoreToSuper_Sloppy),
|
||||||
4);
|
4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
|
||||||
|
// Assignment to named property of super.
|
||||||
|
// x0 : value
|
||||||
|
// stack : receiver ('this'), home_object, key
|
||||||
|
DCHECK(prop != NULL);
|
||||||
|
|
||||||
|
__ Push(x0);
|
||||||
|
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
|
||||||
|
: Runtime::kStoreKeyedToSuper_Sloppy),
|
||||||
|
4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
||||||
ASM_LOCATION("FullCodeGenerator::EmitKeyedPropertyAssignment");
|
ASM_LOCATION("FullCodeGenerator::EmitKeyedPropertyAssignment");
|
||||||
// Assignment to a property, using a keyed store IC.
|
// Assignment to a property, using a keyed store IC.
|
||||||
@ -4101,24 +4122,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
Comment cmnt(masm_, "[ CountOperation");
|
Comment cmnt(masm_, "[ CountOperation");
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
|
|
||||||
// Expression can only be a property, a global or a (parameter or local)
|
|
||||||
// slot.
|
|
||||||
enum LhsKind {
|
|
||||||
VARIABLE,
|
|
||||||
NAMED_PROPERTY,
|
|
||||||
KEYED_PROPERTY,
|
|
||||||
NAMED_SUPER_PROPERTY
|
|
||||||
};
|
|
||||||
LhsKind assign_type = VARIABLE;
|
|
||||||
Property* prop = expr->expression()->AsProperty();
|
Property* prop = expr->expression()->AsProperty();
|
||||||
// In case of a property we use the uninitialized expression context
|
LhsKind assign_type = GetAssignType(prop);
|
||||||
// of the key to detect a named property.
|
|
||||||
if (prop != NULL) {
|
|
||||||
assign_type =
|
|
||||||
(prop->key()->IsPropertyName())
|
|
||||||
? (prop->IsSuperAccess() ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY)
|
|
||||||
: KEYED_PROPERTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate expression and get value.
|
// Evaluate expression and get value.
|
||||||
if (assign_type == VARIABLE) {
|
if (assign_type == VARIABLE) {
|
||||||
@ -4130,26 +4135,52 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
if (expr->is_postfix() && !context()->IsEffect()) {
|
if (expr->is_postfix() && !context()->IsEffect()) {
|
||||||
__ Push(xzr);
|
__ Push(xzr);
|
||||||
}
|
}
|
||||||
if (assign_type == NAMED_PROPERTY) {
|
switch (assign_type) {
|
||||||
// Put the object both on the stack and in the register.
|
case NAMED_PROPERTY: {
|
||||||
VisitForStackValue(prop->obj());
|
// Put the object both on the stack and in the register.
|
||||||
__ Peek(LoadDescriptor::ReceiverRegister(), 0);
|
VisitForStackValue(prop->obj());
|
||||||
EmitNamedPropertyLoad(prop);
|
__ Peek(LoadDescriptor::ReceiverRegister(), 0);
|
||||||
} else if (assign_type == NAMED_SUPER_PROPERTY) {
|
EmitNamedPropertyLoad(prop);
|
||||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
break;
|
||||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
}
|
||||||
__ Push(result_register());
|
|
||||||
const Register scratch = x10;
|
case NAMED_SUPER_PROPERTY: {
|
||||||
__ Peek(scratch, kPointerSize);
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||||
__ Push(scratch, result_register());
|
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||||
EmitNamedSuperPropertyLoad(prop);
|
__ Push(result_register());
|
||||||
} else {
|
const Register scratch = x10;
|
||||||
// KEYED_PROPERTY
|
__ Peek(scratch, kPointerSize);
|
||||||
VisitForStackValue(prop->obj());
|
__ Push(scratch, result_register());
|
||||||
VisitForStackValue(prop->key());
|
EmitNamedSuperPropertyLoad(prop);
|
||||||
__ Peek(LoadDescriptor::ReceiverRegister(), 1 * kPointerSize);
|
break;
|
||||||
__ Peek(LoadDescriptor::NameRegister(), 0);
|
}
|
||||||
EmitKeyedPropertyLoad(prop);
|
|
||||||
|
case KEYED_SUPER_PROPERTY: {
|
||||||
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||||
|
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||||
|
__ Push(result_register());
|
||||||
|
VisitForAccumulatorValue(prop->key());
|
||||||
|
__ Push(result_register());
|
||||||
|
const Register scratch1 = x10;
|
||||||
|
const Register scratch2 = x11;
|
||||||
|
__ Peek(scratch1, 2 * kPointerSize);
|
||||||
|
__ Peek(scratch2, kPointerSize);
|
||||||
|
__ Push(scratch1, scratch2, result_register());
|
||||||
|
EmitKeyedSuperPropertyLoad(prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KEYED_PROPERTY: {
|
||||||
|
VisitForStackValue(prop->obj());
|
||||||
|
VisitForStackValue(prop->key());
|
||||||
|
__ Peek(LoadDescriptor::ReceiverRegister(), 1 * kPointerSize);
|
||||||
|
__ Peek(LoadDescriptor::NameRegister(), 0);
|
||||||
|
EmitKeyedPropertyLoad(prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VARIABLE:
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4189,6 +4220,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
__ Poke(x0, kPointerSize * 2);
|
__ Poke(x0, kPointerSize * 2);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
__ Poke(x0, kPointerSize * 3);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4222,6 +4256,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
__ Poke(x0, 2 * kXRegSize);
|
__ Poke(x0, 2 * kXRegSize);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
__ Poke(x0, 3 * kXRegSize);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4290,6 +4327,17 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case KEYED_SUPER_PROPERTY: {
|
||||||
|
EmitKeyedSuperPropertyStore(prop);
|
||||||
|
if (expr->is_postfix()) {
|
||||||
|
if (!context()->IsEffect()) {
|
||||||
|
context()->PlugTOS();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context()->Plug(x0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case KEYED_PROPERTY: {
|
case KEYED_PROPERTY: {
|
||||||
__ Pop(StoreDescriptor::NameRegister());
|
__ Pop(StoreDescriptor::NameRegister());
|
||||||
__ Pop(StoreDescriptor::ReceiverRegister());
|
__ Pop(StoreDescriptor::ReceiverRegister());
|
||||||
|
@ -518,6 +518,24 @@ class FullCodeGenerator: public AstVisitor {
|
|||||||
|
|
||||||
// Platform-specific support for compiling assignments.
|
// Platform-specific support for compiling assignments.
|
||||||
|
|
||||||
|
// Left-hand side can only be a property, a global or a (parameter or local)
|
||||||
|
// slot.
|
||||||
|
enum LhsKind {
|
||||||
|
VARIABLE,
|
||||||
|
NAMED_PROPERTY,
|
||||||
|
KEYED_PROPERTY,
|
||||||
|
NAMED_SUPER_PROPERTY,
|
||||||
|
KEYED_SUPER_PROPERTY
|
||||||
|
};
|
||||||
|
|
||||||
|
static LhsKind GetAssignType(Property* property) {
|
||||||
|
if (property == NULL) return VARIABLE;
|
||||||
|
bool super_access = property->IsSuperAccess();
|
||||||
|
return (property->key()->IsPropertyName())
|
||||||
|
? (super_access ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY)
|
||||||
|
: (super_access ? KEYED_SUPER_PROPERTY : KEYED_PROPERTY);
|
||||||
|
}
|
||||||
|
|
||||||
// Load a value from a named property.
|
// Load a value from a named property.
|
||||||
// The receiver is left on the stack by the IC.
|
// The receiver is left on the stack by the IC.
|
||||||
void EmitNamedPropertyLoad(Property* expr);
|
void EmitNamedPropertyLoad(Property* expr);
|
||||||
@ -569,6 +587,10 @@ class FullCodeGenerator: public AstVisitor {
|
|||||||
// is expected in accumulator.
|
// is expected in accumulator.
|
||||||
void EmitNamedSuperPropertyStore(Property* prop);
|
void EmitNamedSuperPropertyStore(Property* prop);
|
||||||
|
|
||||||
|
// Complete a super named property assignment. The right-hand-side value
|
||||||
|
// is expected in accumulator.
|
||||||
|
void EmitKeyedSuperPropertyStore(Property* prop);
|
||||||
|
|
||||||
// Complete a keyed property assignment. The receiver and key are
|
// Complete a keyed property assignment. The receiver and key are
|
||||||
// expected on top of the stack and the right-hand-side value in the
|
// expected on top of the stack and the right-hand-side value in the
|
||||||
// accumulator.
|
// accumulator.
|
||||||
|
@ -1820,22 +1820,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
|
|
||||||
Comment cmnt(masm_, "[ Assignment");
|
Comment cmnt(masm_, "[ Assignment");
|
||||||
|
|
||||||
// Left-hand side can only be a property, a global or a (parameter or local)
|
|
||||||
// slot.
|
|
||||||
enum LhsKind {
|
|
||||||
VARIABLE,
|
|
||||||
NAMED_PROPERTY,
|
|
||||||
KEYED_PROPERTY,
|
|
||||||
NAMED_SUPER_PROPERTY
|
|
||||||
};
|
|
||||||
LhsKind assign_type = VARIABLE;
|
|
||||||
Property* property = expr->target()->AsProperty();
|
Property* property = expr->target()->AsProperty();
|
||||||
if (property != NULL) {
|
LhsKind assign_type = GetAssignType(property);
|
||||||
assign_type = (property->key()->IsPropertyName())
|
|
||||||
? (property->IsSuperAccess() ? NAMED_SUPER_PROPERTY
|
|
||||||
: NAMED_PROPERTY)
|
|
||||||
: KEYED_PROPERTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate LHS expression.
|
// Evaluate LHS expression.
|
||||||
switch (assign_type) {
|
switch (assign_type) {
|
||||||
@ -1860,6 +1846,18 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
VisitForStackValue(property->obj());
|
VisitForStackValue(property->obj());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||||
|
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||||
|
__ Push(result_register());
|
||||||
|
VisitForAccumulatorValue(property->key());
|
||||||
|
__ Push(result_register());
|
||||||
|
if (expr->is_compound()) {
|
||||||
|
__ push(MemOperand(esp, 2 * kPointerSize));
|
||||||
|
__ push(MemOperand(esp, 2 * kPointerSize));
|
||||||
|
__ push(result_register());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY: {
|
case KEYED_PROPERTY: {
|
||||||
if (expr->is_compound()) {
|
if (expr->is_compound()) {
|
||||||
VisitForStackValue(property->obj());
|
VisitForStackValue(property->obj());
|
||||||
@ -1892,6 +1890,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
EmitNamedPropertyLoad(property);
|
EmitNamedPropertyLoad(property);
|
||||||
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
EmitKeyedSuperPropertyLoad(property);
|
||||||
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
EmitKeyedPropertyLoad(property);
|
EmitKeyedPropertyLoad(property);
|
||||||
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
@ -1939,7 +1941,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
break;
|
break;
|
||||||
case NAMED_SUPER_PROPERTY:
|
case NAMED_SUPER_PROPERTY:
|
||||||
EmitNamedSuperPropertyStore(property);
|
EmitNamedSuperPropertyStore(property);
|
||||||
context()->Plug(eax);
|
context()->Plug(result_register());
|
||||||
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
EmitKeyedSuperPropertyStore(property);
|
||||||
|
context()->Plug(result_register());
|
||||||
break;
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
EmitKeyedPropertyAssignment(expr);
|
EmitKeyedPropertyAssignment(expr);
|
||||||
@ -2574,14 +2580,26 @@ void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
|
|||||||
Literal* key = prop->key()->AsLiteral();
|
Literal* key = prop->key()->AsLiteral();
|
||||||
DCHECK(key != NULL);
|
DCHECK(key != NULL);
|
||||||
|
|
||||||
__ push(eax);
|
|
||||||
__ push(Immediate(key->value()));
|
__ push(Immediate(key->value()));
|
||||||
|
__ push(eax);
|
||||||
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
|
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
|
||||||
: Runtime::kStoreToSuper_Sloppy),
|
: Runtime::kStoreToSuper_Sloppy),
|
||||||
4);
|
4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
|
||||||
|
// Assignment to named property of super.
|
||||||
|
// eax : value
|
||||||
|
// stack : receiver ('this'), home_object, key
|
||||||
|
|
||||||
|
__ push(eax);
|
||||||
|
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
|
||||||
|
: Runtime::kStoreKeyedToSuper_Sloppy),
|
||||||
|
4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
||||||
// Assignment to a property, using a keyed store IC.
|
// Assignment to a property, using a keyed store IC.
|
||||||
// eax : value
|
// eax : value
|
||||||
@ -4391,24 +4409,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
Comment cmnt(masm_, "[ CountOperation");
|
Comment cmnt(masm_, "[ CountOperation");
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
|
|
||||||
// Expression can only be a property, a global or a (parameter or local)
|
|
||||||
// slot.
|
|
||||||
enum LhsKind {
|
|
||||||
VARIABLE,
|
|
||||||
NAMED_PROPERTY,
|
|
||||||
KEYED_PROPERTY,
|
|
||||||
NAMED_SUPER_PROPERTY
|
|
||||||
};
|
|
||||||
LhsKind assign_type = VARIABLE;
|
|
||||||
Property* prop = expr->expression()->AsProperty();
|
Property* prop = expr->expression()->AsProperty();
|
||||||
// In case of a property we use the uninitialized expression context
|
LhsKind assign_type = GetAssignType(prop);
|
||||||
// of the key to detect a named property.
|
|
||||||
if (prop != NULL) {
|
|
||||||
assign_type =
|
|
||||||
(prop->key()->IsPropertyName())
|
|
||||||
? (prop->IsSuperAccess() ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY)
|
|
||||||
: KEYED_PROPERTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate expression and get value.
|
// Evaluate expression and get value.
|
||||||
if (assign_type == VARIABLE) {
|
if (assign_type == VARIABLE) {
|
||||||
@ -4420,25 +4422,50 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
if (expr->is_postfix() && !context()->IsEffect()) {
|
if (expr->is_postfix() && !context()->IsEffect()) {
|
||||||
__ push(Immediate(Smi::FromInt(0)));
|
__ push(Immediate(Smi::FromInt(0)));
|
||||||
}
|
}
|
||||||
if (assign_type == NAMED_PROPERTY) {
|
switch (assign_type) {
|
||||||
// Put the object both on the stack and in the register.
|
case NAMED_PROPERTY: {
|
||||||
VisitForStackValue(prop->obj());
|
// Put the object both on the stack and in the register.
|
||||||
__ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
|
VisitForStackValue(prop->obj());
|
||||||
EmitNamedPropertyLoad(prop);
|
__ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
|
||||||
} else if (assign_type == NAMED_SUPER_PROPERTY) {
|
EmitNamedPropertyLoad(prop);
|
||||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
break;
|
||||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
}
|
||||||
__ push(result_register());
|
|
||||||
__ push(MemOperand(esp, kPointerSize));
|
case NAMED_SUPER_PROPERTY: {
|
||||||
__ push(result_register());
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||||
EmitNamedSuperPropertyLoad(prop);
|
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||||
} else {
|
__ push(result_register());
|
||||||
VisitForStackValue(prop->obj());
|
__ push(MemOperand(esp, kPointerSize));
|
||||||
VisitForStackValue(prop->key());
|
__ push(result_register());
|
||||||
__ mov(LoadDescriptor::ReceiverRegister(),
|
EmitNamedSuperPropertyLoad(prop);
|
||||||
Operand(esp, kPointerSize)); // Object.
|
break;
|
||||||
__ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); // Key.
|
}
|
||||||
EmitKeyedPropertyLoad(prop);
|
|
||||||
|
case KEYED_SUPER_PROPERTY: {
|
||||||
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||||
|
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||||
|
__ push(result_register());
|
||||||
|
VisitForAccumulatorValue(prop->key());
|
||||||
|
__ push(result_register());
|
||||||
|
__ push(MemOperand(esp, 2 * kPointerSize));
|
||||||
|
__ push(MemOperand(esp, 2 * kPointerSize));
|
||||||
|
__ push(result_register());
|
||||||
|
EmitKeyedSuperPropertyLoad(prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KEYED_PROPERTY: {
|
||||||
|
VisitForStackValue(prop->obj());
|
||||||
|
VisitForStackValue(prop->key());
|
||||||
|
__ mov(LoadDescriptor::ReceiverRegister(),
|
||||||
|
Operand(esp, kPointerSize)); // Object.
|
||||||
|
__ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); // Key.
|
||||||
|
EmitKeyedPropertyLoad(prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VARIABLE:
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4476,6 +4503,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
__ mov(Operand(esp, 2 * kPointerSize), eax);
|
__ mov(Operand(esp, 2 * kPointerSize), eax);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
__ mov(Operand(esp, 3 * kPointerSize), eax);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4517,6 +4547,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
__ mov(Operand(esp, 2 * kPointerSize), eax);
|
__ mov(Operand(esp, 2 * kPointerSize), eax);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
__ mov(Operand(esp, 3 * kPointerSize), eax);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4584,6 +4617,17 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case KEYED_SUPER_PROPERTY: {
|
||||||
|
EmitKeyedSuperPropertyStore(prop);
|
||||||
|
if (expr->is_postfix()) {
|
||||||
|
if (!context()->IsEffect()) {
|
||||||
|
context()->PlugTOS();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context()->Plug(eax);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case KEYED_PROPERTY: {
|
case KEYED_PROPERTY: {
|
||||||
__ pop(StoreDescriptor::NameRegister());
|
__ pop(StoreDescriptor::NameRegister());
|
||||||
__ pop(StoreDescriptor::ReceiverRegister());
|
__ pop(StoreDescriptor::ReceiverRegister());
|
||||||
|
@ -76,83 +76,6 @@ static Object* LoadFromSuper(Isolate* isolate, Handle<Object> receiver,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
|
|
||||||
HandleScope scope(isolate);
|
|
||||||
DCHECK(args.length() == 3);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
|
|
||||||
|
|
||||||
return LoadFromSuper(isolate, receiver, home_object, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
|
|
||||||
HandleScope scope(isolate);
|
|
||||||
DCHECK(args.length() == 3);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
|
|
||||||
|
|
||||||
Handle<Name> name;
|
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
|
||||||
Runtime::ToName(isolate, key));
|
|
||||||
uint32_t index;
|
|
||||||
if (name->AsArrayIndex(&index)) {
|
|
||||||
return ThrowUnsupportedSuper(isolate);
|
|
||||||
}
|
|
||||||
return LoadFromSuper(isolate, receiver, home_object, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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_DefineClass) {
|
RUNTIME_FUNCTION(Runtime_DefineClass) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
DCHECK(args.length() == 6);
|
DCHECK(args.length() == 6);
|
||||||
@ -284,5 +207,122 @@ RUNTIME_FUNCTION(Runtime_ClassGetSourceCode) {
|
|||||||
source, Handle<Smi>::cast(start_position)->value(),
|
source, Handle<Smi>::cast(start_position)->value(),
|
||||||
Handle<Smi>::cast(end_position)->value());
|
Handle<Smi>::cast(end_position)->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
DCHECK(args.length() == 3);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
|
||||||
|
|
||||||
|
return LoadFromSuper(isolate, receiver, home_object, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
DCHECK(args.length() == 3);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
|
||||||
|
|
||||||
|
Handle<Name> name;
|
||||||
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
||||||
|
Runtime::ToName(isolate, key));
|
||||||
|
uint32_t index;
|
||||||
|
if (name->AsArrayIndex(&index)) {
|
||||||
|
// TODO(dslomov): Implement.
|
||||||
|
return ThrowUnsupportedSuper(isolate);
|
||||||
|
}
|
||||||
|
return LoadFromSuper(isolate, receiver, home_object, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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(Name, name, 2);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Object, value, 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(Name, name, 2);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
|
||||||
|
|
||||||
|
return StoreToSuper(isolate, home_object, receiver, name, value, SLOPPY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Object* StoreKeyedToSuper(Isolate* isolate, Handle<JSObject> home_object,
|
||||||
|
Handle<Object> receiver, Handle<Object> key,
|
||||||
|
Handle<Object> value, StrictMode strict_mode) {
|
||||||
|
Handle<Name> name;
|
||||||
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
||||||
|
Runtime::ToName(isolate, key));
|
||||||
|
uint32_t index;
|
||||||
|
if (name->AsArrayIndex(&index)) {
|
||||||
|
// TODO(dslomov): Implement.
|
||||||
|
return ThrowUnsupportedSuper(isolate);
|
||||||
|
}
|
||||||
|
return StoreToSuper(isolate, home_object, receiver, name, value, strict_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_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, key, 2);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
|
||||||
|
|
||||||
|
return StoreKeyedToSuper(isolate, home_object, receiver, key, value, STRICT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_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, key, 2);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
|
||||||
|
|
||||||
|
return StoreKeyedToSuper(isolate, home_object, receiver, key, value, SLOPPY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace v8::internal
|
} // namespace v8::internal
|
||||||
|
@ -187,14 +187,16 @@ namespace internal {
|
|||||||
/* Classes support */ \
|
/* Classes support */ \
|
||||||
F(ToMethod, 2, 1) \
|
F(ToMethod, 2, 1) \
|
||||||
F(HomeObjectSymbol, 0, 1) \
|
F(HomeObjectSymbol, 0, 1) \
|
||||||
|
F(DefineClass, 6, 1) \
|
||||||
|
F(ClassGetSourceCode, 1, 1) \
|
||||||
F(ThrowNonMethodError, 0, 1) \
|
F(ThrowNonMethodError, 0, 1) \
|
||||||
F(ThrowUnsupportedSuperError, 0, 1) \
|
F(ThrowUnsupportedSuperError, 0, 1) \
|
||||||
F(LoadFromSuper, 3, 1) \
|
F(LoadFromSuper, 3, 1) \
|
||||||
F(LoadKeyedFromSuper, 3, 1) \
|
F(LoadKeyedFromSuper, 3, 1) \
|
||||||
F(StoreToSuper_Strict, 4, 1) \
|
F(StoreToSuper_Strict, 4, 1) \
|
||||||
F(StoreToSuper_Sloppy, 4, 1) \
|
F(StoreToSuper_Sloppy, 4, 1) \
|
||||||
F(DefineClass, 6, 1) \
|
F(StoreKeyedToSuper_Strict, 4, 1) \
|
||||||
F(ClassGetSourceCode, 1, 1)
|
F(StoreKeyedToSuper_Sloppy, 4, 1)
|
||||||
|
|
||||||
|
|
||||||
#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
|
#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
|
||||||
|
@ -1854,22 +1854,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
|
|
||||||
Comment cmnt(masm_, "[ Assignment");
|
Comment cmnt(masm_, "[ Assignment");
|
||||||
|
|
||||||
// Left-hand side can only be a property, a global or a (parameter or local)
|
|
||||||
// slot.
|
|
||||||
enum LhsKind {
|
|
||||||
VARIABLE,
|
|
||||||
NAMED_PROPERTY,
|
|
||||||
KEYED_PROPERTY,
|
|
||||||
NAMED_SUPER_PROPERTY
|
|
||||||
};
|
|
||||||
LhsKind assign_type = VARIABLE;
|
|
||||||
Property* property = expr->target()->AsProperty();
|
Property* property = expr->target()->AsProperty();
|
||||||
if (property != NULL) {
|
LhsKind assign_type = GetAssignType(property);
|
||||||
assign_type = (property->key()->IsPropertyName())
|
|
||||||
? (property->IsSuperAccess() ? NAMED_SUPER_PROPERTY
|
|
||||||
: NAMED_PROPERTY)
|
|
||||||
: KEYED_PROPERTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate LHS expression.
|
// Evaluate LHS expression.
|
||||||
switch (assign_type) {
|
switch (assign_type) {
|
||||||
@ -1894,6 +1880,18 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
__ Push(result_register());
|
__ Push(result_register());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||||
|
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||||
|
__ Push(result_register());
|
||||||
|
VisitForAccumulatorValue(property->key());
|
||||||
|
__ Push(result_register());
|
||||||
|
if (expr->is_compound()) {
|
||||||
|
__ Push(MemOperand(rsp, 2 * kPointerSize));
|
||||||
|
__ Push(MemOperand(rsp, 2 * kPointerSize));
|
||||||
|
__ Push(result_register());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY: {
|
case KEYED_PROPERTY: {
|
||||||
if (expr->is_compound()) {
|
if (expr->is_compound()) {
|
||||||
VisitForStackValue(property->obj());
|
VisitForStackValue(property->obj());
|
||||||
@ -1925,6 +1923,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
EmitNamedSuperPropertyLoad(property);
|
EmitNamedSuperPropertyLoad(property);
|
||||||
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
EmitKeyedSuperPropertyLoad(property);
|
||||||
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
EmitKeyedPropertyLoad(property);
|
EmitKeyedPropertyLoad(property);
|
||||||
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
PrepareForBailoutForId(property->LoadId(), TOS_REG);
|
||||||
@ -1974,6 +1976,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
EmitNamedSuperPropertyStore(property);
|
EmitNamedSuperPropertyStore(property);
|
||||||
context()->Plug(rax);
|
context()->Plug(rax);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
EmitKeyedSuperPropertyStore(property);
|
||||||
|
context()->Plug(rax);
|
||||||
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
EmitKeyedPropertyAssignment(expr);
|
EmitKeyedPropertyAssignment(expr);
|
||||||
break;
|
break;
|
||||||
@ -2571,14 +2577,27 @@ void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
|
|||||||
Literal* key = prop->key()->AsLiteral();
|
Literal* key = prop->key()->AsLiteral();
|
||||||
DCHECK(key != NULL);
|
DCHECK(key != NULL);
|
||||||
|
|
||||||
__ Push(rax);
|
|
||||||
__ Push(key->value());
|
__ Push(key->value());
|
||||||
|
__ Push(rax);
|
||||||
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
|
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
|
||||||
: Runtime::kStoreToSuper_Sloppy),
|
: Runtime::kStoreToSuper_Sloppy),
|
||||||
4);
|
4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
|
||||||
|
// Assignment to named property of super.
|
||||||
|
// rax : value
|
||||||
|
// stack : receiver ('this'), home_object, key
|
||||||
|
DCHECK(prop != NULL);
|
||||||
|
|
||||||
|
__ Push(rax);
|
||||||
|
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
|
||||||
|
: Runtime::kStoreKeyedToSuper_Sloppy),
|
||||||
|
4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
||||||
// Assignment to a property, using a keyed store IC.
|
// Assignment to a property, using a keyed store IC.
|
||||||
|
|
||||||
@ -4406,24 +4425,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
Comment cmnt(masm_, "[ CountOperation");
|
Comment cmnt(masm_, "[ CountOperation");
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
|
|
||||||
// Expression can only be a property, a global or a (parameter or local)
|
|
||||||
// slot.
|
|
||||||
enum LhsKind {
|
|
||||||
VARIABLE,
|
|
||||||
NAMED_PROPERTY,
|
|
||||||
KEYED_PROPERTY,
|
|
||||||
NAMED_SUPER_PROPERTY
|
|
||||||
};
|
|
||||||
LhsKind assign_type = VARIABLE;
|
|
||||||
Property* prop = expr->expression()->AsProperty();
|
Property* prop = expr->expression()->AsProperty();
|
||||||
// In case of a property we use the uninitialized expression context
|
LhsKind assign_type = GetAssignType(prop);
|
||||||
// of the key to detect a named property.
|
|
||||||
if (prop != NULL) {
|
|
||||||
assign_type =
|
|
||||||
(prop->key()->IsPropertyName())
|
|
||||||
? (prop->IsSuperAccess() ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY)
|
|
||||||
: KEYED_PROPERTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate expression and get value.
|
// Evaluate expression and get value.
|
||||||
if (assign_type == VARIABLE) {
|
if (assign_type == VARIABLE) {
|
||||||
@ -4435,25 +4438,50 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
if (expr->is_postfix() && !context()->IsEffect()) {
|
if (expr->is_postfix() && !context()->IsEffect()) {
|
||||||
__ Push(Smi::FromInt(0));
|
__ Push(Smi::FromInt(0));
|
||||||
}
|
}
|
||||||
if (assign_type == NAMED_PROPERTY) {
|
switch (assign_type) {
|
||||||
VisitForStackValue(prop->obj());
|
case NAMED_PROPERTY: {
|
||||||
__ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
|
VisitForStackValue(prop->obj());
|
||||||
EmitNamedPropertyLoad(prop);
|
__ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
|
||||||
} else if (assign_type == NAMED_SUPER_PROPERTY) {
|
EmitNamedPropertyLoad(prop);
|
||||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
break;
|
||||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
}
|
||||||
__ Push(result_register());
|
|
||||||
__ Push(MemOperand(rsp, kPointerSize));
|
case NAMED_SUPER_PROPERTY: {
|
||||||
__ Push(result_register());
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||||
EmitNamedSuperPropertyLoad(prop);
|
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||||
} else {
|
__ Push(result_register());
|
||||||
VisitForStackValue(prop->obj());
|
__ Push(MemOperand(rsp, kPointerSize));
|
||||||
VisitForStackValue(prop->key());
|
__ Push(result_register());
|
||||||
// Leave receiver on stack
|
EmitNamedSuperPropertyLoad(prop);
|
||||||
__ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, kPointerSize));
|
break;
|
||||||
// Copy of key, needed for later store.
|
}
|
||||||
__ movp(LoadDescriptor::NameRegister(), Operand(rsp, 0));
|
|
||||||
EmitKeyedPropertyLoad(prop);
|
case KEYED_SUPER_PROPERTY: {
|
||||||
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||||
|
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||||
|
__ Push(result_register());
|
||||||
|
VisitForAccumulatorValue(prop->key());
|
||||||
|
__ Push(result_register());
|
||||||
|
__ Push(MemOperand(rsp, 2 * kPointerSize));
|
||||||
|
__ Push(MemOperand(rsp, 2 * kPointerSize));
|
||||||
|
__ Push(result_register());
|
||||||
|
EmitKeyedSuperPropertyLoad(prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KEYED_PROPERTY: {
|
||||||
|
VisitForStackValue(prop->obj());
|
||||||
|
VisitForStackValue(prop->key());
|
||||||
|
// Leave receiver on stack
|
||||||
|
__ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, kPointerSize));
|
||||||
|
// Copy of key, needed for later store.
|
||||||
|
__ movp(LoadDescriptor::NameRegister(), Operand(rsp, 0));
|
||||||
|
EmitKeyedPropertyLoad(prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VARIABLE:
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4491,6 +4519,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
__ movp(Operand(rsp, 2 * kPointerSize), rax);
|
__ movp(Operand(rsp, 2 * kPointerSize), rax);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
__ movp(Operand(rsp, 3 * kPointerSize), rax);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4529,6 +4560,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
__ movp(Operand(rsp, 2 * kPointerSize), rax);
|
__ movp(Operand(rsp, 2 * kPointerSize), rax);
|
||||||
break;
|
break;
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
__ movp(Operand(rsp, 3 * kPointerSize), rax);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4596,6 +4630,17 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case KEYED_SUPER_PROPERTY: {
|
||||||
|
EmitKeyedSuperPropertyStore(prop);
|
||||||
|
if (expr->is_postfix()) {
|
||||||
|
if (!context()->IsEffect()) {
|
||||||
|
context()->PlugTOS();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context()->Plug(rax);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case KEYED_PROPERTY: {
|
case KEYED_PROPERTY: {
|
||||||
__ Pop(StoreDescriptor::NameRegister());
|
__ Pop(StoreDescriptor::NameRegister());
|
||||||
__ Pop(StoreDescriptor::ReceiverRegister());
|
__ Pop(StoreDescriptor::ReceiverRegister());
|
||||||
|
@ -228,6 +228,93 @@
|
|||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
(function TestSetterKeyed() {
|
||||||
|
var x = 'x';
|
||||||
|
function Base() {}
|
||||||
|
Base.prototype = {
|
||||||
|
constructor: Base,
|
||||||
|
get x() {
|
||||||
|
return this._x;
|
||||||
|
},
|
||||||
|
set x(v) {
|
||||||
|
this._x = v;
|
||||||
|
},
|
||||||
|
_x: 'base'
|
||||||
|
};
|
||||||
|
|
||||||
|
function Derived() {}
|
||||||
|
Derived.__proto__ = Base;
|
||||||
|
Derived.prototype = {
|
||||||
|
__proto__: Base.prototype,
|
||||||
|
constructor: Derived,
|
||||||
|
_x: 'derived'
|
||||||
|
};
|
||||||
|
Derived.prototype.testSetter = function() {
|
||||||
|
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('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);
|
||||||
|
|
||||||
|
|
||||||
|
Derived.prototype.testSetterWithToString = function() {
|
||||||
|
var toStringCalled;
|
||||||
|
var o = { toString: function() {
|
||||||
|
toStringCalled++;
|
||||||
|
return 'x';
|
||||||
|
} };
|
||||||
|
|
||||||
|
toStringCalled = 0;
|
||||||
|
super[o] = 'set';
|
||||||
|
assertEquals(1, toStringCalled);
|
||||||
|
assertEquals('set', this._x);
|
||||||
|
|
||||||
|
var eToThrow = new Error();
|
||||||
|
var oThrowsInToString = { toString: function() {
|
||||||
|
throw eToThrow;
|
||||||
|
} };
|
||||||
|
|
||||||
|
var ex = null;
|
||||||
|
try {
|
||||||
|
super[oThrowsInToString] = 'xyz';
|
||||||
|
} catch(e) { ex = e }
|
||||||
|
assertEquals(eToThrow, ex);
|
||||||
|
assertEquals('set', this._x);
|
||||||
|
|
||||||
|
var oReturnsNumericString = { toString: function() {
|
||||||
|
return "1";
|
||||||
|
} };
|
||||||
|
|
||||||
|
ex = null;
|
||||||
|
try {
|
||||||
|
super[oReturnsNumericString] = 'abc';
|
||||||
|
} catch(e) { ex = e }
|
||||||
|
assertTrue(ex instanceof ReferenceError);
|
||||||
|
|
||||||
|
assertEquals('set', this._x);
|
||||||
|
|
||||||
|
ex = null;
|
||||||
|
try {
|
||||||
|
super[1] = 10; // Indexed properties unsupported yet.
|
||||||
|
} catch (e) { ex = e; }
|
||||||
|
assertTrue(ex instanceof ReferenceError);
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
d = new Derived();
|
||||||
|
d.testSetterWithToString();
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
||||||
(function TestSetterDataProperties() {
|
(function TestSetterDataProperties() {
|
||||||
function Base() {}
|
function Base() {}
|
||||||
Base.prototype = {
|
Base.prototype = {
|
||||||
@ -252,6 +339,31 @@
|
|||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
(function TestKeyedSetterDataProperties() {
|
||||||
|
var x = 'x';
|
||||||
|
function Base() {}
|
||||||
|
Base.prototype = {
|
||||||
|
constructor: Base,
|
||||||
|
x: 'x from Base'
|
||||||
|
};
|
||||||
|
|
||||||
|
function Derived() {}
|
||||||
|
Derived.prototype = {
|
||||||
|
__proto__: Base.prototype,
|
||||||
|
constructor: Derived,
|
||||||
|
};
|
||||||
|
|
||||||
|
Derived.prototype.testSetter = function() {
|
||||||
|
assertEquals('x from Base', super[x]);
|
||||||
|
super[x] = 'data property';
|
||||||
|
assertEquals('x from Base', super[x]);
|
||||||
|
assertEquals('data property', this[x]);
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
|
||||||
|
new Derived().testSetter();
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
||||||
(function TestAccessorsOnPrimitives() {
|
(function TestAccessorsOnPrimitives() {
|
||||||
var getCalled = 0;
|
var getCalled = 0;
|
||||||
var setCalled = 0;
|
var setCalled = 0;
|
||||||
@ -342,6 +454,99 @@
|
|||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
(function TestKeyedAccessorsOnPrimitives() {
|
||||||
|
var x = 'x';
|
||||||
|
var newProperty = 'newProperty';
|
||||||
|
var toString = 'toString';
|
||||||
|
var getCalled = 0;
|
||||||
|
var setCalled = 0;
|
||||||
|
function Base() {}
|
||||||
|
Base.prototype = {
|
||||||
|
constructor: Base,
|
||||||
|
get x() {
|
||||||
|
getCalled++;
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
set x(v) {
|
||||||
|
setCalled++;
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function Derived() {}
|
||||||
|
Derived.prototype = {
|
||||||
|
__proto__: Base.prototype,
|
||||||
|
constructor: Derived,
|
||||||
|
};
|
||||||
|
Derived.prototype.testSetter = function() {
|
||||||
|
setCalled = 0;
|
||||||
|
getCalled = 0;
|
||||||
|
assertEquals('object', typeof this);
|
||||||
|
assertTrue(this instanceof Number)
|
||||||
|
assertEquals(42, this.valueOf());
|
||||||
|
assertEquals(1, super[x]);
|
||||||
|
assertEquals(1, getCalled);
|
||||||
|
assertEquals(0, setCalled);
|
||||||
|
|
||||||
|
assertEquals(5, super[x] = 5);
|
||||||
|
assertEquals(1, getCalled);
|
||||||
|
assertEquals(1, setCalled);
|
||||||
|
|
||||||
|
assertEquals(6, super[x] += 5);
|
||||||
|
assertEquals(2, getCalled);
|
||||||
|
assertEquals(2, setCalled);
|
||||||
|
|
||||||
|
super[newProperty] = 15;
|
||||||
|
assertEquals(15, this[newProperty]);
|
||||||
|
assertEquals(undefined, super[newProperty]);
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
|
||||||
|
Derived.prototype.testSetterStrict = function() {
|
||||||
|
'use strict';
|
||||||
|
getCalled = 0;
|
||||||
|
setCalled = 0;
|
||||||
|
assertTrue(42 === this);
|
||||||
|
|
||||||
|
assertEquals(1, super[x]);
|
||||||
|
assertEquals(1, getCalled);
|
||||||
|
assertEquals(0, setCalled);
|
||||||
|
|
||||||
|
assertEquals(5, super[x] = 5);
|
||||||
|
assertEquals(1, getCalled);
|
||||||
|
assertEquals(1, setCalled);
|
||||||
|
|
||||||
|
assertEquals(6, super[x] += 5);
|
||||||
|
assertEquals(2, getCalled);
|
||||||
|
assertEquals(2, setCalled);
|
||||||
|
|
||||||
|
var ex;
|
||||||
|
try {
|
||||||
|
super[newProperty] = 15;
|
||||||
|
} catch (e) { ex = e; }
|
||||||
|
assertTrue(ex instanceof TypeError);
|
||||||
|
}.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 ex;
|
||||||
|
try {
|
||||||
|
super[toString]();
|
||||||
|
} catch(e) { ex = e; }
|
||||||
|
|
||||||
|
assertTrue(ex instanceof TypeError);
|
||||||
|
}
|
||||||
|
f.toMethod(DerivedFromString.prototype).call(42);
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
||||||
(function TestSetterUndefinedProperties() {
|
(function TestSetterUndefinedProperties() {
|
||||||
function Base() {}
|
function Base() {}
|
||||||
function Derived() {}
|
function Derived() {}
|
||||||
@ -371,6 +576,36 @@
|
|||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
(function TestKeyedSetterUndefinedProperties() {
|
||||||
|
var x = 'x';
|
||||||
|
function Base() {}
|
||||||
|
function Derived() {}
|
||||||
|
Derived.prototype = { __proto__ : Base.prototype };
|
||||||
|
Derived.prototype.mSloppy = function () {
|
||||||
|
assertEquals(undefined, super[x]);
|
||||||
|
assertEquals(undefined, this[x]);
|
||||||
|
super[x] = 10;
|
||||||
|
assertEquals(10, this[x]);
|
||||||
|
assertEquals(undefined, super[x]);
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
|
||||||
|
Derived.prototype.mStrict = function () {
|
||||||
|
'use strict';
|
||||||
|
assertEquals(undefined, super[x]);
|
||||||
|
assertEquals(undefined, this[x]);
|
||||||
|
super[x] = 10;
|
||||||
|
assertEquals(10, this[x]);
|
||||||
|
assertEquals(undefined, super[x]);
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
var d = new Derived();
|
||||||
|
d.mSloppy();
|
||||||
|
assertEquals(10, d.x);
|
||||||
|
var d1 = new Derived();
|
||||||
|
d1.mStrict();
|
||||||
|
assertEquals(10, d.x);
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
||||||
(function TestSetterCreatingOwnProperties() {
|
(function TestSetterCreatingOwnProperties() {
|
||||||
function Base() {}
|
function Base() {}
|
||||||
function Derived() {}
|
function Derived() {}
|
||||||
@ -425,6 +660,63 @@
|
|||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
(function TestKeyedSetterCreatingOwnProperties() {
|
||||||
|
var ownReadOnly = 'ownReadOnly';
|
||||||
|
var ownReadonlyAccessor = 'ownReadonlyAccessor';
|
||||||
|
var ownSetter = 'ownSetter';
|
||||||
|
function Base() {}
|
||||||
|
function Derived() {}
|
||||||
|
Derived.prototype = { __proto__ : Base.prototype };
|
||||||
|
var setterCalled;
|
||||||
|
|
||||||
|
Derived.prototype.mSloppy = function() {
|
||||||
|
assertEquals(42, this[ownReadOnly]);
|
||||||
|
super[ownReadOnly] = 55;
|
||||||
|
assertEquals(42, this[ownReadOnly]);
|
||||||
|
|
||||||
|
assertEquals(15, this[ownReadonlyAccessor]);
|
||||||
|
super[ownReadonlyAccessor] = 55;
|
||||||
|
assertEquals(15, this[ownReadonlyAccessor]);
|
||||||
|
|
||||||
|
setterCalled = 0;
|
||||||
|
super[ownSetter] = 42;
|
||||||
|
assertEquals(1, setterCalled);
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
|
||||||
|
Derived.prototype.mStrict = function() {
|
||||||
|
'use strict';
|
||||||
|
assertEquals(42, this[ownReadOnly]);
|
||||||
|
var ex;
|
||||||
|
try {
|
||||||
|
super[ownReadOnly] = 55;
|
||||||
|
} catch(e) { ex = e; }
|
||||||
|
assertTrue(ex instanceof TypeError);
|
||||||
|
assertEquals(42, this[ownReadOnly]);
|
||||||
|
|
||||||
|
assertEquals(15, this[ownReadonlyAccessor]);
|
||||||
|
ex = null;
|
||||||
|
try {
|
||||||
|
super[ownReadonlyAccessor] = 55;
|
||||||
|
} catch(e) { ex = e; }
|
||||||
|
assertTrue(ex instanceof TypeError);
|
||||||
|
assertEquals(15, this[ownReadonlyAccessor]);
|
||||||
|
|
||||||
|
setterCalled = 0;
|
||||||
|
super[ownSetter] = 42;
|
||||||
|
assertEquals(1, setterCalled);
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
|
||||||
|
var d = new Derived();
|
||||||
|
Object.defineProperty(d, 'ownReadOnly', { value : 42, writable : false });
|
||||||
|
Object.defineProperty(d, 'ownSetter',
|
||||||
|
{ set : function() { setterCalled++; } });
|
||||||
|
Object.defineProperty(d, 'ownReadonlyAccessor',
|
||||||
|
{ get : function() { return 15; }});
|
||||||
|
d.mSloppy();
|
||||||
|
d.mStrict();
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
||||||
(function TestSetterNoProtoWalk() {
|
(function TestSetterNoProtoWalk() {
|
||||||
function Base() {}
|
function Base() {}
|
||||||
function Derived() {}
|
function Derived() {}
|
||||||
@ -492,6 +784,74 @@
|
|||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
(function TestKeyedSetterNoProtoWalk() {
|
||||||
|
var x = 'x';
|
||||||
|
function Base() {}
|
||||||
|
function Derived() {}
|
||||||
|
var getCalled;
|
||||||
|
var setCalled;
|
||||||
|
Derived.prototype = {
|
||||||
|
__proto__ : Base.prototype,
|
||||||
|
get x() { getCalled++; return 42; },
|
||||||
|
set x(v) { setCalled++; }
|
||||||
|
};
|
||||||
|
|
||||||
|
Derived.prototype.mSloppy = function() {
|
||||||
|
setCalled = 0;
|
||||||
|
getCalled = 0;
|
||||||
|
assertEquals(42, this[x]);
|
||||||
|
assertEquals(1, getCalled);
|
||||||
|
assertEquals(0, setCalled);
|
||||||
|
|
||||||
|
getCalled = 0;
|
||||||
|
setCalled = 0;
|
||||||
|
this[x] = 43;
|
||||||
|
assertEquals(0, getCalled);
|
||||||
|
assertEquals(1, setCalled);
|
||||||
|
|
||||||
|
getCalled = 0;
|
||||||
|
setCalled = 0;
|
||||||
|
super[x] = 15;
|
||||||
|
assertEquals(0, setCalled);
|
||||||
|
assertEquals(0, getCalled);
|
||||||
|
|
||||||
|
assertEquals(15, this[x]);
|
||||||
|
assertEquals(0, getCalled);
|
||||||
|
assertEquals(0, setCalled);
|
||||||
|
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
|
||||||
|
Derived.prototype.mStrict = function() {
|
||||||
|
'use strict';
|
||||||
|
setCalled = 0;
|
||||||
|
getCalled = 0;
|
||||||
|
assertEquals(42, this[x]);
|
||||||
|
assertEquals(1, getCalled);
|
||||||
|
assertEquals(0, setCalled);
|
||||||
|
|
||||||
|
getCalled = 0;
|
||||||
|
setCalled = 0;
|
||||||
|
this[x] = 43;
|
||||||
|
assertEquals(0, getCalled);
|
||||||
|
assertEquals(1, setCalled);
|
||||||
|
|
||||||
|
getCalled = 0;
|
||||||
|
setCalled = 0;
|
||||||
|
super[x] = 15;
|
||||||
|
assertEquals(0, setCalled);
|
||||||
|
assertEquals(0, getCalled);
|
||||||
|
|
||||||
|
assertEquals(15, this[x]);
|
||||||
|
assertEquals(0, getCalled);
|
||||||
|
assertEquals(0, setCalled);
|
||||||
|
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
|
||||||
|
new Derived().mSloppy();
|
||||||
|
new Derived().mStrict();
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
||||||
(function TestSetterDoesNotReconfigure() {
|
(function TestSetterDoesNotReconfigure() {
|
||||||
function Base() {}
|
function Base() {}
|
||||||
function Derived() {}
|
function Derived() {}
|
||||||
@ -535,6 +895,51 @@
|
|||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
(function TestKeyedSetterDoesNotReconfigure() {
|
||||||
|
var nonEnumConfig = 'nonEnumConfig';
|
||||||
|
var nonEnumNonConfig = 'nonEnumNonConfig';
|
||||||
|
function Base() {}
|
||||||
|
function Derived() {}
|
||||||
|
|
||||||
|
Derived.prototype.mStrict = function (){
|
||||||
|
'use strict';
|
||||||
|
super[nonEnumConfig] = 5;
|
||||||
|
var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig');
|
||||||
|
assertEquals(5, d1.value);
|
||||||
|
assertTrue(d1.configurable);
|
||||||
|
assertFalse(d1.enumerable);
|
||||||
|
|
||||||
|
super[nonEnumNonConfig] = 5;
|
||||||
|
var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig');
|
||||||
|
assertEquals(5, d1.value);
|
||||||
|
assertFalse(d1.configurable);
|
||||||
|
assertFalse(d1.enumerable);
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
|
||||||
|
Derived.prototype.mSloppy = function (){
|
||||||
|
super[nonEnumConfig] = 42;
|
||||||
|
var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig');
|
||||||
|
assertEquals(42, d1.value);
|
||||||
|
assertTrue(d1.configurable);
|
||||||
|
assertFalse(d1.enumerable);
|
||||||
|
|
||||||
|
super[nonEnumNonConfig] = 42;
|
||||||
|
var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig');
|
||||||
|
assertEquals(42, d1.value);
|
||||||
|
assertFalse(d1.configurable);
|
||||||
|
assertFalse(d1.enumerable);
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
|
||||||
|
var d = new Derived();
|
||||||
|
Object.defineProperty(d, 'nonEnumConfig',
|
||||||
|
{ value : 0, enumerable : false, configurable : true, writable : true });
|
||||||
|
Object.defineProperty(d, 'nonEnumNonConfig',
|
||||||
|
{ value : 0, enumerable : false, configurable : false, writable : true });
|
||||||
|
d.mStrict();
|
||||||
|
d.mSloppy();
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
||||||
(function TestCountOperations() {
|
(function TestCountOperations() {
|
||||||
function Base() {}
|
function Base() {}
|
||||||
Base.prototype = {
|
Base.prototype = {
|
||||||
@ -583,6 +988,55 @@
|
|||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
(function TestKeyedCountOperations() {
|
||||||
|
var x = 'x';
|
||||||
|
function Base() {}
|
||||||
|
Base.prototype = {
|
||||||
|
constructor: Base,
|
||||||
|
get x() {
|
||||||
|
return this._x;
|
||||||
|
},
|
||||||
|
set x(v) {
|
||||||
|
this._x = v;
|
||||||
|
},
|
||||||
|
_x: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
function Derived() {}
|
||||||
|
Derived.__proto__ = Base;
|
||||||
|
Derived.prototype = {
|
||||||
|
__proto__: Base.prototype,
|
||||||
|
constructor: Derived,
|
||||||
|
_x: 2
|
||||||
|
};
|
||||||
|
|
||||||
|
Derived.prototype.testCounts = function() {
|
||||||
|
assertEquals(2, this._x);
|
||||||
|
assertEquals(2, super[x]);
|
||||||
|
super[x]++;
|
||||||
|
assertEquals(3, super[x]);
|
||||||
|
++super[x];
|
||||||
|
assertEquals(4, super[x]);
|
||||||
|
assertEquals(4, super[x]++);
|
||||||
|
assertEquals(5, super[x]);
|
||||||
|
assertEquals(6, ++super[x]);
|
||||||
|
assertEquals(6, super[x]);
|
||||||
|
assertEquals(6, this._x);
|
||||||
|
|
||||||
|
super[x]--;
|
||||||
|
assertEquals(5, super[x]);
|
||||||
|
--super[x];
|
||||||
|
assertEquals(4, super[x]);
|
||||||
|
assertEquals(4, super[x]--);
|
||||||
|
assertEquals(3, super[x]);
|
||||||
|
assertEquals(2, --super[x]);
|
||||||
|
assertEquals(2, super[x]);
|
||||||
|
assertEquals(2, this._x);
|
||||||
|
}.toMethod(Derived.prototype);
|
||||||
|
new Derived().testCounts();
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
||||||
(function TestSuperCall() {
|
(function TestSuperCall() {
|
||||||
function Subclass(base, constructor) {
|
function Subclass(base, constructor) {
|
||||||
var homeObject = { __proto__ : base.prototype };
|
var homeObject = { __proto__ : base.prototype };
|
||||||
|
Loading…
Reference in New Issue
Block a user