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:
parent
b4c11d0816
commit
aa3b00a25a
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user