From 143b4b87b4792e329f69e6f322cec6244e6a48ea Mon Sep 17 00:00:00 2001 From: "fschneider@chromium.org" Date: Fri, 30 Oct 2009 07:56:38 +0000 Subject: [PATCH] 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 call LoadIC_Initialize nop mov [esp],eax mov eax,0xc6 mov ecx,0xf5c25c41 ;; object: 0xf5c25c41 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 | 56 ++++++++++++++++++++++++++---------------- src/compiler.cc | 16 +++++++----- src/ia32/fast-codegen-ia32.cc | 54 ++++++++++++++++++++++++++++------------ src/x64/fast-codegen-x64.cc | 57 +++++++++++++++++++++++++++++-------------- 4 files changed, 122 insertions(+), 61 deletions(-) diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index 6540d40..4b72e8a 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -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 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 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 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 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); } diff --git a/src/compiler.cc b/src/compiler.cc index 129f1aa..77a97ad 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -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"); diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc index 247f124..6ad2b75 100644 --- a/src/ia32/fast-codegen-ia32.cc +++ b/src/ia32/fast-codegen-ia32.cc @@ -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 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 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); } diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc index b938119..d46cb2b 100644 --- a/src/x64/fast-codegen-x64.cc +++ b/src/x64/fast-codegen-x64.cc @@ -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 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 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 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 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); } -- 2.7.4