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
This commit is contained in:
kmillikin@chromium.org 2009-11-02 13:30:24 +00:00
parent b4c11d0816
commit aa3b00a25a
7 changed files with 188 additions and 62 deletions

View File

@ -572,12 +572,14 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
} }
void FastCodeGenerator::EmitVariableAssignment(Expression::Context context, void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
Variable* var) { Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL);
if (var->is_global()) { if (var->is_global()) {
// Assignment to a global variable, use inline caching. Right-hand-side // Assignment to a global variable. Use inline caching for the
// value is passed in r0, variable name in r2, and the global object // assignment. Right-hand-side value is passed in r0, variable name in
// on the stack. // r2, and the global object on the stack.
__ pop(r0); __ pop(r0);
__ mov(r2, Operand(var->name())); __ mov(r2, Operand(var->name()));
__ ldr(ip, CodeGenerator::GlobalObject()); __ ldr(ip, CodeGenerator::GlobalObject());
@ -585,9 +587,10 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
// Overwrite the global object on the stack with the result if needed. // Overwrite the global object on the stack with the result if needed.
DropAndMove(context, r0); DropAndMove(expr->context(), r0);
} else { } else {
switch (context) { switch (expr->context()) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
@ -631,25 +634,69 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
} }
void FastCodeGenerator::EmitNamedPropertyAssignment( void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Expression::Context context, // Assignment to a property, using a named store IC.
Handle<Object> name) { 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); __ pop(r0);
__ mov(r2, Operand(name)); __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ 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( void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Expression::Context context) { // 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); __ pop(r0);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ 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. // Receiver and key are still on stack.
__ add(sp, sp, Operand(2 * kPointerSize)); __ add(sp, sp, Operand(2 * kPointerSize));
Move(context, r0); Move(expr->context(), r0);
} }

View File

