From: kmillikin@chromium.org Date: Mon, 2 Nov 2009 11:01:47 +0000 (+0000) Subject: Refactor the somewhat complicated code generation for assignments into X-Git-Tag: upstream/4.7.83~23030 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b710d66f392fccac6493f66f06abeaae6b53045e;p=platform%2Fupstream%2Fv8.git Refactor the somewhat complicated code generation for assignments into 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 --- diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index 967d53e9a..99f55573f 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -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 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 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 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 name) { + __ pop(r0); + __ mov(r2, Operand(name)); + Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + DropAndMove(context, r0); +} + + +void FastCodeGenerator::EmitKeyedPropertyAssignment( + Expression::Context context) { + __ pop(r0); + Handle 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(); diff --git a/src/compiler.cc b/src/compiler.cc index e9db632db..86bf160e1 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -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); diff --git a/src/fast-codegen.cc b/src/fast-codegen.cc index 615821fc2..1d12a0ddf 100644 --- a/src/fast-codegen.cc +++ b/src/fast-codegen.cc @@ -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(); } diff --git a/src/fast-codegen.h b/src/fast-codegen.h index f0ea85d60..319bb2f04 100644 --- a/src/fast-codegen.h +++ b/src/fast-codegen.h @@ -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 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); diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc index 9225934ae..851f733f2 100644 --- a/src/ia32/fast-codegen-ia32.cc +++ b/src/ia32/fast-codegen-ia32.cc @@ -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 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 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 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 name) { + __ pop(eax); + __ mov(ecx, name); + Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + __ call(ic, RelocInfo::CODE_TARGET); + DropAndMove(context, eax); +} + + +void FastCodeGenerator::EmitKeyedPropertyAssignment( + Expression::Context context) { + __ pop(eax); + Handle 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(); diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc index d9cfa299c..5592d0893 100644 --- a/src/x64/fast-codegen-x64.cc +++ b/src/x64/fast-codegen-x64.cc @@ -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 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 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 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 name) { + __ pop(rax); + __ Move(rcx, name); + Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + DropAndMove(context, rax); +} + + +void FastCodeGenerator::EmitKeyedPropertyAssignment( + Expression::Context context) { + __ pop(rax); + Handle 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();