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) { ...@@ -455,14 +455,42 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
// Left-hand side can only be a global or a (parameter or local) slot. // Record the source position for the assignment.
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); SetSourcePosition(expr->position());
ASSERT(var != NULL);
ASSERT(var->is_global() || var->slot() != NULL);
// 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(); Expression* rhs = expr->value();
Location destination = expr->location(); if (var == NULL) {
if (var->is_global()) { // 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 // 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 // value is passed in r0, variable name in r2, and the global object on
// the stack. // the stack.
...@@ -534,29 +562,15 @@ void FastCodeGenerator::VisitProperty(Property* expr) { ...@@ -534,29 +562,15 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
__ mov(r2, Operand(key->AsLiteral()->handle())); __ mov(r2, Operand(key->AsLiteral()->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ 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 { } else {
// Do a KEYED property load. // Do a KEYED property load.
Visit(expr->key()); Visit(expr->key());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ 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. // Drop key and receiver left on the stack by IC.
__ pop(); __ pop();
} }
switch (expr->location().type()) { DropAndMove(expr->location(), r0);
case Location::kUninitialized:
UNREACHABLE();
case Location::kValue:
__ str(r0, MemOperand(sp));
break;
case Location::kEffect:
__ pop();
}
} }
......
...@@ -741,8 +741,8 @@ void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) { ...@@ -741,8 +741,8 @@ void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
void CodeGenSelector::VisitAssignment(Assignment* expr) { void CodeGenSelector::VisitAssignment(Assignment* expr) {
// We support plain non-compound assignments to parameters and // We support plain non-compound assignments to properties, parameters and
// non-context (stack-allocated) locals. // non-context (stack-allocated) locals, and global variables.
if (expr->starts_initialization_block() || if (expr->starts_initialization_block() ||
expr->ends_initialization_block()) { expr->ends_initialization_block()) {
BAILOUT("initialization block start"); BAILOUT("initialization block start");
...@@ -755,10 +755,14 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) { ...@@ -755,10 +755,14 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
} }
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); Variable* var = expr->target()->AsVariableProxy()->AsVariable();
if (var == NULL) BAILOUT("non-variable assignment"); if (var == NULL) {
Property* prop = expr->target()->AsProperty();
if (!var->is_global()) { if (prop == NULL) BAILOUT("non-variable, non-property assignment");
ASSERT(var->slot() != NULL); 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(); Slot::Type type = var->slot()->type();
if (type != Slot::PARAMETER && type != Slot::LOCAL) { if (type != Slot::PARAMETER && type != Slot::LOCAL) {
BAILOUT("non-parameter/non-local slot assignment"); BAILOUT("non-parameter/non-local slot assignment");
......
...@@ -442,13 +442,44 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -442,13 +442,44 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
// Left-hand side can only be a global or a (parameter or local) slot. // Record the source position for the assignment.
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); SetSourcePosition(expr->position());
ASSERT(var != NULL);
ASSERT(var->is_global() || var->slot() != NULL);
// 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(); 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 // Assignment to a global variable, use inline caching. Right-hand-side
// value is passed in eax, variable name in ecx, and the global object // value is passed in eax, variable name in ecx, and the global object
// on the stack. // on the stack.
...@@ -469,6 +500,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -469,6 +500,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
DropAndMove(expr->location(), eax); DropAndMove(expr->location(), eax);
} else { } else {
// Local or parameter assignment. // Local or parameter assignment.
ASSERT(var->slot() != NULL);
// Code for the right-hand side expression depends on its type. // Code for the right-hand side expression depends on its type.
if (rhs->AsLiteral() != NULL) { if (rhs->AsLiteral() != NULL) {
...@@ -509,7 +541,6 @@ void FastCodeGenerator::VisitProperty(Property* expr) { ...@@ -509,7 +541,6 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
// Evaluate receiver. // Evaluate receiver.
Visit(expr->obj()); Visit(expr->obj());
if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() && if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() &&
!String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) { !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) {
// Do a NAMED property load. // Do a NAMED property load.
...@@ -531,16 +562,7 @@ void FastCodeGenerator::VisitProperty(Property* expr) { ...@@ -531,16 +562,7 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
// Drop key left on the stack by IC. // Drop key left on the stack by IC.
__ add(Operand(esp), Immediate(kPointerSize)); __ add(Operand(esp), Immediate(kPointerSize));
} }
switch (expr->location().type()) { DropAndMove(expr->location(), eax);
case Location::kUninitialized:
UNREACHABLE();
case Location::kValue:
__ mov(Operand(esp, 0), eax);
break;
case Location::kEffect:
__ add(Operand(esp), Immediate(kPointerSize));
break;
}
} }
......
...@@ -454,14 +454,44 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -454,14 +454,44 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
// Left-hand side can only be a global or a (parameter or local) slot. // Record the source position for the assignment.
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); SetSourcePosition(expr->position());
ASSERT(var != NULL);
ASSERT(var->is_global() || var->slot() != NULL);
// 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(); Expression* rhs = expr->value();
Location destination = expr->location(); if (var == NULL) {
if (var->is_global()) { // 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 // Assignment to a global variable, use inline caching. Right-hand-side
// value is passed in rax, variable name in rcx, and the global object // value is passed in rax, variable name in rcx, and the global object
// on the stack. // on the stack.
...@@ -530,7 +560,7 @@ void FastCodeGenerator::VisitProperty(Property* expr) { ...@@ -530,7 +560,7 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
__ Move(rcx, key->AsLiteral()->handle()); __ Move(rcx, key->AsLiteral()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ 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. // instruction after the call it is treated specially by the LoadIC code.
__ nop(); __ nop();
} else { } else {
...@@ -538,22 +568,13 @@ void FastCodeGenerator::VisitProperty(Property* expr) { ...@@ -538,22 +568,13 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
Visit(expr->key()); Visit(expr->key());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ 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. // instruction after the call it is treated specially by the LoadIC code.
__ nop(); __ nop();
// Drop key left on the stack by IC. // Drop key left on the stack by IC.
__ addq(rsp, Immediate(kPointerSize)); __ addq(rsp, Immediate(kPointerSize));
} }
switch (expr->location().type()) { DropAndMove(expr->location(), rax);
case Location::kUninitialized:
UNREACHABLE();
case Location::kValue:
__ movq(Operand(rsp, 0), rax);
break;
case Location::kEffect:
__ addq(rsp, Immediate(kPointerSize));
break;
}
} }
......
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