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
parent b4c11d08
......@@ -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<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::EmitVariableAssignment(Expression::Context context,
}
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);
}
......
......@@ -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) {
......
......@@ -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();
......
......@@ -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<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);
......
......@@ -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<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::EmitVariableAssignment(Expression::Context context,
}
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);
}
......
......@@ -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();
......
......@@ -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<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::EmitVariableAssignment(Expression::Context context,
}
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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment