| Index: src/x64/codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/codegen-x64.cc (revision 2232)
|
| +++ src/x64/codegen-x64.cc (working copy)
|
| @@ -155,6 +155,7 @@
|
| " test_nesting_calls(test_local_variables(1,3), 42, 47),"
|
| " test_local_variables(-25.3, 2));"
|
| " var o = { x: 42 };"
|
| + " var a = [ 1, 2, 3 ];"
|
| " return test_if_then_else(1, 47, 39);"
|
| "})()")),
|
| Factory::NewStringFromAscii(CStrVector("CodeGeneratorTestScript")),
|
| @@ -310,7 +311,7 @@
|
| // all registers).
|
| if (FLAG_trace) {
|
| frame_->Push(return_value);
|
| - // *return_value = frame_->CallRuntime(Runtime::kTraceExit, 1);
|
| + *return_value = frame_->CallRuntime(Runtime::kTraceExit, 1);
|
| }
|
| return_value->ToRegister(rax);
|
|
|
| @@ -324,6 +325,8 @@
|
| masm_->ret((scope_->num_parameters() + 1) * kPointerSize);
|
| DeleteFrame();
|
|
|
| + // TODO(x64): introduce kX64JSReturnSequenceLength and enable assert.
|
| +
|
| // Check that the size of the code used for returning matches what is
|
| // expected by the debugger.
|
| // ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
|
| @@ -576,7 +579,7 @@
|
| CodeForStatementPosition(node);
|
| Load(node->expression());
|
| Result return_value = frame_->Pop();
|
| - /* if (function_return_is_shadowed_) {
|
| + if (function_return_is_shadowed_) {
|
| function_return_.Jump(&return_value);
|
| } else {
|
| frame_->PrepareForReturn();
|
| @@ -589,8 +592,6 @@
|
| GenerateReturnSequence(&return_value);
|
| }
|
| }
|
| - */
|
| - GenerateReturnSequence(&return_value);
|
| }
|
|
|
|
|
| @@ -683,7 +684,7 @@
|
| } else {
|
| ASSERT(var->is_global());
|
| Reference ref(this, node);
|
| - // ref.GetValue(typeof_state());
|
| + ref.GetValue(typeof_state());
|
| }
|
| }
|
|
|
| @@ -728,10 +729,7 @@
|
| // Literal index (1).
|
| __ push(Immediate(Smi::FromInt(node_->literal_index())));
|
| // Constant properties (2).
|
| - __ movq(kScratchRegister,
|
| - node_->constant_properties(),
|
| - RelocInfo::EMBEDDED_OBJECT);
|
| - __ push(kScratchRegister);
|
| + __ PushHeapObject(node_->constant_properties());
|
| __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
|
| if (!boilerplate_.is(rax)) __ movq(boilerplate_, rax);
|
| }
|
| @@ -763,10 +761,7 @@
|
| // If so, jump to the deferred code passing the literals array.
|
| DeferredObjectLiteral* deferred =
|
| new DeferredObjectLiteral(boilerplate.reg(), literals.reg(), node);
|
| - __ movq(kScratchRegister,
|
| - Factory::undefined_value(),
|
| - RelocInfo::EMBEDDED_OBJECT);
|
| - __ cmpq(boilerplate.reg(), kScratchRegister);
|
| + __ CmpHeapObject(boilerplate.reg(), Factory::undefined_value());
|
| deferred->Branch(equal);
|
| deferred->BindExit();
|
| literals.Unuse();
|
| @@ -828,10 +823,125 @@
|
| }
|
| }
|
|
|
| -void CodeGenerator::VisitArrayLiteral(ArrayLiteral* a) {
|
| - UNIMPLEMENTED();
|
| +
|
| +// Materialize the array literal 'node' in the literals array 'literals'
|
| +// of the function. Leave the array boilerplate in 'boilerplate'.
|
| +class DeferredArrayLiteral: public DeferredCode {
|
| + public:
|
| + DeferredArrayLiteral(Register boilerplate,
|
| + Register literals,
|
| + ArrayLiteral* node)
|
| + : boilerplate_(boilerplate), literals_(literals), node_(node) {
|
| + set_comment("[ DeferredArrayLiteral");
|
| + }
|
| +
|
| + void Generate();
|
| +
|
| + private:
|
| + Register boilerplate_;
|
| + Register literals_;
|
| + ArrayLiteral* node_;
|
| +};
|
| +
|
| +
|
| +void DeferredArrayLiteral::Generate() {
|
| + // Since the entry is undefined we call the runtime system to
|
| + // compute the literal.
|
| + // Literal array (0).
|
| + __ push(literals_);
|
| + // Literal index (1).
|
| + __ push(Immediate(Smi::FromInt(node_->literal_index())));
|
| + // Constant properties (2).
|
| + __ PushHeapObject(node_->literals());
|
| + __ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
|
| + if (!boilerplate_.is(rax)) __ movq(boilerplate_, rax);
|
| }
|
|
|
| +
|
| +void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
|
| + Comment cmnt(masm_, "[ ArrayLiteral");
|
| +
|
| + // Retrieve the literals array and check the allocated entry. Begin
|
| + // with a writable copy of the function of this activation in a
|
| + // register.
|
| + frame_->PushFunction();
|
| + Result literals = frame_->Pop();
|
| + literals.ToRegister();
|
| + frame_->Spill(literals.reg());
|
| +
|
| + // Load the literals array of the function.
|
| + __ movq(literals.reg(),
|
| + FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
|
| +
|
| + // Load the literal at the ast saved index.
|
| + Result boilerplate = allocator_->Allocate();
|
| + ASSERT(boilerplate.is_valid());
|
| + int literal_offset =
|
| + FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
|
| + __ movq(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset));
|
| +
|
| + // Check whether we need to materialize the object literal boilerplate.
|
| + // If so, jump to the deferred code passing the literals array.
|
| + DeferredArrayLiteral* deferred =
|
| + new DeferredArrayLiteral(boilerplate.reg(), literals.reg(), node);
|
| + __ CmpHeapObject(boilerplate.reg(), Factory::undefined_value());
|
| + deferred->Branch(equal);
|
| + deferred->BindExit();
|
| + literals.Unuse();
|
| +
|
| + // Push the resulting array literal boilerplate on the stack.
|
| + frame_->Push(&boilerplate);
|
| + // Clone the boilerplate object.
|
| + Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
|
| + if (node->depth() == 1) {
|
| + clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
|
| + }
|
| + Result clone = frame_->CallRuntime(clone_function_id, 1);
|
| + // Push the newly cloned literal object as the result.
|
| + frame_->Push(&clone);
|
| +
|
| + // Generate code to set the elements in the array that are not
|
| + // literals.
|
| + for (int i = 0; i < node->values()->length(); i++) {
|
| + Expression* value = node->values()->at(i);
|
| +
|
| + // If value is a literal the property value is already set in the
|
| + // boilerplate object.
|
| + if (value->AsLiteral() != NULL) continue;
|
| + // If value is a materialized literal the property value is already set
|
| + // in the boilerplate object if it is simple.
|
| + if (CompileTimeValue::IsCompileTimeValue(value)) continue;
|
| +
|
| + // The property must be set by generated code.
|
| + Load(value);
|
| +
|
| + // Get the property value off the stack.
|
| + Result prop_value = frame_->Pop();
|
| + prop_value.ToRegister();
|
| +
|
| + // Fetch the array literal while leaving a copy on the stack and
|
| + // use it to get the elements array.
|
| + frame_->Dup();
|
| + Result elements = frame_->Pop();
|
| + elements.ToRegister();
|
| + frame_->Spill(elements.reg());
|
| + // Get the elements array.
|
| + __ movq(elements.reg(),
|
| + FieldOperand(elements.reg(), JSObject::kElementsOffset));
|
| +
|
| + // Write to the indexed properties array.
|
| + int offset = i * kPointerSize + Array::kHeaderSize;
|
| + __ movq(FieldOperand(elements.reg(), offset), prop_value.reg());
|
| +
|
| + // Update the write barrier for the array address.
|
| + frame_->Spill(prop_value.reg()); // Overwritten by the write barrier.
|
| + Result scratch = allocator_->Allocate();
|
| + ASSERT(scratch.is_valid());
|
| + __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg());
|
| + }
|
| +}
|
| +
|
| +
|
| void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* a) {
|
| UNIMPLEMENTED();
|
| }
|
| @@ -1290,20 +1400,15 @@
|
| // Fast case checks.
|
|
|
| // 'false' => false.
|
| - __ movq(kScratchRegister, Factory::false_value(), RelocInfo::EMBEDDED_OBJECT);
|
| - __ cmpq(value.reg(), kScratchRegister);
|
| + __ CmpHeapObject(value.reg(), Factory::false_value());
|
| dest->false_target()->Branch(equal);
|
|
|
| // 'true' => true.
|
| - __ movq(kScratchRegister, Factory::true_value(), RelocInfo::EMBEDDED_OBJECT);
|
| - __ cmpq(value.reg(), kScratchRegister);
|
| + __ CmpHeapObject(value.reg(), Factory::true_value());
|
| dest->true_target()->Branch(equal);
|
|
|
| // 'undefined' => false.
|
| - __ movq(kScratchRegister,
|
| - Factory::undefined_value(),
|
| - RelocInfo::EMBEDDED_OBJECT);
|
| - __ cmpq(value.reg(), kScratchRegister);
|
| + __ CmpHeapObject(value.reg(), Factory::undefined_value());
|
| dest->false_target()->Branch(equal);
|
|
|
| // Smi => false iff zero.
|
| @@ -1632,9 +1737,7 @@
|
| value,
|
| &slow));
|
| if (potential_slot->var()->mode() == Variable::CONST) {
|
| - __ movq(kScratchRegister, Factory::the_hole_value(),
|
| - RelocInfo::EMBEDDED_OBJECT);
|
| - __ cmpq(value.reg(), kScratchRegister);
|
| + __ CmpHeapObject(value.reg(), Factory::the_hole_value());
|
| done.Branch(not_equal, &value);
|
| __ movq(value.reg(), Factory::undefined_value(),
|
| RelocInfo::EMBEDDED_OBJECT);
|
| @@ -1675,9 +1778,7 @@
|
| Comment cmnt(masm_, "[ Load const");
|
| JumpTarget exit;
|
| __ movq(rcx, SlotOperand(slot, rcx));
|
| - __ movq(kScratchRegister, Factory::the_hole_value(),
|
| - RelocInfo::EMBEDDED_OBJECT);
|
| - __ cmpq(rcx, kScratchRegister);
|
| + __ CmpHeapObject(rcx, Factory::the_hole_value());
|
| exit.Branch(not_equal);
|
| __ movq(rcx, Factory::undefined_value(), RelocInfo::EMBEDDED_OBJECT);
|
| exit.Bind();
|
| @@ -1761,9 +1862,7 @@
|
| VirtualFrame::SpilledScope spilled_scope;
|
| Comment cmnt(masm_, "[ Init const");
|
| __ movq(rcx, SlotOperand(slot, rcx));
|
| - __ movq(kScratchRegister, Factory::the_hole_value(),
|
| - RelocInfo::EMBEDDED_OBJECT);
|
| - __ cmpq(rcx, kScratchRegister);
|
| + __ CmpHeapObject(rcx, Factory::the_hole_value());
|
| exit.Branch(not_equal);
|
| }
|
|
|
| @@ -1850,13 +1949,18 @@
|
| // Stub classes have public member named masm, not masm_.
|
| #define __ ACCESS_MASM(masm)
|
|
|
| +
|
| +void Reference::GetValue(TypeofState typeof_state) {
|
| + UNIMPLEMENTED();
|
| +}
|
| +
|
| +
|
| void ToBooleanStub::Generate(MacroAssembler* masm) {
|
| Label false_result, true_result, not_string;
|
| __ movq(rax, Operand(rsp, 1 * kPointerSize));
|
|
|
| // 'null' => false.
|
| - __ movq(kScratchRegister, Factory::null_value(), RelocInfo::EMBEDDED_OBJECT);
|
| - __ cmpq(rax, kScratchRegister);
|
| + __ CmpHeapObject(rax, Factory::null_value());
|
| __ j(equal, &false_result);
|
|
|
| // Get the map and type of the heap object.
|
| @@ -1885,10 +1989,7 @@
|
|
|
| __ bind(¬_string);
|
| // HeapNumber => false iff +0, -0, or NaN.
|
| - __ movq(kScratchRegister,
|
| - Factory::heap_number_map(),
|
| - RelocInfo::EMBEDDED_OBJECT);
|
| - __ cmpq(rdx, kScratchRegister);
|
| + __ CmpHeapObject(rdx, Factory::heap_number_map());
|
| __ j(not_equal, &true_result);
|
| // TODO(x64): Don't use fp stack, use MMX registers?
|
| __ fldz(); // Load zero onto fp stack
|
|
|