| Index: src/x64/codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/codegen-x64.cc (revision 2228)
|
| +++ src/x64/codegen-x64.cc (working copy)
|
| @@ -103,14 +103,38 @@
|
|
|
| void CodeGenerator::TestCodeGenerator() {
|
| // Compile a function from a string, and run it.
|
| +
|
| + // Set flags appropriately for this stage of implementation.
|
| + // TODO(X64): Make ic and lazy compilation work, and stop disabling them.
|
| + // These settings stick - remove them when we don't want them anymore.
|
| +#ifdef DEBUG
|
| + FLAG_print_builtin_source = true;
|
| + FLAG_print_builtin_ast = true;
|
| +#endif
|
| + FLAG_use_ic = false;
|
| + FLAG_lazy = false;
|
| +
|
| Handle<JSFunction> test_function = Compiler::Compile(
|
| Factory::NewStringFromAscii(CStrVector(
|
| - "39;"
|
| + "// Put all code in anonymous function to avoid global scope.\n"
|
| "(function(){"
|
| - "function foo(x, y){var w; y = x; x = w; w = y; y = x; return w;};"
|
| - "function bar(x, y, zee){return zee;};"
|
| - "foo(2,3);"
|
| - "return foo(bar(foo(1,3), 42, 47), foo( -25.3, 2));"
|
| + " function test_if_then_else(x, y, z){"
|
| + " if (x) {"
|
| + " x = y;"
|
| + " } else {"
|
| + " x = z;"
|
| + " }"
|
| + " return x;"
|
| + " }"
|
| + " function test_local_variables(x, y){"
|
| + " var w; y = x; x = w; w = y; y = x; return w;"
|
| + " };"
|
| + " test_local_variables(2,3);"
|
| + " function test_nesting_calls(x, y, zee){return zee;};"
|
| + " test_local_variables("
|
| + " test_nesting_calls(test_local_variables(1,3), 42, 47),"
|
| + " test_local_variables(-25.3, 2));"
|
| + " return test_if_then_else(1, 47, 39);"
|
| "})()")),
|
| Factory::NewStringFromAscii(CStrVector("CodeGeneratorTestScript")),
|
| 0,
|
| @@ -417,10 +441,104 @@
|
| UNIMPLEMENTED();
|
| }
|
|
|
| -void CodeGenerator::VisitIfStatement(IfStatement* a) {
|
| - UNIMPLEMENTED();
|
| +
|
| +void CodeGenerator::VisitIfStatement(IfStatement* node) {
|
| + ASSERT(!in_spilled_code());
|
| + Comment cmnt(masm_, "[ IfStatement");
|
| + // Generate different code depending on which parts of the if statement
|
| + // are present or not.
|
| + bool has_then_stm = node->HasThenStatement();
|
| + bool has_else_stm = node->HasElseStatement();
|
| +
|
| + CodeForStatementPosition(node);
|
| + JumpTarget exit;
|
| + if (has_then_stm && has_else_stm) {
|
| + JumpTarget then;
|
| + JumpTarget else_;
|
| + ControlDestination dest(&then, &else_, true);
|
| + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
|
| +
|
| + if (dest.false_was_fall_through()) {
|
| + // The else target was bound, so we compile the else part first.
|
| + Visit(node->else_statement());
|
| +
|
| + // We may have dangling jumps to the then part.
|
| + if (then.is_linked()) {
|
| + if (has_valid_frame()) exit.Jump();
|
| + then.Bind();
|
| + Visit(node->then_statement());
|
| + }
|
| + } else {
|
| + // The then target was bound, so we compile the then part first.
|
| + Visit(node->then_statement());
|
| +
|
| + if (else_.is_linked()) {
|
| + if (has_valid_frame()) exit.Jump();
|
| + else_.Bind();
|
| + Visit(node->else_statement());
|
| + }
|
| + }
|
| +
|
| + } else if (has_then_stm) {
|
| + ASSERT(!has_else_stm);
|
| + JumpTarget then;
|
| + ControlDestination dest(&then, &exit, true);
|
| + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
|
| +
|
| + if (dest.false_was_fall_through()) {
|
| + // The exit label was bound. We may have dangling jumps to the
|
| + // then part.
|
| + if (then.is_linked()) {
|
| + exit.Unuse();
|
| + exit.Jump();
|
| + then.Bind();
|
| + Visit(node->then_statement());
|
| + }
|
| + } else {
|
| + // The then label was bound.
|
| + Visit(node->then_statement());
|
| + }
|
| +
|
| + } else if (has_else_stm) {
|
| + ASSERT(!has_then_stm);
|
| + JumpTarget else_;
|
| + ControlDestination dest(&exit, &else_, false);
|
| + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
|
| +
|
| + if (dest.true_was_fall_through()) {
|
| + // The exit label was bound. We may have dangling jumps to the
|
| + // else part.
|
| + if (else_.is_linked()) {
|
| + exit.Unuse();
|
| + exit.Jump();
|
| + else_.Bind();
|
| + Visit(node->else_statement());
|
| + }
|
| + } else {
|
| + // The else label was bound.
|
| + Visit(node->else_statement());
|
| + }
|
| +
|
| + } else {
|
| + ASSERT(!has_then_stm && !has_else_stm);
|
| + // We only care about the condition's side effects (not its value
|
| + // or control flow effect). LoadCondition is called without
|
| + // forcing control flow.
|
| + ControlDestination dest(&exit, &exit, true);
|
| + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, false);
|
| + if (!dest.is_used()) {
|
| + // We got a value on the frame rather than (or in addition to)
|
| + // control flow.
|
| + frame_->Drop();
|
| + }
|
| + }
|
| +
|
| + if (exit.is_linked()) {
|
| + exit.Bind();
|
| + }
|
| }
|
|
|
| +
|
| void CodeGenerator::VisitContinueStatement(ContinueStatement* a) {
|
| UNIMPLEMENTED();
|
| }
|
| @@ -993,7 +1111,7 @@
|
| if (force_control && !dest->is_used()) {
|
| // Convert the TOS value into flow to the control destination.
|
| // TODO(X64): Make control flow to control destinations work.
|
| - // ToBoolean(dest);
|
| + ToBoolean(dest);
|
| }
|
|
|
| ASSERT(!(force_control && !dest->is_used()));
|
| @@ -1001,6 +1119,64 @@
|
| }
|
|
|
|
|
| +class ToBooleanStub: public CodeStub {
|
| + public:
|
| + ToBooleanStub() { }
|
| +
|
| + void Generate(MacroAssembler* masm);
|
| +
|
| + private:
|
| + Major MajorKey() { return ToBoolean; }
|
| + int MinorKey() { return 0; }
|
| +};
|
| +
|
| +
|
| +// ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and
|
| +// convert it to a boolean in the condition code register or jump to
|
| +// 'false_target'/'true_target' as appropriate.
|
| +void CodeGenerator::ToBoolean(ControlDestination* dest) {
|
| + Comment cmnt(masm_, "[ ToBoolean");
|
| +
|
| + // The value to convert should be popped from the frame.
|
| + Result value = frame_->Pop();
|
| + value.ToRegister();
|
| + // Fast case checks.
|
| +
|
| + // 'false' => false.
|
| + __ movq(kScratchRegister, Factory::false_value(), RelocInfo::EMBEDDED_OBJECT);
|
| + __ cmpq(value.reg(), kScratchRegister);
|
| + dest->false_target()->Branch(equal);
|
| +
|
| + // 'true' => true.
|
| + __ movq(kScratchRegister, Factory::true_value(), RelocInfo::EMBEDDED_OBJECT);
|
| + __ cmpq(value.reg(), kScratchRegister);
|
| + dest->true_target()->Branch(equal);
|
| +
|
| + // 'undefined' => false.
|
| + __ movq(kScratchRegister,
|
| + Factory::undefined_value(),
|
| + RelocInfo::EMBEDDED_OBJECT);
|
| + __ cmpq(value.reg(), kScratchRegister);
|
| + dest->false_target()->Branch(equal);
|
| +
|
| + // Smi => false iff zero.
|
| + ASSERT(kSmiTag == 0);
|
| + __ testq(value.reg(), value.reg());
|
| + dest->false_target()->Branch(zero);
|
| + __ testq(value.reg(), Immediate(kSmiTagMask));
|
| + dest->true_target()->Branch(zero);
|
| +
|
| + // Call the stub for all other cases.
|
| + frame_->Push(&value); // Undo the Pop() from above.
|
| + ToBooleanStub stub;
|
| + Result temp = frame_->CallStub(&stub, 1);
|
| + // Convert the result to a condition code.
|
| + __ testq(temp.reg(), temp.reg());
|
| + temp.Unuse();
|
| + dest->Split(not_equal);
|
| +}
|
| +
|
| +
|
| void CodeGenerator::LoadUnsafeSmi(Register target, Handle<Object> value) {
|
| UNIMPLEMENTED();
|
| // TODO(X64): Implement security policy for loads of smis.
|
| @@ -1526,18 +1702,6 @@
|
| // Stub classes have public member named masm, not masm_.
|
| #define __ ACCESS_MASM(masm)
|
|
|
| -class ToBooleanStub: public CodeStub {
|
| - public:
|
| - ToBooleanStub() { }
|
| -
|
| - void Generate(MacroAssembler* masm);
|
| -
|
| - private:
|
| - Major MajorKey() { return ToBoolean; }
|
| - int MinorKey() { return 0; }
|
| -};
|
| -
|
| -
|
| void ToBooleanStub::Generate(MacroAssembler* masm) {
|
| Label false_result, true_result, not_string;
|
| __ movq(rax, Operand(rsp, 1 * kPointerSize));
|
|
|