Refactor the somewhat complicated code generation for assignments into
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Nov 2009 11:01:47 +0000 (11:01 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Nov 2009 11:01:47 +0000 (11:01 +0000)
a platform-independent structure and a few platform-specific helpers
to do the heavy lifting.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3195 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

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

index 967d53e..99f5557 100644 (file)
@@ -572,129 +572,87 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
 }
 
 
-void FastCodeGenerator::VisitAssignment(Assignment* expr) {
-  Comment cmnt(masm_, "[ Assignment");
-  ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
-
-  // 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 == 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);
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      __ pop(r0);
-      __ 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);
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      __ pop(r0);
-      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->context(), r0);
-  } else if (var->is_global()) {
+void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
+                                               Variable* var) {
+  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.
-
-    // Code for the right-hand-side expression depends on its type.
-    if (rhs->AsLiteral() != NULL) {
-      __ mov(r0, Operand(rhs->AsLiteral()->handle()));
-    } else {
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      Visit(rhs);
-      __ pop(r0);
-    }
+    // value is passed in r0, variable name in r2, and the global object
+    // on the stack.
+    __ pop(r0);
     __ mov(r2, Operand(var->name()));
     __ ldr(ip, CodeGenerator::GlobalObject());
     __ push(ip);
     Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
     __ Call(ic, RelocInfo::CODE_TARGET);
     // Overwrite the global object on the stack with the result if needed.
-    DropAndMove(expr->context(), r0);
+    DropAndMove(context, r0);
   } else {
-    // Local or parameter assignment.
-
-    // Code for the right-hand side expression depends on its type.
-    if (rhs->AsLiteral() != NULL) {
-      // Two cases: 'temp <- (var = constant)', or 'var = constant' with a
-      // discarded result.  Always perform the assignment.
-      __ mov(ip, Operand(rhs->AsLiteral()->handle()));
-      __ str(ip, MemOperand(fp, SlotOffset(var->slot())));
-      Move(expr->context(), ip);
-    } else {
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      Visit(rhs);
-      // Load right-hand side into ip.
-      switch (expr->context()) {
-        case Expression::kUninitialized:
-          UNREACHABLE();
-        case Expression::kEffect:
-          // Case 'var = temp'.  Discard right-hand-side temporary.
-          __ pop(r0);
-          __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
-          break;
-        case Expression::kValue:
-          // Case 'temp1 <- (var = temp0)'.  Preserve right-hand-side
-          // temporary on the stack.
-          __ ldr(r0, MemOperand(sp));
-          __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
-          break;
-        case Expression::kTest:
-          // Case 'if (var = temp) ...'.
-          __ pop(r0);
-          __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
-          TestAndBranch(r0, true_label_, false_label_);
-          break;
-        case Expression::kValueTest: {
-          // Case '(var = temp) || ...' in value context.
-          Label discard;
-          __ ldr(r0, MemOperand(sp));
-          __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
-          TestAndBranch(r0, true_label_, &discard);
-          __ bind(&discard);
-          __ pop();
-          __ jmp(false_label_);
-          break;
-        }
-        case Expression::kTestValue: {
-          // Case '(var = temp) && ...' in value context.
-          Label discard;
-          __ ldr(r0, MemOperand(sp));
-          __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
-          TestAndBranch(r0, &discard, false_label_);
-          __ bind(&discard);
-          __ pop();
-          __ jmp(true_label_);
-          break;
-        }
+    switch (context) {
+      case Expression::kUninitialized:
+        UNREACHABLE();
+      case Expression::kEffect:
+        // Perform assignment and discard value.
+        __ pop(r0);
+        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+        break;
+      case Expression::kValue:
+        // Perform assignment and preserve value.
+        __ ldr(r0, MemOperand(sp));
+        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+        break;
+      case Expression::kTest:
+        // Perform assignment and test (and discard) value.
+        __ pop(r0);
+        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+        TestAndBranch(r0, true_label_, false_label_);
+        break;
+      case Expression::kValueTest: {
+        Label discard;
+        __ ldr(r0, MemOperand(sp));
+        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+        TestAndBranch(r0, true_label_, &discard);
+        __ bind(&discard);
+        __ pop();
+        __ jmp(false_label_);
+        break;
+      }
+      case Expression::kTestValue: {
+        Label discard;
+        __ ldr(r0, MemOperand(sp));
+        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+        TestAndBranch(r0, &discard, false_label_);
+        __ bind(&discard);
+        __ pop();
+        __ jmp(true_label_);
+        break;
       }
     }
   }
 }
 
 
+void FastCodeGenerator::EmitNamedPropertyAssignment(
+    Expression::Context context,
+    Handle<Object> name) {
+  __ pop(r0);
+  __ mov(r2, Operand(name));
+  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+  __ Call(ic, RelocInfo::CODE_TARGET);
+  DropAndMove(context, r0);
+}
+
+
+void FastCodeGenerator::EmitKeyedPropertyAssignment(
+    Expression::Context context) {
+  __ pop(r0);
+  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+  __ Call(ic, RelocInfo::CODE_TARGET);
+  // Receiver and key are still on stack.
+  __ add(sp, sp, Operand(2 * kPointerSize));
+  Move(context, r0);
+}
+
+
 void FastCodeGenerator::VisitProperty(Property* expr) {
   Comment cmnt(masm_, "[ Property");
   Expression* key = expr->key();
index e9db632..86bf160 100644 (file)
@@ -736,18 +736,36 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
   }
 
   Variable* var = expr->target()->AsVariableProxy()->AsVariable();
-  if (var == NULL) {
-    Property* prop = expr->target()->AsProperty();
-    if (prop == NULL) BAILOUT("non-variable, non-property assignment");
+  Property* prop = expr->target()->AsProperty();
+  if (var != NULL) {
+    // All global variables are supported.
+    if (!var->is_global()) {
+      if (var->slot() == NULL) {
+        // This is a parameter that has rewritten to an arguments access.
+        BAILOUT("non-global/non-slot assignment");
+      }
+      Slot::Type type = var->slot()->type();
+      if (type != Slot::PARAMETER && type != Slot::LOCAL) {
+        BAILOUT("non-parameter/non-local slot assignment");
+      }
+    }
+  } else if (prop != NULL) {
     ProcessExpression(prop->obj(), Expression::kValue);
     CHECK_BAILOUT;
-    ProcessExpression(prop->key(), Expression::kValue);
-  } 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");
+    // We will only visit the key during code generation for keyed property
+    // stores.  Leave its expression context uninitialized for named
+    // property stores.
+    Literal* lit = prop->key()->AsLiteral();
+    uint32_t ignored;
+    if (lit == NULL ||
+        !lit->handle()->IsSymbol() ||
+        String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
+      ProcessExpression(prop->key(), Expression::kValue);
+      CHECK_BAILOUT;
     }
+  } else {
+    // This is a throw reference error.
+    BAILOUT("non-variable/non-property assignment");
   }
 
   ProcessExpression(expr->value(), Expression::kValue);
index 615821f..1d12a0d 100644 (file)
@@ -424,6 +424,47 @@ void FastCodeGenerator::VisitLiteral(Literal* expr) {
 }
 
 
+void FastCodeGenerator::VisitAssignment(Assignment* expr) {
+  Comment cmnt(masm_, "[ Assignment");
+  ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
+
+  // Record source code position of the (possible) IC call.
+  SetSourcePosition(expr->position());
+
+  Expression* rhs = expr->value();
+  // Left-hand side can only be a property, a global or a (parameter or
+  // local) slot.
+  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+  Property* prop = expr->target()->AsProperty();
+  if (var != NULL) {
+    Visit(rhs);
+    ASSERT_EQ(Expression::kValue, rhs->context());
+    EmitVariableAssignment(expr->context(), var);
+  } else if (prop != NULL) {
+    // Assignment to a property.
+    Visit(prop->obj());
+    ASSERT_EQ(Expression::kValue, prop->obj()->context());
+    // Use the expression context of the key subexpression to detect whether
+    // we have decided to us a named or keyed IC.
+    if (prop->key()->context() == Expression::kUninitialized) {
+      ASSERT(prop->key()->AsLiteral() != NULL);
+      Visit(rhs);
+      ASSERT_EQ(Expression::kValue, rhs->context());
+      EmitNamedPropertyAssignment(expr->context(),
+                                  prop->key()->AsLiteral()->handle());
+    } else {
+      Visit(prop->key());
+      ASSERT_EQ(Expression::kValue, prop->key()->context());
+      Visit(rhs);
+      ASSERT_EQ(Expression::kValue, rhs->context());
+      EmitKeyedPropertyAssignment(expr->context());
+    }
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
 void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
   UNREACHABLE();
 }
index f0ea85d..319bb2f 100644 (file)
@@ -75,6 +75,21 @@ class FastCodeGenerator: public AstVisitor {
   void EmitCallWithStub(Call* expr);
   void EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info);
 
+  // Platform-specific support for compiling assignments.
+
+  // Complete a variable assignment.  The right-hand-side value are expected
+  // on top of the stack.
+  void EmitVariableAssignment(Expression::Context context, Variable* var);
+
+  // Complete a named property assignment.  The receiver and right-hand-side
+  // value are expected on top of the stack.
+  void EmitNamedPropertyAssignment(Expression::Context context,
+                                   Handle<Object> name);
+
+  // Complete a keyed property assignment.  The reciever, key, and
+  // right-hand-side value are expected on top of the stack.
+  void EmitKeyedPropertyAssignment(Expression::Context context);
+
   void SetFunctionPosition(FunctionLiteral* fun);
   void SetReturnPosition(FunctionLiteral* fun);
   void SetStatementPosition(Statement* stmt);
index 9225934..851f733 100644 (file)
@@ -586,131 +586,88 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
 }
 
 
-void FastCodeGenerator::VisitAssignment(Assignment* expr) {
-  Comment cmnt(masm_, "[ Assignment");
-  ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
-
-  // 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 == 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);
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      __ pop(eax);
-      __ 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);
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      __ pop(eax);
-      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->context(), eax);
-  } else if (var->is_global()) {
+void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
+                                               Variable* var) {
+  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.
-
-    // Code for the right-hand-side expression depends on its type.
-    if (rhs->AsLiteral() != NULL) {
-      __ mov(eax, rhs->AsLiteral()->handle());
-    } else {
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      Visit(rhs);
-      __ pop(eax);
-    }
-    // Record position for debugger.
-    SetSourcePosition(expr->position());
+    __ pop(eax);
     __ mov(ecx, var->name());
     __ push(CodeGenerator::GlobalObject());
     Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
     __ call(ic, RelocInfo::CODE_TARGET);
     // Overwrite the global object on the stack with the result if needed.
-    DropAndMove(expr->context(), eax);
+    DropAndMove(context, 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) {
-      // Two cases: 'temp <- (var = constant)', or 'var = constant' with a
-      // discarded result.  Always perform the assignment.
-      __ mov(eax, rhs->AsLiteral()->handle());
-      __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
-      Move(expr->context(), eax);
-    } else {
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      Visit(rhs);
-      switch (expr->context()) {
-        case Expression::kUninitialized:
-          UNREACHABLE();
-        case Expression::kEffect:
-          // Case 'var = temp'.  Discard right-hand-side temporary.
-          __ pop(Operand(ebp, SlotOffset(var->slot())));
-          break;
-        case Expression::kValue:
-          // Case 'temp1 <- (var = temp0)'.  Preserve right-hand-side
-          // temporary on the stack.
-          __ mov(eax, Operand(esp, 0));
-          __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
-          break;
-        case Expression::kTest:
-          // Case 'if (var = temp) ...'.
-          __ pop(eax);
-          __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
-          TestAndBranch(eax, true_label_, false_label_);
-          break;
-        case Expression::kValueTest: {
-          // Case '(var = temp) || ...' in value context.
-          Label discard;
-          __ mov(eax, Operand(esp, 0));
-          __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
-          TestAndBranch(eax, true_label_, &discard);
-          __ bind(&discard);
-          __ add(Operand(esp), Immediate(kPointerSize));
-          __ jmp(false_label_);
-          break;
-        }
-        case Expression::kTestValue: {
-          // Case '(var = temp) && ...' in value context.
-          Label discard;
-          __ mov(eax, Operand(esp, 0));
-          __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
-          TestAndBranch(eax, &discard, false_label_);
-          __ bind(&discard);
-          __ add(Operand(esp), Immediate(kPointerSize));
-          __ jmp(true_label_);
-          break;
-        }
+    switch (context) {
+      case Expression::kUninitialized:
+        UNREACHABLE();
+      case Expression::kEffect:
+        // Perform assignment and discard value.
+        __ pop(Operand(ebp, SlotOffset(var->slot())));
+        break;
+      case Expression::kValue:
+        // Perform assignment and preserve value.
+        __ mov(eax, Operand(esp, 0));
+        __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+        break;
+      case Expression::kTest:
+        // Perform assignment and test (and discard) value.
+        __ pop(eax);
+        __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+        TestAndBranch(eax, true_label_, false_label_);
+        break;
+      case Expression::kValueTest: {
+        Label discard;
+        __ mov(eax, Operand(esp, 0));
+        __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+        TestAndBranch(eax, true_label_, &discard);
+        __ bind(&discard);
+        __ add(Operand(esp), Immediate(kPointerSize));
+        __ jmp(false_label_);
+        break;
+      }
+      case Expression::kTestValue: {
+        Label discard;
+        __ mov(eax, Operand(esp, 0));
+        __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+        TestAndBranch(eax, &discard, false_label_);
+        __ bind(&discard);
+        __ add(Operand(esp), Immediate(kPointerSize));
+        __ jmp(true_label_);
+        break;
       }
     }
   }
 }
 
 
+void FastCodeGenerator::EmitNamedPropertyAssignment(
+    Expression::Context context,
+    Handle<Object> name) {
+  __ pop(eax);
+  __ mov(ecx, name);
+  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+  __ call(ic, RelocInfo::CODE_TARGET);
+  DropAndMove(context, eax);
+}
+
+
+void FastCodeGenerator::EmitKeyedPropertyAssignment(
+    Expression::Context context) {
+  __ pop(eax);
+  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+  __ call(ic, RelocInfo::CODE_TARGET);
+  // This nop signals to the IC that there is no inlined code at the call
+  // site for it to patch.
+  __ nop();
+  // Receiver and key are still on stack.
+  __ add(Operand(esp), Immediate(2 * kPointerSize));
+  Move(context, eax);
+}
+
+
 void FastCodeGenerator::VisitProperty(Property* expr) {
   Comment cmnt(masm_, "[ Property");
   Expression* key = expr->key();
index d9cfa29..5592d08 100644 (file)
@@ -600,130 +600,88 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
 }
 
 
-void FastCodeGenerator::VisitAssignment(Assignment* expr) {
-  Comment cmnt(masm_, "[ Assignment");
-  ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
-
-  // 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 == 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);
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      __ pop(rax);
-      __ 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);
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      __ pop(rax);
-      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->context(), rax);
-  } else if (var->is_global()) {
+void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
+                                               Variable* var) {
+  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.
-
-    // Code for the right-hand-side expression depends on its type.
-    if (rhs->AsLiteral() != NULL) {
-      __ Move(rax, rhs->AsLiteral()->handle());
-    } else {
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      Visit(rhs);
-      __ pop(rax);
-    }
-    // Record position for debugger.
-    SetSourcePosition(expr->position());
+    __ pop(rax);
     __ Move(rcx, var->name());
     __ push(CodeGenerator::GlobalObject());
     Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
     __ Call(ic, RelocInfo::CODE_TARGET);
     // Overwrite the global object on the stack with the result if needed.
-    DropAndMove(expr->context(), rax);
+    DropAndMove(context, rax);
   } else {
-    // Local or parameter assignment.
-
-    // Code for the right-hand-side expression depends on its type.
-    if (rhs->AsLiteral() != NULL) {
-      // Two cases: 'temp <- (var = constant)', or 'var = constant' with a
-      // discarded result.  Always perform the assignment.
-      __ Move(kScratchRegister, rhs->AsLiteral()->handle());
-      __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
-      Move(expr->context(), kScratchRegister);
-    } else {
-      ASSERT_EQ(Expression::kValue, rhs->context());
-      Visit(rhs);
-      switch (expr->context()) {
-        case Expression::kUninitialized:
-          UNREACHABLE();
-        case Expression::kEffect:
-          // Case 'var = temp'.  Discard right-hand-side temporary.
-          __ pop(Operand(rbp, SlotOffset(var->slot())));
-          break;
-        case Expression::kValue:
-          // Case 'temp1 <- (var = temp0)'.  Preserve right-hand-side
-          // temporary on the stack.
-          __ movq(kScratchRegister, Operand(rsp, 0));
-          __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
-          break;
-        case Expression::kTest:
-          // Case 'if (var = temp) ...'.
-          __ pop(rax);
-          __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
-          TestAndBranch(rax, true_label_, false_label_);
-          break;
-        case Expression::kValueTest: {
-          // Case '(var = temp) || ...' in value context.
-          Label discard;
-          __ movq(rax, Operand(rsp, 0));
-          __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
-          TestAndBranch(rax, true_label_, &discard);
-          __ bind(&discard);
-          __ addq(rsp, Immediate(kPointerSize));
-          __ jmp(false_label_);
-          break;
-        }
-        case Expression::kTestValue: {
-          // Case '(var = temp) && ...' in value context.
-          Label discard;
-          __ movq(rax, Operand(rsp, 0));
-          __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
-          TestAndBranch(rax, &discard, false_label_);
-          __ bind(&discard);
-          __ addq(rsp, Immediate(kPointerSize));
-          __ jmp(true_label_);
-          break;
-        }
+    switch (context) {
+      case Expression::kUninitialized:
+        UNREACHABLE();
+      case Expression::kEffect:
+        // Perform assignment and discard value.
+        __ pop(Operand(rbp, SlotOffset(var->slot())));
+        break;
+      case Expression::kValue:
+        // Perform assignment and preserve value.
+        __ movq(rax, Operand(rsp, 0));
+        __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
+        break;
+      case Expression::kTest:
+        // Perform assignment and test (and discard) value.
+        __ pop(rax);
+        __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
+        TestAndBranch(rax, true_label_, false_label_);
+        break;
+      case Expression::kValueTest: {
+        Label discard;
+        __ movq(rax, Operand(rsp, 0));
+        __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
+        TestAndBranch(rax, true_label_, &discard);
+        __ bind(&discard);
+        __ addq(rsp, Immediate(kPointerSize));
+        __ jmp(false_label_);
+        break;
+      }
+      case Expression::kTestValue: {
+        Label discard;
+        __ movq(rax, Operand(rsp, 0));
+        __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
+        TestAndBranch(rax, &discard, false_label_);
+        __ bind(&discard);
+        __ addq(rsp, Immediate(kPointerSize));
+        __ jmp(true_label_);
+        break;
       }
     }
   }
 }
 
 
+void FastCodeGenerator::EmitNamedPropertyAssignment(
+    Expression::Context context,
+    Handle<Object> name) {
+  __ pop(rax);
+  __ Move(rcx, name);
+  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+  __ Call(ic, RelocInfo::CODE_TARGET);
+  DropAndMove(context, rax);
+}
+
+
+void FastCodeGenerator::EmitKeyedPropertyAssignment(
+    Expression::Context context) {
+  __ pop(rax);
+  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+  __ Call(ic, RelocInfo::CODE_TARGET);
+  // This nop signals to the IC that there is no inlined code at the call
+  // site for it to patch.
+  __ nop();
+  // Receiver and key are still on stack.
+  __ addq(rsp, Immediate(2 * kPointerSize));
+  Move(context, rax);
+}
+
+
 void FastCodeGenerator::VisitProperty(Property* expr) {
   Comment cmnt(masm_, "[ Property");
   Expression* key = expr->key();