From ab3e85eeb4882ca2656e52956387c820ae9146b8 Mon Sep 17 00:00:00 2001 From: "kmillikin@chromium.org" Date: Fri, 30 Oct 2009 14:06:48 +0000 Subject: [PATCH] Initial implementation of top-level compilation of expressions in test context. Test contexts are used for the left subexpressions of short-circuited boolean operators. The right subexpressions inherit their expression context from the binary op expression. Compilation of short-circuited operations in effect and test context is straightforward: effect(e0 || e1) = test(e0, L0, L1) L1: effect(e1) L0: test(e0 || e1, L0, L1) = test(e0, L0, L2) L2: test(e1, L0, L1) Because the value of the first subexpression may be needed as the value of the whole expression in a value context, we introduce a hybrid value/test contest (the value is needed if true, but not if false). value(e0 || e1) = value/test(e0, L0, L1) L1: value(e1) L0: The compilation of value/test and test/value (introduced by boolean AND) is: value/test(e0 || e1, L0, L1) = value/test(e0, L0, L2) L2: value/test(e1, L0, L1) test/value(e0 || e1, L0, L1) = test(e0, L0, L2) L2: test/value(e1, L0, L1) Boolean AND is the dual. The AST nodes themselves (not their parents) are responsible for producing the proper result (effect, value, or control flow) depending on their context. Review URL: http://codereview.chromium.org/339082 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3187 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/fast-codegen-arm.cc | 224 +++++++++++++++++++++------- src/ast.h | 14 +- src/compiler.cc | 40 ++++- src/fast-codegen.cc | 94 ++++++++++-- src/fast-codegen.h | 14 +- src/ia32/fast-codegen-ia32.cc | 265 ++++++++++++++++++++++----------- src/x64/fast-codegen-x64.cc | 273 +++++++++++++++++++++++----------- 7 files changed, 674 insertions(+), 250 deletions(-) diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index ebf15aad57..d592284516 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -123,15 +123,51 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { } -void FastCodeGenerator::Move(Expression::Context context, Slot* source) { +void FastCodeGenerator::Move(Expression::Context context, Register source) { switch (context) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: break; case Expression::kValue: + __ push(source); + break; + case Expression::kTest: + TestAndBranch(source, true_label_, false_label_); + break; + case Expression::kValueTest: { + Label discard; + __ push(source); + TestAndBranch(source, true_label_, &discard); + __ bind(&discard); + __ pop(); + __ jmp(false_label_); + break; + } + case Expression::kTestValue: { + Label discard; + __ push(source); + TestAndBranch(source, &discard, false_label_); + __ bind(&discard); + __ pop(); + __ jmp(true_label_); + } + } +} + + +void FastCodeGenerator::Move(Expression::Context context, Slot* source) { + switch (context) { + case Expression::kUninitialized: + UNREACHABLE(); + case Expression::kEffect: + break; + case Expression::kValue: // Fall through. + case Expression::kTest: // Fall through. + case Expression::kValueTest: // Fall through. + case Expression::kTestValue: __ ldr(ip, MemOperand(fp, SlotOffset(source))); - __ push(ip); + Move(context, ip); break; } } @@ -143,9 +179,12 @@ void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { UNREACHABLE(); case Expression::kEffect: break; - case Expression::kValue: + case Expression::kValue: // Fall through. + case Expression::kTest: // Fall through. + case Expression::kValueTest: // Fall through. + case Expression::kTestValue: __ mov(ip, Operand(expr->handle())); - __ push(ip); + Move(context, ip); break; } } @@ -162,10 +201,49 @@ void FastCodeGenerator::DropAndMove(Expression::Context context, case Expression::kValue: __ str(source, MemOperand(sp)); break; + case Expression::kTest: + ASSERT(!source.is(sp)); + __ pop(); + TestAndBranch(source, true_label_, false_label_); + break; + case Expression::kValueTest: { + Label discard; + __ str(source, MemOperand(sp)); + TestAndBranch(source, true_label_, &discard); + __ bind(&discard); + __ pop(); + __ jmp(false_label_); + break; + } + case Expression::kTestValue: { + Label discard; + __ str(source, MemOperand(sp)); + TestAndBranch(source, &discard, false_label_); + __ bind(&discard); + __ pop(); + __ jmp(true_label_); + break; + } } } +void FastCodeGenerator::TestAndBranch(Register source, + Label* true_label, + Label* false_label) { + ASSERT_NE(NULL, true_label); + ASSERT_NE(NULL, false_label); + // Call the runtime to find the boolean value of the source and then + // translate it into control flow to the pair of labels. + __ push(source); + __ CallRuntime(Runtime::kToBool, 1); + __ LoadRoot(ip, Heap::kTrueValueRootIndex); + __ cmp(r0, ip); + __ b(eq, true_label); + __ jmp(false_label); +} + + void FastCodeGenerator::DeclareGlobals(Handle pairs) { // Call the runtime to declare the globals. // The context is the first argument. @@ -369,6 +447,28 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { case Expression::kValue: if (!result_saved) __ push(r0); break; + case Expression::kTest: + if (result_saved) __ pop(r0); + TestAndBranch(r0, true_label_, false_label_); + break; + case Expression::kValueTest: { + Label discard; + if (!result_saved) __ push(r0); + TestAndBranch(r0, true_label_, &discard); + __ bind(&discard); + __ pop(); + __ jmp(false_label_); + break; + } + case Expression::kTestValue: { + Label discard; + if (!result_saved) __ push(r0); + TestAndBranch(r0, &discard, false_label_); + __ bind(&discard); + __ pop(); + __ jmp(true_label_); + break; + } } } @@ -446,6 +546,28 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { case Expression::kValue: if (!result_saved) __ push(r0); break; + case Expression::kTest: + if (result_saved) __ pop(r0); + TestAndBranch(r0, true_label_, false_label_); + break; + case Expression::kValueTest: { + Label discard; + if (!result_saved) __ push(r0); + TestAndBranch(r0, true_label_, &discard); + __ bind(&discard); + __ pop(); + __ jmp(false_label_); + break; + } + case Expression::kTestValue: { + Label discard; + if (!result_saved) __ push(r0); + TestAndBranch(r0, &discard, false_label_); + __ bind(&discard); + __ pop(); + __ jmp(true_label_); + break; + } } } @@ -530,16 +652,44 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { UNREACHABLE(); case Expression::kEffect: // Case 'var = temp'. Discard right-hand-side temporary. - __ pop(ip); + __ pop(r0); + __ str(r0, MemOperand(fp, SlotOffset(var->slot()))); break; case Expression::kValue: // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side // temporary on the stack. - __ ldr(ip, MemOperand(sp)); + __ ldr(r0, MemOperand(sp)); + __ str(r0, MemOperand(fp, SlotOffset(var->slot()))); break; + case Expression::kTest: + // Case 'if (var = temp) ...'. + __ pop(r0); + __ str(r0, MemOperand(fp, SlotOffset(var->slot()))); + TestAndBranch(r0, true_label_, false_label_); + break; + case Expression::kValueTest: { + // Case '(var = temp) || ...' in value context. + Label discard; + __ ldr(r0, MemOperand(sp)); + __ str(r0, MemOperand(fp, SlotOffset(var->slot()))); + TestAndBranch(r0, true_label_, &discard); + __ bind(&discard); + __ pop(); + __ jmp(false_label_); + break; + } + case Expression::kTestValue: { + // Case '(var = temp) && ...' in value context. + Label discard; + __ ldr(r0, MemOperand(sp)); + __ str(r0, MemOperand(fp, SlotOffset(var->slot()))); + TestAndBranch(r0, &discard, false_label_); + __ bind(&discard); + __ pop(); + __ jmp(true_label_); + break; + } } - // Do the slot assignment. - __ str(ip, MemOperand(fp, SlotOffset(var->slot()))); } } } @@ -734,11 +884,19 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { case Expression::kUninitialized: UNREACHABLE(); break; + case Expression::kEffect: + break; case Expression::kValue: __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); __ push(ip); break; - case Expression::kEffect: + case Expression::kTestValue: + // Value is false so it's needed. + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); + __ push(ip); + case Expression::kTest: // Fall through. + case Expression::kValueTest: + __ jmp(false_label_); break; } break; @@ -794,52 +952,4 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { } -void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { - // Compile a short-circuited boolean operation in a non-test context. - - // Compile (e0 || e1) as if it were - // (let (temp = e0) temp ? temp : e1). - // Compile (e0 && e1) as if it were - // (let (temp = e0) !temp ? temp : e1). - - Label done; - Expression::Context context = expr->context(); - Expression* left = expr->left(); - Expression* right = expr->right(); - - // Call the runtime to find the boolean value of the left-hand - // subexpression. Duplicate the value if it may be needed as the final - // result. - if (left->AsLiteral() != NULL) { - __ mov(r0, Operand(left->AsLiteral()->handle())); - __ push(r0); - if (context == Expression::kValue) __ push(r0); - } else { - Visit(left); - ASSERT_EQ(Expression::kValue, left->context()); - if (context == Expression::kValue) { - __ ldr(r0, MemOperand(sp)); - __ push(r0); - } - } - // The left-hand value is in on top of the stack. It is duplicated on the - // stack iff the destination location is value. - __ CallRuntime(Runtime::kToBool, 1); - if (expr->op() == Token::OR) { - __ LoadRoot(ip, Heap::kTrueValueRootIndex); - } else { - __ LoadRoot(ip, Heap::kFalseValueRootIndex); - } - __ cmp(r0, ip); - __ b(eq, &done); - - // Discard the left-hand value if present on the stack. - if (context == Expression::kValue) __ pop(); - // Save or discard the right-hand value as needed. - Visit(right); - ASSERT_EQ(context, right->context()); - - __ bind(&done); -} - } } // namespace v8::internal diff --git a/src/ast.h b/src/ast.h index 4c661e1433..590a3f8d36 100644 --- a/src/ast.h +++ b/src/ast.h @@ -162,9 +162,21 @@ class Statement: public AstNode { class Expression: public AstNode { public: enum Context { + // Not assigned a context yet, or else will not be visited during + // code generation. kUninitialized, + // Evaluated for its side effects. kEffect, - kValue + // Evaluated for its value (and side effects). + kValue, + // Evaluated for control flow (and side effects). + kTest, + // Evaluated for control flow and side effects. Value is also + // needed if true. + kValueTest, + // Evaluated for control flow and side effects. Value is also + // needed if false. + kTestValue }; Expression() : context_(kUninitialized) {} diff --git a/src/compiler.cc b/src/compiler.cc index 38a41a2ba5..297ada325d 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -849,7 +849,45 @@ void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) { break; case Token::OR: - ProcessExpression(expr->left(), Expression::kValue); + switch (context_) { + case Expression::kUninitialized: + UNREACHABLE(); + case Expression::kEffect: // Fall through. + case Expression::kTest: // Fall through. + case Expression::kTestValue: + // The left subexpression's value is not needed, it is in a pure + // test context. + ProcessExpression(expr->left(), Expression::kTest); + break; + case Expression::kValue: // Fall through. + case Expression::kValueTest: + // The left subexpression's value is needed, it is in a hybrid + // value/test context. + ProcessExpression(expr->left(), Expression::kValueTest); + break; + } + CHECK_BAILOUT; + ProcessExpression(expr->right(), context_); + break; + + case Token::AND: + switch (context_) { + case Expression::kUninitialized: + UNREACHABLE(); + case Expression::kEffect: // Fall through. + case Expression::kTest: // Fall through. + case Expression::kValueTest: + // The left subexpression's value is not needed, it is in a pure + // test context. + ProcessExpression(expr->left(), Expression::kTest); + break; + case Expression::kValue: // Fall through. + case Expression::kTestValue: + // The left subexpression's value is needed, it is in a hybrid + // test/value context. + ProcessExpression(expr->left(), Expression::kTestValue); + break; + } CHECK_BAILOUT; ProcessExpression(expr->right(), context_); break; diff --git a/src/fast-codegen.cc b/src/fast-codegen.cc index 397fe3409f..e2ec9ccfa0 100644 --- a/src/fast-codegen.cc +++ b/src/fast-codegen.cc @@ -35,6 +35,8 @@ namespace v8 { namespace internal { +#define __ ACCESS_MASM(masm_) + Handle FastCodeGenerator::MakeCode(FunctionLiteral* fun, Handle