if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
__ JumpIfNotSmi(eax, &miss_force_generic);
- // ecx is a smi, don't use times_half_pointer_size istead of
+ // ecx is a smi, use times_half_pointer_size instead of
// times_pointer_size
__ mov(FieldOperand(edi,
ecx,
} else {
ASSERT(elements_kind == FAST_ELEMENTS);
// Do the store and update the write barrier.
- // ecx is a smi, don't use times_half_pointer_size istead of
+ // ecx is a smi, use times_half_pointer_size instead of
// times_pointer_size
__ lea(ecx, FieldOperand(edi,
ecx,
VisitForAccumulatorValue(subexpr);
// Store the subexpression value in the array's elements.
- __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
- __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
+ __ movq(r8, Operand(rsp, 0)); // Copy of array literal.
+ __ movq(rbx, FieldOperand(r8, JSObject::kElementsOffset));
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ movq(FieldOperand(rbx, offset), result_register());
+ Label no_map_change;
+ __ JumpIfSmi(result_register(), &no_map_change);
// Update the write barrier for the array store.
- __ RecordWriteField(rbx, offset, result_register(), rcx, kDontSaveFPRegs);
+ __ RecordWriteField(rbx, offset, result_register(), rcx,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ if (FLAG_smi_only_arrays) {
+ __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
+ __ CheckFastSmiOnlyElements(rdi, &no_map_change, Label::kNear);
+ __ push(r8);
+ __ CallRuntime(Runtime::kNonSmiElementStored, 1);
+ }
+ __ bind(&no_map_change);
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
}
// rax: value
// rbx: receiver's elements array (a FixedArray)
// rcx: index
+
Label non_smi_value;
+ __ JumpIfNotSmi(rax, &non_smi_value);
+ // It's irrelevant whether array is smi-only or not when writing a smi.
__ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
rax);
- __ JumpIfNotSmi(rax, &non_smi_value, Label::kNear);
__ ret(0);
+
__ bind(&non_smi_value);
- // Slow case that needs to retain rcx for use by RecordWrite.
- // Update write barrier for the elements array address.
+ if (FLAG_smi_only_arrays) {
+ // Writing a non-smi, check whether array allows non-smi elements.
+ __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ CheckFastObjectElements(rdi, &slow, Label::kNear);
+ }
+ __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
+ rax);
__ movq(rdx, rax);
__ lea(rcx,
FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize));
}
+void MacroAssembler::CheckFastObjectElements(Register map,
+ Label* fail,
+ Label::Distance distance) {
+ STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 1);
+ cmpb(FieldOperand(map, Map::kBitField2Offset),
+ Immediate(Map::kMaximumBitField2FastSmiOnlyElementValue));
+ j(below_equal, fail, distance);
+ cmpb(FieldOperand(map, Map::kBitField2Offset),
+ Immediate(Map::kMaximumBitField2FastElementValue));
+ j(above, fail, distance);
+}
+
+
+void MacroAssembler::CheckFastSmiOnlyElements(Register map,
+ Label* fail,
+ Label::Distance distance) {
+ STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+ cmpb(FieldOperand(map, Map::kBitField2Offset),
+ Immediate(Map::kMaximumBitField2FastSmiOnlyElementValue));
+ j(above, fail, distance);
+}
+
+
void MacroAssembler::CheckMap(Register obj,
Handle<Map> map,
Label* fail,
Label* fail,
Label::Distance distance = Label::kFar);
+ // Check if a map for a JSObject indicates that the object can have both smi
+ // and HeapObject elements. Jump to the specified label if it does not.
+ void CheckFastObjectElements(Register map,
+ Label* fail,
+ Label::Distance distance = Label::kFar);
+
+ // Check if a map for a JSObject indicates that the object has fast smi only
+ // elements. Jump to the specified label if it does not.
+ void CheckFastSmiOnlyElements(Register map,
+ Label* fail,
+ Label::Distance distance = Label::kFar);
+
// Check if the map of an object is equal to a specified map and
// branch to label if not. Skip the smi check if not required
// (object is known to be a heap object)
__ cmpl(rax, rcx);
__ j(greater, &attempt_to_grow_elements);
+ // Check if value is a smi.
+ __ movq(rcx, Operand(rsp, argc * kPointerSize));
+ __ JumpIfNotSmi(rcx, &with_write_barrier);
+
// Save new length.
__ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
// Push the element.
- __ movq(rcx, Operand(rsp, argc * kPointerSize));
__ lea(rdx, FieldOperand(rbx,
rax, times_pointer_size,
FixedArray::kHeaderSize - argc * kPointerSize));
__ movq(Operand(rdx, 0), rcx);
- // Check if value is a smi.
__ Integer32ToSmi(rax, rax); // Return new length as smi.
-
- __ JumpIfNotSmi(rcx, &with_write_barrier);
-
__ ret((argc + 1) * kPointerSize);
__ bind(&with_write_barrier);
+ if (FLAG_smi_only_arrays) {
+ __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ CheckFastObjectElements(rdi, &call_builtin);
+ }
+
+ // Save new length.
+ __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
+
+ // Push the element.
+ __ lea(rdx, FieldOperand(rbx,
+ rax, times_pointer_size,
+ FixedArray::kHeaderSize - argc * kPointerSize));
+ __ movq(Operand(rdx, 0), rcx);
+
__ RecordWrite(
rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+ __ Integer32ToSmi(rax, rax); // Return new length as smi.
__ ret((argc + 1) * kPointerSize);
__ bind(&attempt_to_grow_elements);
__ jmp(&call_builtin);
}
+ __ movq(rdi, Operand(rsp, argc * kPointerSize));
+ if (FLAG_smi_only_arrays) {
+ // Growing elements that are SMI-only requires special handling in case
+ // the new element is non-Smi. For now, delegate to the builtin.
+ Label no_fast_elements_check;
+ __ JumpIfSmi(rdi, &no_fast_elements_check);
+ __ movq(rsi, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ CheckFastObjectElements(rsi, &call_builtin, Label::kFar);
+ __ bind(&no_fast_elements_check);
+ }
+
ExternalReference new_space_allocation_top =
ExternalReference::new_space_allocation_top_address(isolate());
ExternalReference new_space_allocation_limit =
// We fit and could grow elements.
__ Store(new_space_allocation_top, rcx);
- __ movq(rcx, Operand(rsp, argc * kPointerSize));
// Push the argument...
- __ movq(Operand(rdx, 0), rcx);
+ __ movq(Operand(rdx, 0), rdi);
// ... and fill the rest with holes.
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
for (int i = 1; i < kAllocationDelta; i++) {
// tell the incremental marker to rescan the object that we just grew. We
// don't need to worry about the holes because they are in old space and
// already marked black.
- __ RecordWrite(rbx, rdx, rcx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
+ __ RecordWrite(rbx, rdx, rdi, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
// Restore receiver to rdx as finish sequence assumes it's here.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
// Do the store and update the write barrier.
__ SmiToInteger32(rcx, rcx);
- __ lea(rcx,
- FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize));
- __ movq(Operand(rcx, 0), rax);
- // Make sure to preserve the value in register rax.
- __ movq(rdx, rax);
- ASSERT(elements_kind == FAST_ELEMENTS);
- __ RecordWrite(rdi, rcx, rdx, kDontSaveFPRegs);
+ if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ __ JumpIfNotSmi(rax, &miss_force_generic);
+ __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
+ rax);
+ } else {
+ ASSERT(elements_kind == FAST_ELEMENTS);
+ __ lea(rcx,
+ FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize));
+ __ movq(Operand(rcx, 0), rax);
+ // Make sure to preserve the value in register rax.
+ __ movq(rdx, rax);
+ __ RecordWrite(rdi, rcx, rdx, kDontSaveFPRegs);
+ }
// Done.
__ ret(0);
}
// We expect an object to only be of one element kind.
-function assertKind(expected, obj){
+function assertKind(expected, obj) {
if (support_smi_only_arrays) {
assertEquals(expected == element_kind.fast_smi_only_elements,
%HasFastSmiOnlyElements(obj));
// Make sure the element kind transitions from smionly when a non-smi is stored.
var you = new Array();
assertKind(element_kind.fast_smi_only_elements, you);
-for(i = 0; i < 1337; i++) {
+for (var i = 0; i < 1337; i++) {
var val = i;
if (i == 1336) {
assertKind(element_kind.fast_smi_only_elements, you);
}
assertKind(element_kind.fast_elements, you);
-assertKind(element_kind.dictionary_elements, new Array(0xC0C0A));
-
-// fast_double_elements not yet available
+assertKind(element_kind.dictionary_elements, new Array(0xDECAF));
+var fast_double_array = new Array(0xDECAF);
+for (var i = 0; i < 0xDECAF; i++) fast_double_array[i] = i / 2;
+assertKind(element_kind.fast_double_elements, fast_double_array);
assertKind(element_kind.external_byte_elements, new Int8Array(9001));
assertKind(element_kind.external_unsigned_byte_elements, new Uint8Array(007));