Support for property assignment in the fast compiler.

The code for .result = (b.y = 99) where b is a global variable is:

  push [esi+0x17]
  mov ecx,0xf5c229ad          ;; object: 0xf5c229ad <String[1]: b>
  call LoadIC_Initialize
  nop
  mov [esp],eax
  mov eax,0xc6
  mov ecx,0xf5c25c41          ;; object: 0xf5c25c41 <String[1]: y>
  call StoreIC_Initialize
  nop
  mov [esp],eax
  pop [ebp+0xf4]

There is still some room for improvement in the generated code.

Other changes:
 - Replaced switch-statement in FastCodeGenerator::VisitProperty with DropAndMove(...)
 - Do not emit nop after IC calls on ARM.

Review URL: http://codereview.chromium.org/347001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3180 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6da43b7e
......@@ -455,14 +455,42 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
// Left-hand side can only be a global or a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL);
ASSERT(var->is_global() || var->slot() != NULL);
// Record the source position for the assignment.
SetSourcePosition(expr->position());
// Left-hand side can only be a property, a global or
// a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
Expression* rhs = expr->value();
Location destination = expr->location();
if (var->is_global()) {
if (var == NULL) {
// Assignment to a property.
ASSERT(expr->target()->AsProperty() != NULL);
Property* prop = expr->target()->AsProperty();
Visit(prop->obj());
Literal* literal_key = prop->key()->AsLiteral();
uint32_t dummy;
if (literal_key != NULL &&
literal_key->handle()->IsSymbol() &&
!String::cast(*(literal_key->handle()))->AsArrayIndex(&dummy)) {
// NAMED property assignment
Visit(rhs);
Move(r0, rhs->location());
__ mov(r2, Operand(literal_key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
} else {
// KEYED property assignment
Visit(prop->key());
Visit(rhs);
Move(r0, rhs->location());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Drop key from the stack
__ pop();
}
// Overwrite the receiver on the stack with the result if needed.
DropAndMove(expr->location(), r0);
} else if (var->is_global()) {
// Assignment to a global variable, use inline caching. Right-hand-side
// value is passed in r0, variable name in r2, and the global object on
// the stack.
......@@ -534,29 +562,15 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
__ mov(r2, Operand(key->AsLiteral()->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test eax,..."
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
} else {
// Do a KEYED property load.
Visit(expr->key());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test eax,..."
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Drop key and receiver left on the stack by IC.
__ pop();
}
switch (expr->location().type()) {
case Location::kUninitialized:
UNREACHABLE();
case Location::kValue:
__ str(r0, MemOperand(sp));
break;
case Location::kEffect:
__ pop();
}
DropAndMove(expr->location(), r0);
}
......
......@@ -741,8 +741,8 @@ void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
void CodeGenSelector::VisitAssignment(Assignment* expr) {
// We support plain non-compound assignments to parameters and
// non-context (stack-allocated) locals.
// We support plain non-compound assignments to properties, parameters and
// non-context (stack-allocated) locals, and global variables.
if (expr->starts_initialization_block() ||
expr->ends_initialization_block()) {
BAILOUT("initialization block start");
......@@ -755,10 +755,14 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
}
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
if (var == NULL) BAILOUT("non-variable assignment");
if (!var->is_global()) {
ASSERT(var->slot() != NULL);
if (var == NULL) {
Property* prop = expr->target()->AsProperty();
if (prop == NULL) BAILOUT("non-variable, non-property assignment");
VisitAsValue(prop->obj());
CHECK_BAILOUT;
VisitAsValue(prop->key());
} else if (!var->is_global()) {
if (var->slot() == NULL) BAILOUT("Assigment with an unsupported LHS.");
Slot::Type type = var->slot()->type();
if (type != Slot::PARAMETER && type != Slot::LOCAL) {
BAILOUT("non-parameter/non-local slot assignment");
......
......@@ -442,13 +442,44 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
// Left-hand side can only be a global or a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL);
ASSERT(var->is_global() || var->slot() != NULL);
// Record the source position for the assignment.
SetSourcePosition(expr->position());
// Left-hand side can only be a property, a global or
// a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
Expression* rhs = expr->value();
if (var->is_global()) {
if (var == NULL) {
// Assignment to a property.
ASSERT(expr->target()->AsProperty() != NULL);
Property* prop = expr->target()->AsProperty();
Visit(prop->obj());
Literal* literal_key = prop->key()->AsLiteral();
uint32_t dummy;
if (literal_key != NULL &&
literal_key->handle()->IsSymbol() &&
!String::cast(*(literal_key->handle()))->AsArrayIndex(&dummy)) {
// NAMED property assignment
Visit(rhs);
Move(eax, rhs->location());
__ mov(ecx, Immediate(literal_key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
__ nop();
} else {
// KEYED property assignment
Visit(prop->key());
Visit(rhs);
Move(eax, rhs->location());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
__ nop();
// Drop key from the stack
__ add(Operand(esp), Immediate(kPointerSize));
}
// Overwrite the receiver on the stack with the result if needed.
DropAndMove(expr->location(), eax);
} else if (var->is_global()) {
// Assignment to a global variable, use inline caching. Right-hand-side
// value is passed in eax, variable name in ecx, and the global object
// on the stack.
......@@ -469,6 +500,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
DropAndMove(expr->location(), eax);
} else {
// Local or parameter assignment.
ASSERT(var->slot() != NULL);
// Code for the right-hand side expression depends on its type.
if (rhs->AsLiteral() != NULL) {
......@@ -509,7 +541,6 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
// Evaluate receiver.
Visit(expr->obj());
if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() &&
!String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) {
// Do a NAMED property load.
......@@ -531,16 +562,7 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
// Drop key left on the stack by IC.
__ add(Operand(esp), Immediate(kPointerSize));
}
switch (expr->location().type()) {
case Location::kUninitialized:
UNREACHABLE();
case Location::kValue:
__ mov(Operand(esp, 0), eax);
break;
case Location::kEffect:
__ add(Operand(esp), Immediate(kPointerSize));
break;
}
DropAndMove(expr->location(), eax);
}
......
......@@ -454,14 +454,44 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
// Left-hand side can only be a global or a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL);
ASSERT(var->is_global() || var->slot() != NULL);
// Record the source position for the assignment.
SetSourcePosition(expr->position());
// Left-hand side can only be a property, a global or
// a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
Expression* rhs = expr->value();
Location destination = expr->location();
if (var->is_global()) {
if (var == NULL) {
// Assignment to a property.
ASSERT(expr->target()->AsProperty() != NULL);
Property* prop = expr->target()->AsProperty();
Visit(prop->obj());
Literal* literal_key = prop->key()->AsLiteral();
uint32_t dummy;
if (literal_key != NULL &&
literal_key->handle()->IsSymbol() &&
!String::cast(*(literal_key->handle()))->AsArrayIndex(&dummy)) {
// NAMED property assignment
Visit(rhs);
Move(rax, rhs->location());
__ Move(rcx, literal_key->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
__ nop();
} else {
// KEYED property assignment
Visit(prop->key());
Visit(rhs);
Move(rax, rhs->location());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
__ nop();
// Drop key from the stack
__ addq(rsp, Immediate(kPointerSize));
}
// Overwrite the receiver on the stack with the result if needed.
DropAndMove(expr->location(), rax);
} else if (var->is_global()) {
// Assignment to a global variable, use inline caching. Right-hand-side
// value is passed in rax, variable name in rcx, and the global object
// on the stack.
......@@ -530,7 +560,7 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
__ Move(rcx, key->AsLiteral()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test eax,..."
// By emitting a nop we make sure that we do not have a "test rax,..."
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
} else {
......@@ -538,22 +568,13 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
Visit(expr->key());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test ..."
// By emitting a nop we make sure that we do not have a "test rax,..."
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Drop key left on the stack by IC.
__ addq(rsp, Immediate(kPointerSize));
}
switch (expr->location().type()) {
case Location::kUninitialized:
UNREACHABLE();
case Location::kValue:
__ movq(Operand(rsp, 0), rax);
break;
case Location::kEffect:
__ addq(rsp, Immediate(kPointerSize));
break;
}
DropAndMove(expr->location(), rax);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment