Support for property assignment in the fast compiler.
authorfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 30 Oct 2009 07:56:38 +0000 (07:56 +0000)
committerfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 30 Oct 2009 07:56:38 +0000 (07:56 +0000)
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

src/arm/fast-codegen-arm.cc
src/compiler.cc
src/ia32/fast-codegen-ia32.cc
src/x64/fast-codegen-x64.cc

index 6540d40165a04d37ff269b4f4c9875911b740688..4b72e8a769f69930a634622e6f69ec87e86dab78 100644 (file)
@@ -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);
 }
 
 
index 129f1aac15094ea0532d7e316c6a28019beac337..77a97adca991de4f4113a8586e9ba3f1644c0a7d 100644 (file)
@@ -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");
index 247f124962874006b12ab4706e6a215f779a8288..6ad2b75fccb85bc88e5c53beb8a55afb86cdeabc 100644 (file)
@@ -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);
 }
 
 
index b938119cd3f638f63ad563e023c286a48409a4ff..d46cb2bd834a2f78bbd737624a7e4e450de0df36 100644 (file)
@@ -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);
 }