Support for post-fix count operations (x++, x--) where x is a global

variable for the top-level compiler.

Review URL: http://codereview.chromium.org/342058

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3194 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
fschneider@chromium.org 2009-11-02 10:22:22 +00:00
parent e09c4f20c5
commit a07146c0cb
6 changed files with 236 additions and 7 deletions

View File

@ -380,7 +380,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
// If result_saved == true: the result is saved on top of the stack.
// If result_saved == false: the result is in eax.
// If result_saved == false: the result is in r0.
bool result_saved = false;
for (int i = 0; i < expr->properties()->length(); i++) {
@ -972,6 +972,81 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
}
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
VariableProxy* v = expr->expression()->AsVariableProxy();
ASSERT(v->AsVariable() != NULL);
ASSERT(v->AsVariable()->is_global());
Visit(v);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kValue: // Fall through
case Expression::kTest: // Fall through
case Expression::kTestValue: // Fall through
case Expression::kValueTest:
// Duplicate the result on the stack.
__ push(r0);
break;
case Expression::kEffect:
// Do not save result.
break;
}
// Call runtime for +1/-1.
__ push(r0);
__ mov(ip, Operand(Smi::FromInt(1)));
__ push(ip);
if (expr->op() == Token::INC) {
__ CallRuntime(Runtime::kNumberAdd, 2);
} else {
__ CallRuntime(Runtime::kNumberSub, 2);
}
// Call Store IC.
__ mov(r2, Operand(v->AsVariable()->name()));
__ ldr(ip, CodeGenerator::GlobalObject());
__ push(ip);
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Restore up stack after store IC.
__ add(sp, sp, Operand(kPointerSize));
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect: // Fall through
case Expression::kValue:
// Do nothing. Result in either on the stack for value context
// or discarded for effect context.
break;
case Expression::kTest:
__ pop(r0);
TestAndBranch(r0, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
__ ldr(r0, MemOperand(sp));
TestAndBranch(r0, true_label_, &discard);
__ bind(&discard);
__ add(sp, sp, Operand(kPointerSize));
__ b(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ ldr(r0, MemOperand(sp));
TestAndBranch(r0, &discard, false_label_);
__ bind(&discard);
__ add(sp, sp, Operand(kPointerSize));
__ b(true_label_);
break;
}
}
}
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
switch (expr->op()) {
case Token::COMMA:

View File

@ -847,7 +847,11 @@ void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) {
void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
BAILOUT("CountOperation");
// We support postfix count operations on global variables.
if (expr->is_prefix()) BAILOUT("Prefix CountOperation");
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
if (var == NULL || !var->is_global()) BAILOUT("non-global postincrement");
ProcessExpression(expr->expression(), Expression::kValue);
}

View File

@ -434,11 +434,6 @@ void FastCodeGenerator::VisitThrow(Throw* expr) {
}
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
UNREACHABLE();
}

View File

@ -993,6 +993,79 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
}
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
VariableProxy* v = expr->expression()->AsVariableProxy();
ASSERT(v->AsVariable() != NULL);
ASSERT(v->AsVariable()->is_global());
Visit(v);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kValue: // Fall through
case Expression::kTest: // Fall through
case Expression::kTestValue: // Fall through
case Expression::kValueTest:
// Duplicate the result on the stack.
__ push(eax);
break;
case Expression::kEffect:
// Do not save result.
break;
}
// Call runtime for +1/-1.
__ push(eax);
__ push(Immediate(Smi::FromInt(1)));
if (expr->op() == Token::INC) {
__ CallRuntime(Runtime::kNumberAdd, 2);
} else {
__ CallRuntime(Runtime::kNumberSub, 2);
}
// Call Store IC.
__ mov(ecx, v->AsVariable()->name());
__ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// Restore up stack after store IC.
__ add(Operand(esp), Immediate(kPointerSize));
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect: // Fall through
case Expression::kValue:
// Do nothing. Result in either on the stack for value context
// or discarded for effect context.
break;
case Expression::kTest:
__ pop(eax);
TestAndBranch(eax, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
__ mov(eax, Operand(esp, 0));
TestAndBranch(eax, true_label_, &discard);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ mov(eax, Operand(esp, 0));
TestAndBranch(eax, &discard, false_label_);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
__ jmp(true_label_);
break;
}
}
}
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
switch (expr->op()) {
case Token::COMMA:

View File

@ -914,6 +914,78 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Move(expr->context(), rax);
}
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
VariableProxy* v = expr->expression()->AsVariableProxy();
ASSERT(v->AsVariable() != NULL);
ASSERT(v->AsVariable()->is_global());
Visit(v);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kValue: // Fall through
case Expression::kTest: // Fall through
case Expression::kTestValue: // Fall through
case Expression::kValueTest:
// Duplicate the result on the stack.
__ push(rax);
break;
case Expression::kEffect:
// Do not save result.
break;
}
// Call runtime for +1/-1.
__ push(rax);
__ Push(Smi::FromInt(1));
if (expr->op() == Token::INC) {
__ CallRuntime(Runtime::kNumberAdd, 2);
} else {
__ CallRuntime(Runtime::kNumberSub, 2);
}
// Call Store IC.
__ Move(rcx, v->AsVariable()->name());
__ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// Restore up stack after store IC
__ addq(rsp, Immediate(kPointerSize));
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect: // Fall through
case Expression::kValue:
// Do nothing. Result in either on the stack for value context
// or discarded for effect context.
break;
case Expression::kTest:
__ pop(rax);
TestAndBranch(rax, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
__ movq(rax, Operand(rsp, 0));
TestAndBranch(rax, true_label_, &discard);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ movq(rax, Operand(rsp, 0));
TestAndBranch(rax, &discard, false_label_);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ jmp(true_label_);
break;
}
}
}
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Comment cmnt(masm_, "[ UnaryOperation");

View File

@ -53,3 +53,13 @@ assertEquals("2", eval('g'));
// Test a second load.
g = 3;
assertEquals(3, eval('g'));
// Test postfix count operation
var t;
t = g++;
assertEquals(3, t);
assertEquals(4, g);
code = "g--; 1";
assertEquals(1, eval(code));
assertEquals(3, g);