From: kmillikin@chromium.org Date: Mon, 2 Nov 2009 13:30:24 +0000 (+0000) Subject: Add support for initialization block assignments in the toplevel code X-Git-Tag: upstream/4.7.83~23027 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=aa3b00a25ae42f302c5ad79a9a1484789c3ed5b4;p=platform%2Fupstream%2Fv8.git Add support for initialization block assignments in the toplevel code generator, mimicing the behavior of the optimizing compiler. Initialization blocks can only contain (thus begin and end) with a property assignment in toplevel code. Review URL: http://codereview.chromium.org/348038 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3198 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index 2bf2659a9..d410a50e4 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -572,12 +572,14 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } -void FastCodeGenerator::EmitVariableAssignment(Expression::Context context, - Variable* var) { +void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { + Variable* var = expr->target()->AsVariableProxy()->AsVariable(); + ASSERT(var != NULL); + 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. + // Assignment to a global variable. Use inline caching for the + // assignment. Right-hand-side 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()); @@ -585,9 +587,10 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context, 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(context, r0); + DropAndMove(expr->context(), r0); + } else { - switch (context) { + switch (expr->context()) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: @@ -631,25 +634,69 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context, } -void FastCodeGenerator::EmitNamedPropertyAssignment( - Expression::Context context, - Handle name) { +void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { + // Assignment to a property, using a named store IC. + Property* prop = expr->target()->AsProperty(); + ASSERT(prop != NULL); + ASSERT(prop->key()->AsLiteral() != NULL); + + // If the assignment starts a block of assignments to the same object, + // change to slow case to avoid the quadratic behavior of repeatedly + // adding fast properties. + if (expr->starts_initialization_block()) { + __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is under value. + __ push(ip); + __ CallRuntime(Runtime::kToSlowProperties, 1); + } + __ pop(r0); - __ mov(r2, Operand(name)); + __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); __ Call(ic, RelocInfo::CODE_TARGET); - DropAndMove(context, r0); + + // If the assignment ends an initialization block, revert to fast case. + if (expr->ends_initialization_block()) { + __ push(r0); // Result of assignment, saved even if not needed. + __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is under value. + __ push(ip); + __ CallRuntime(Runtime::kToFastProperties, 1); + __ pop(r0); + } + + DropAndMove(expr->context(), r0); } -void FastCodeGenerator::EmitKeyedPropertyAssignment( - Expression::Context context) { +void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { + // Assignment to a property, using a keyed store IC. + + // If the assignment starts a block of assignments to the same object, + // change to slow case to avoid the quadratic behavior of repeatedly + // adding fast properties. + if (expr->starts_initialization_block()) { + // Reciever is under the key and value. + __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); + __ push(ip); + __ CallRuntime(Runtime::kToSlowProperties, 1); + } + __ pop(r0); Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); __ Call(ic, RelocInfo::CODE_TARGET); + + // If the assignment ends an initialization block, revert to fast case. + if (expr->ends_initialization_block()) { + __ push(r0); // Result of assignment, saved even if not needed. + // Reciever is under the key and value. + __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); + __ push(ip); + __ CallRuntime(Runtime::kToFastProperties, 1); + __ pop(r0); + } + // Receiver and key are still on stack. __ add(sp, sp, Operand(2 * kPointerSize)); - Move(context, r0); + Move(expr->context(), r0); } diff --git a/src/compiler.cc b/src/compiler.cc index 2526ad766..fc5ffe1ad 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -724,11 +724,6 @@ void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) { void CodeGenSelector::VisitAssignment(Assignment* expr) { // 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"); - } - Token::Value op = expr->op(); if (op == Token::INIT_CONST) BAILOUT("initialize constant"); if (op != Token::ASSIGN && op != Token::INIT_VAR) { diff --git a/src/fast-codegen.cc b/src/fast-codegen.cc index 1d12a0ddf..76d51c06c 100644 --- a/src/fast-codegen.cc +++ b/src/fast-codegen.cc @@ -439,7 +439,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { if (var != NULL) { Visit(rhs); ASSERT_EQ(Expression::kValue, rhs->context()); - EmitVariableAssignment(expr->context(), var); + EmitVariableAssignment(expr); } else if (prop != NULL) { // Assignment to a property. Visit(prop->obj()); @@ -450,14 +450,13 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { ASSERT(prop->key()->AsLiteral() != NULL); Visit(rhs); ASSERT_EQ(Expression::kValue, rhs->context()); - EmitNamedPropertyAssignment(expr->context(), - prop->key()->AsLiteral()->handle()); + EmitNamedPropertyAssignment(expr); } else { Visit(prop->key()); ASSERT_EQ(Expression::kValue, prop->key()->context()); Visit(rhs); ASSERT_EQ(Expression::kValue, rhs->context()); - EmitKeyedPropertyAssignment(expr->context()); + EmitKeyedPropertyAssignment(expr); } } else { UNREACHABLE(); diff --git a/src/fast-codegen.h b/src/fast-codegen.h index 319bb2f04..92af19ebd 100644 --- a/src/fast-codegen.h +++ b/src/fast-codegen.h @@ -77,18 +77,17 @@ class FastCodeGenerator: public AstVisitor { // Platform-specific support for compiling assignments. - // Complete a variable assignment. The right-hand-side value are expected + // Complete a variable assignment. The right-hand-side value is expected // on top of the stack. - void EmitVariableAssignment(Expression::Context context, Variable* var); + void EmitVariableAssignment(Assignment* expr); // 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); + void EmitNamedPropertyAssignment(Assignment* expr); // 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 EmitKeyedPropertyAssignment(Assignment* expr); void SetFunctionPosition(FunctionLiteral* fun); void SetReturnPosition(FunctionLiteral* fun); diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc index a234ae1e2..e049dba23 100644 --- a/src/ia32/fast-codegen-ia32.cc +++ b/src/ia32/fast-codegen-ia32.cc @@ -586,21 +586,24 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } -void FastCodeGenerator::EmitVariableAssignment(Expression::Context context, - Variable* var) { +void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { + Variable* var = expr->target()->AsVariableProxy()->AsVariable(); + ASSERT(var != NULL); + 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. + // Assignment to a global variable. Use inline caching for the + // assignment. Right-hand-side value is passed in eax, variable name in + // ecx, and the global object on the stack. __ 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(context, eax); + // Overwrite the receiver on the stack with the result if needed. + DropAndMove(expr->context(), eax); + } else { - switch (context) { + switch (expr->context()) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: @@ -643,28 +646,68 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context, } -void FastCodeGenerator::EmitNamedPropertyAssignment( - Expression::Context context, - Handle name) { +void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { + // Assignment to a property, using a named store IC. + Property* prop = expr->target()->AsProperty(); + ASSERT(prop != NULL); + ASSERT(prop->key()->AsLiteral() != NULL); + + // If the assignment starts a block of assignments to the same object, + // change to slow case to avoid the quadratic behavior of repeatedly + // adding fast properties. + if (expr->starts_initialization_block()) { + __ push(Operand(esp, kPointerSize)); // Receiver is under value. + __ CallRuntime(Runtime::kToSlowProperties, 1); + } + __ pop(eax); - __ mov(ecx, name); + __ mov(ecx, prop->key()->AsLiteral()->handle()); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); __ call(ic, RelocInfo::CODE_TARGET); - DropAndMove(context, eax); + + // If the assignment ends an initialization block, revert to fast case. + if (expr->ends_initialization_block()) { + __ push(eax); // Result of assignment, saved even if not needed. + __ push(Operand(esp, kPointerSize)); // Receiver is under value. + __ CallRuntime(Runtime::kToFastProperties, 1); + __ pop(eax); + } + + DropAndMove(expr->context(), eax); } -void FastCodeGenerator::EmitKeyedPropertyAssignment( - Expression::Context context) { +void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { + // Assignment to a property, using a keyed store IC. + + // If the assignment starts a block of assignments to the same object, + // change to slow case to avoid the quadratic behavior of repeatedly + // adding fast properties. + if (expr->starts_initialization_block()) { + // Reciever is under the key and value. + __ push(Operand(esp, 2 * kPointerSize)); + __ CallRuntime(Runtime::kToSlowProperties, 1); + } + __ 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(); + + // If the assignment ends an initialization block, revert to fast case. + if (expr->ends_initialization_block()) { + __ push(eax); // Result of assignment, saved even if not needed. + // Reciever is under the key and value. + __ push(Operand(esp, 2 * kPointerSize)); + __ CallRuntime(Runtime::kToFastProperties, 1); + __ pop(eax); + } + // Receiver and key are still on stack. __ add(Operand(esp), Immediate(2 * kPointerSize)); - Move(context, eax); + Move(expr->context(), eax); } diff --git a/src/parser.cc b/src/parser.cc index 02fcfdc59..d64d8befd 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1339,7 +1339,7 @@ class ParserFinder { // An InitializationBlockFinder finds and marks sequences of statements of the -// form x.y.z.a = ...; x.y.z.b = ...; etc. +// form expr.a = ...; expr.b = ...; etc. class InitializationBlockFinder : public ParserFinder { public: InitializationBlockFinder() @@ -1367,7 +1367,7 @@ class InitializationBlockFinder : public ParserFinder { private: // Returns true if the expressions appear to denote the same object. // In the context of initialization blocks, we only consider expressions - // of the form 'x.y.z'. + // of the form 'expr.x' or expr["x"]. static bool SameObject(Expression* e1, Expression* e2) { VariableProxy* v1 = e1->AsVariableProxy(); VariableProxy* v2 = e2->AsVariableProxy(); diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc index b4c75ab78..5df914623 100644 --- a/src/x64/fast-codegen-x64.cc +++ b/src/x64/fast-codegen-x64.cc @@ -600,21 +600,24 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } -void FastCodeGenerator::EmitVariableAssignment(Expression::Context context, - Variable* var) { +void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { + Variable* var = expr->target()->AsVariableProxy()->AsVariable(); + ASSERT(var != NULL); + 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. + // Assignment to a global variable. Use inline caching for the + // assignment. Right-hand-side value is passed in rax, variable name in + // rcx, and the global object on the stack. __ 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(context, rax); + DropAndMove(expr->context(), rax); + } else { - switch (context) { + switch (expr->context()) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: @@ -657,28 +660,68 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context, } -void FastCodeGenerator::EmitNamedPropertyAssignment( - Expression::Context context, - Handle name) { +void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { + // Assignment to a property, using a named store IC. + Property* prop = expr->target()->AsProperty(); + ASSERT(prop != NULL); + ASSERT(prop->key()->AsLiteral() != NULL); + + // If the assignment starts a block of assignments to the same object, + // change to slow case to avoid the quadratic behavior of repeatedly + // adding fast properties. + if (expr->starts_initialization_block()) { + __ push(Operand(rsp, kPointerSize)); // Receiver is under value. + __ CallRuntime(Runtime::kToSlowProperties, 1); + } + __ pop(rax); - __ Move(rcx, name); + __ Move(rcx, prop->key()->AsLiteral()->handle()); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); __ Call(ic, RelocInfo::CODE_TARGET); - DropAndMove(context, rax); + + // If the assignment ends an initialization block, revert to fast case. + if (expr->ends_initialization_block()) { + __ push(rax); // Result of assignment, saved even if not needed. + __ push(Operand(rsp, kPointerSize)); // Receiver is under value. + __ CallRuntime(Runtime::kToFastProperties, 1); + __ pop(rax); + } + + DropAndMove(expr->context(), rax); } -void FastCodeGenerator::EmitKeyedPropertyAssignment( - Expression::Context context) { +void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { + // Assignment to a property, using a keyed store IC. + + // If the assignment starts a block of assignments to the same object, + // change to slow case to avoid the quadratic behavior of repeatedly + // adding fast properties. + if (expr->starts_initialization_block()) { + // Reciever is under the key and value. + __ push(Operand(rsp, 2 * kPointerSize)); + __ CallRuntime(Runtime::kToSlowProperties, 1); + } + __ 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(); + + // If the assignment ends an initialization block, revert to fast case. + if (expr->ends_initialization_block()) { + __ push(rax); // Result of assignment, saved even if not needed. + // Reciever is under the key and value. + __ push(Operand(rsp, 2 * kPointerSize)); + __ CallRuntime(Runtime::kToFastProperties, 1); + __ pop(rax); + } + // Receiver and key are still on stack. __ addq(rsp, Immediate(2 * kPointerSize)); - Move(context, rax); + Move(expr->context(), rax); }