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 |