@ -724,11 +724,6 @@ void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
void CodeGenSelector::VisitAssignment(Assignment* expr) { void CodeGenSelector::VisitAssignment(Assignment* expr) {
// We support plain non-compound assignments to properties, parameters and // We support plain non-compound assignments to properties, parameters and
// non-context (stack-allocated) locals, and global variables. // 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(); Token::Value op = expr->op();
if (op == Token::INIT_CONST) BAILOUT("initialize constant"); if (op == Token::INIT_CONST) BAILOUT("initialize constant");
if (op != Token::ASSIGN && op != Token::INIT_VAR) { if (op != Token::ASSIGN && op != Token::INIT_VAR) {

View File

@ -439,7 +439,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
if (var != NULL) { if (var != NULL) {
Visit(rhs); Visit(rhs);
ASSERT_EQ(Expression::kValue, rhs->context()); ASSERT_EQ(Expression::kValue, rhs->context());
EmitVariableAssignment(expr->context(), var); EmitVariableAssignment(expr);
} else if (prop != NULL) { } else if (prop != NULL) {
// Assignment to a property. // Assignment to a property.
Visit(prop->obj()); Visit(prop->obj());
@ -450,14 +450,13 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
ASSERT(prop->key()->AsLiteral() != NULL); ASSERT(prop->key()->AsLiteral() != NULL);
Visit(rhs); Visit(rhs);
ASSERT_EQ(Expression::kValue, rhs->context()); ASSERT_EQ(Expression::kValue, rhs->context());
EmitNamedPropertyAssignment(expr->context(), EmitNamedPropertyAssignment(expr);
prop->key()->AsLiteral()->handle());
} else { } else {
Visit(prop->key()); Visit(prop->key());
ASSERT_EQ(Expression::kValue, prop->key()->context()); ASSERT_EQ(Expression::kValue, prop->key()->context());
Visit(rhs); Visit(rhs);
ASSERT_EQ(Expression::kValue, rhs->context()); ASSERT_EQ(Expression::kValue, rhs->context());
EmitKeyedPropertyAssignment(expr->context()); EmitKeyedPropertyAssignment(expr);
} }
} else { } else {
UNREACHABLE(); UNREACHABLE();

View File

@ -77,18 +77,17 @@ class FastCodeGenerator: public AstVisitor {
// Platform-specific support for compiling assignments. // 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. // 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 // Complete a named property assignment. The receiver and right-hand-side
// value are expected on top of the stack. // value are expected on top of the stack.
void EmitNamedPropertyAssignment(Expression::Context context, void EmitNamedPropertyAssignment(Assignment* expr);
Handle<Object> name);
// Complete a keyed property assignment. The reciever, key, and // Complete a keyed property assignment. The reciever, key, and
// right-hand-side value are expected on top of the stack. // 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 SetFunctionPosition(FunctionLiteral* fun);
void SetReturnPosition(FunctionLiteral* fun); void SetReturnPosition(FunctionLiteral* fun);

View File

@ -586,21 +586,24 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
} }
void FastCodeGenerator::EmitVariableAssignment(Expression::Context context, void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
Variable* var) { Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL);
if (var->is_global()) { if (var->is_global()) {
// Assignment to a global variable, use inline caching. Right-hand-side // Assignment to a global variable. Use inline caching for the
// value is passed in eax, variable name in ecx, and the global object // assignment. Right-hand-side value is passed in eax, variable name in
// on the stack. // ecx, and the global object on the stack.
__ pop(eax); __ pop(eax);
__ mov(ecx, var->name()); __ mov(ecx, var->name());
__ push(CodeGenerator::GlobalObject()); __ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ call(ic, RelocInfo::CODE_TARGET);
// Overwrite the global object on the stack with the result if needed. // Overwrite the receiver on the stack with the result if needed.
DropAndMove(context, eax); DropAndMove(expr->context(), eax);
} else { } else {
switch (context) { switch (expr->context()) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
@ -643,28 +646,68 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
} }
void FastCodeGenerator::EmitNamedPropertyAssignment( void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Expression::Context context, // Assignment to a property, using a named store IC.
Handle<Object> name) { 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); __ pop(eax);
__ mov(ecx, name); __ mov(ecx, prop->key()->AsLiteral()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ 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( void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Expression::Context context) { // 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); __ pop(eax);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ call(ic, RelocInfo::CODE_TARGET);
// This nop signals to the IC that there is no inlined code at the call // This nop signals to the IC that there is no inlined code at the call
// site for it to patch. // site for it to patch.
__ nop(); __ 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. // Receiver and key are still on stack.
__ add(Operand(esp), Immediate(2 * kPointerSize)); __ add(Operand(esp), Immediate(2 * kPointerSize));
Move(context, eax); Move(expr->context(), eax);
} }

View File

@ -1339,7 +1339,7 @@ class ParserFinder {
// An InitializationBlockFinder finds and marks sequences of statements of the // 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 { class InitializationBlockFinder : public ParserFinder {
public: public:
InitializationBlockFinder() InitializationBlockFinder()
@ -1367,7 +1367,7 @@ class InitializationBlockFinder : public ParserFinder {
private: private:
// Returns true if the expressions appear to denote the same object. // Returns true if the expressions appear to denote the same object.
// In the context of initialization blocks, we only consider expressions // 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) { static bool SameObject(Expression* e1, Expression* e2) {
VariableProxy* v1 = e1->AsVariableProxy(); VariableProxy* v1 = e1->AsVariableProxy();
VariableProxy* v2 = e2->AsVariableProxy(); VariableProxy* v2 = e2->AsVariableProxy();

View File

@ -600,21 +600,24 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
} }
void FastCodeGenerator::EmitVariableAssignment(Expression::Context context, void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
Variable* var) { Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL);
if (var->is_global()) { if (var->is_global()) {
// Assignment to a global variable, use inline caching. Right-hand-side // Assignment to a global variable. Use inline caching for the
// value is passed in rax, variable name in rcx, and the global object // assignment. Right-hand-side value is passed in rax, variable name in
// on the stack. // rcx, and the global object on the stack.
__ pop(rax); __ pop(rax);
__ Move(rcx, var->name()); __ Move(rcx, var->name());
__ push(CodeGenerator::GlobalObject()); __ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
// Overwrite the global object on the stack with the result if needed. // Overwrite the global object on the stack with the result if needed.
DropAndMove(context, rax); DropAndMove(expr->context(), rax);
} else { } else {
switch (context) { switch (expr->context()) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
@ -657,28 +660,68 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
} }
void FastCodeGenerator::EmitNamedPropertyAssignment( void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Expression::Context context, // Assignment to a property, using a named store IC.
Handle<Object> name) { 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); __ pop(rax);
__ Move(rcx, name); __ Move(rcx, prop->key()->AsLiteral()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ 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( void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Expression::Context context) { // 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); __ pop(rax);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
// This nop signals to the IC that there is no inlined code at the call // This nop signals to the IC that there is no inlined code at the call
// site for it to patch. // site for it to patch.
__ nop(); __ 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. // Receiver and key are still on stack.
__ addq(rsp, Immediate(2 * kPointerSize)); __ addq(rsp, Immediate(2 * kPointerSize));
Move(context, rax); Move(expr->context(), rax);
} }