Revision: 3198 Author: [email protected] Date: Mon Nov 2 05:30:24 2009 Log: 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 http://code.google.com/p/v8/source/detail?r=3198 Modified: /branches/bleeding_edge/src/arm/fast-codegen-arm.cc /branches/bleeding_edge/src/compiler.cc /branches/bleeding_edge/src/fast-codegen.cc /branches/bleeding_edge/src/fast-codegen.h /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc /branches/bleeding_edge/src/parser.cc /branches/bleeding_edge/src/x64/fast-codegen-x64.cc ======================================= --- /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Mon Nov 2 04:04:35 2009 +++ /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Mon Nov 2 05:30:24 2009 @@ -572,12 +572,14 @@ } -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 @@ 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(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::EmitNamedPropertyAssignment( - Expression::Context context, - Handle<Object> 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<Code> 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<Code> 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); } ======================================= --- /branches/bleeding_edge/src/compiler.cc Mon Nov 2 04:04:35 2009 +++ /branches/bleeding_edge/src/compiler.cc Mon Nov 2 05:30:24 2009 @@ -724,11 +724,6 @@ 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) { ======================================= --- /branches/bleeding_edge/src/fast-codegen.cc Mon Nov 2 03:01:47 2009 +++ /branches/bleeding_edge/src/fast-codegen.cc Mon Nov 2 05:30:24 2009 @@ -439,7 +439,7 @@ 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 @@ 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(); ======================================= --- /branches/bleeding_edge/src/fast-codegen.h Mon Nov 2 03:01:47 2009 +++ /branches/bleeding_edge/src/fast-codegen.h Mon Nov 2 05:30:24 2009 @@ -77,18 +77,17 @@ // 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<Object> 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); ======================================= --- /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Mon Nov 2 04:04:35 2009 +++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Mon Nov 2 05:30:24 2009 @@ -586,21 +586,24 @@ } -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<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(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::EmitNamedPropertyAssignment( - Expression::Context context, - Handle<Object> 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<Code> 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<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(); + + // 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); } ======================================= --- /branches/bleeding_edge/src/parser.cc Tue Oct 13 02:37:17 2009 +++ /branches/bleeding_edge/src/parser.cc Mon Nov 2 05:30:24 2009 @@ -1339,7 +1339,7 @@ // 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 @@ 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(); ======================================= --- /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Mon Nov 2 04:04:35 2009 +++ /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Mon Nov 2 05:30:24 2009 @@ -600,21 +600,24 @@ } -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<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(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::EmitNamedPropertyAssignment( - Expression::Context context, - Handle<Object> 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<Code> 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<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(); + + // 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); } --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---
