ARM: Implement runtime function for array literal transitions.
Also simplify ia32 and x64 handing of the trace_elements_transition flag. R=jkummerow@chromium.org BUG=none TEST=array-literal-transitions.js Review URL: http://codereview.chromium.org/8539011 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9979 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
504f2f34d5
commit
8bdb3ffbca
@ -6888,6 +6888,8 @@ struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
|
||||
// ElementsTransitionGenerator::GenerateDoubleToObject
|
||||
{ r6, r2, r0, EMIT_REMEMBERED_SET },
|
||||
{ r2, r6, r9, EMIT_REMEMBERED_SET },
|
||||
// StoreArrayLiteralElementStub::Generate
|
||||
{ r5, r0, r6, EMIT_REMEMBERED_SET },
|
||||
// Null termination.
|
||||
{ no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET}
|
||||
};
|
||||
@ -7124,6 +7126,64 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
|
||||
// Fall through when we need to inform the incremental marker.
|
||||
}
|
||||
|
||||
|
||||
void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : element value to store
|
||||
// -- r1 : array literal
|
||||
// -- r2 : map of array literal
|
||||
// -- r3 : element index as smi
|
||||
// -- r4 : array literal index in function as smi
|
||||
// -----------------------------------
|
||||
|
||||
Label element_done;
|
||||
Label double_elements;
|
||||
Label smi_element;
|
||||
Label slow_elements;
|
||||
Label fast_elements;
|
||||
|
||||
__ CheckFastElements(r2, r5, &double_elements);
|
||||
// FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
|
||||
__ JumpIfSmi(r0, &smi_element);
|
||||
__ CheckFastSmiOnlyElements(r2, r5, &fast_elements);
|
||||
|
||||
// Store into the array literal requires a elements transition. Call into
|
||||
// the runtime.
|
||||
__ bind(&slow_elements);
|
||||
// call.
|
||||
__ Push(r1, r3, r0);
|
||||
__ ldr(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ ldr(r5, FieldMemOperand(r5, JSFunction::kLiteralsOffset));
|
||||
__ Push(r5, r4);
|
||||
__ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
|
||||
|
||||
// Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
|
||||
__ bind(&fast_elements);
|
||||
__ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
|
||||
__ add(r6, r5, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
__ add(r6, r6, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
||||
__ str(r0, MemOperand(r6, 0));
|
||||
// Update the write barrier for the array store.
|
||||
__ RecordWrite(r5, r6, r0, kLRHasNotBeenSaved, kDontSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
|
||||
__ Ret();
|
||||
|
||||
// Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
|
||||
// FAST_ELEMENTS, and value is Smi.
|
||||
__ bind(&smi_element);
|
||||
__ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
|
||||
__ add(r6, r5, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
__ str(r0, FieldMemOperand(r6, FixedArray::kHeaderSize));
|
||||
__ Ret();
|
||||
|
||||
// Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
|
||||
__ bind(&double_elements);
|
||||
__ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
|
||||
__ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r10,
|
||||
&slow_elements);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -1580,56 +1580,12 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
}
|
||||
VisitForAccumulatorValue(subexpr);
|
||||
|
||||
__ ldr(r6, MemOperand(sp)); // Copy of array literal.
|
||||
__ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset));
|
||||
__ ldr(r2, FieldMemOperand(r6, JSObject::kMapOffset));
|
||||
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
|
||||
|
||||
Label element_done;
|
||||
Label double_elements;
|
||||
Label smi_element;
|
||||
Label slow_elements;
|
||||
Label fast_elements;
|
||||
__ CheckFastElements(r2, r3, &double_elements);
|
||||
|
||||
// FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
|
||||
__ JumpIfSmi(result_register(), &smi_element);
|
||||
__ CheckFastSmiOnlyElements(r2, r3, &fast_elements);
|
||||
|
||||
// Store into the array literal requires a elements transition. Call into
|
||||
// the runtime.
|
||||
__ bind(&slow_elements);
|
||||
__ push(r6); // Copy of array literal.
|
||||
__ mov(r1, Operand(Smi::FromInt(i)));
|
||||
__ mov(r2, Operand(Smi::FromInt(NONE))); // PropertyAttributes
|
||||
__ mov(r3, Operand(Smi::FromInt(strict_mode_flag()))); // Strict mode.
|
||||
__ Push(r1, result_register(), r2, r3);
|
||||
__ CallRuntime(Runtime::kSetProperty, 5);
|
||||
__ b(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
|
||||
__ bind(&double_elements);
|
||||
__ ldr(r1, MemOperand(sp)); // Copy of array literal.
|
||||
__ ldr(r2, FieldMemOperand(r1, JSObject::kMapOffset));
|
||||
__ mov(r3, Operand(Smi::FromInt(i)));
|
||||
__ StoreNumberToDoubleElements(result_register(), r3, r6, r1, r4, r5, r9,
|
||||
r7, &slow_elements);
|
||||
__ b(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
|
||||
__ bind(&fast_elements);
|
||||
__ str(result_register(), FieldMemOperand(r1, offset));
|
||||
// Update the write barrier for the array store.
|
||||
__ RecordWriteField(
|
||||
r1, offset, result_register(), r2, kLRHasBeenSaved, kDontSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
|
||||
__ b(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
|
||||
// FAST_ELEMENTS, and value is Smi.
|
||||
__ bind(&smi_element);
|
||||
__ str(result_register(), FieldMemOperand(r1, offset));
|
||||
// Fall through
|
||||
|
||||
__ bind(&element_done);
|
||||
__ mov(r4, Operand(Smi::FromInt(expr->literal_index())));
|
||||
StoreArrayLiteralElementStub stub;
|
||||
__ CallStub(&stub);
|
||||
|
||||
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
|
||||
}
|
||||
|
@ -775,7 +775,8 @@ BUILTIN(ArraySlice) {
|
||||
|
||||
// Set the ElementsKind.
|
||||
ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
|
||||
if (result_array->GetElementsKind() != elements_kind) {
|
||||
if (IsMoreGeneralElementsKindTransition(result_array->GetElementsKind(),
|
||||
elements_kind)) {
|
||||
MaybeObject* maybe = result_array->TransitionElementsKind(elements_kind);
|
||||
if (maybe->IsFailure()) return maybe;
|
||||
}
|
||||
@ -875,7 +876,8 @@ BUILTIN(ArraySplice) {
|
||||
|
||||
// Set the ElementsKind.
|
||||
ElementsKind elements_kind = array->GetElementsKind();
|
||||
if (result_array->GetElementsKind() != elements_kind) {
|
||||
if (IsMoreGeneralElementsKindTransition(result_array->GetElementsKind(),
|
||||
elements_kind)) {
|
||||
MaybeObject* maybe = result_array->TransitionElementsKind(elements_kind);
|
||||
if (maybe->IsFailure()) return maybe;
|
||||
}
|
||||
|
@ -7046,16 +7046,14 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
|
||||
Label slow_elements_from_double;
|
||||
Label fast_elements;
|
||||
|
||||
if (!FLAG_trace_elements_transitions) {
|
||||
__ CheckFastElements(edi, &double_elements);
|
||||
__ CheckFastElements(edi, &double_elements);
|
||||
|
||||
// FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
|
||||
__ JumpIfSmi(eax, &smi_element);
|
||||
__ CheckFastSmiOnlyElements(edi, &fast_elements, Label::kNear);
|
||||
// FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
|
||||
__ JumpIfSmi(eax, &smi_element);
|
||||
__ CheckFastSmiOnlyElements(edi, &fast_elements, Label::kNear);
|
||||
|
||||
// Store into the array literal requires a elements transition. Call into
|
||||
// the runtime.
|
||||
}
|
||||
// Store into the array literal requires a elements transition. Call into
|
||||
// the runtime.
|
||||
|
||||
__ bind(&slow_elements);
|
||||
__ pop(edi); // Pop return address and remember to put back later for tail
|
||||
@ -7070,49 +7068,45 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
|
||||
// place.
|
||||
__ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
|
||||
|
||||
if (!FLAG_trace_elements_transitions) {
|
||||
// Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
|
||||
__ bind(&double_elements);
|
||||
__ bind(&slow_elements_from_double);
|
||||
__ pop(edx);
|
||||
__ jmp(&slow_elements);
|
||||
|
||||
__ push(edx);
|
||||
__ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset));
|
||||
__ StoreNumberToDoubleElements(eax,
|
||||
edx,
|
||||
ecx,
|
||||
edi,
|
||||
xmm0,
|
||||
&slow_elements_from_double,
|
||||
false);
|
||||
__ pop(edx);
|
||||
__ jmp(&element_done);
|
||||
// Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
|
||||
__ bind(&fast_elements);
|
||||
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
|
||||
__ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size,
|
||||
FixedArrayBase::kHeaderSize));
|
||||
__ mov(Operand(ecx, 0), eax);
|
||||
// Update the write barrier for the array store.
|
||||
__ RecordWrite(ebx, ecx, eax,
|
||||
kDontSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ ret(0);
|
||||
|
||||
__ bind(&slow_elements_from_double);
|
||||
__ pop(edx);
|
||||
__ jmp(&slow_elements);
|
||||
// Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
|
||||
// FAST_ELEMENTS, and value is Smi.
|
||||
__ bind(&smi_element);
|
||||
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
|
||||
__ mov(FieldOperand(ebx, ecx, times_half_pointer_size,
|
||||
FixedArrayBase::kHeaderSize), eax);
|
||||
__ ret(0);
|
||||
|
||||
// Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
|
||||
__ bind(&fast_elements);
|
||||
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
|
||||
__ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size,
|
||||
FixedArrayBase::kHeaderSize));
|
||||
__ mov(Operand(ecx, 0), eax);
|
||||
// Update the write barrier for the array store.
|
||||
__ RecordWrite(ebx, ecx, eax,
|
||||
kDontSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ jmp(&element_done);
|
||||
// Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
|
||||
__ bind(&double_elements);
|
||||
|
||||
// Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
|
||||
// FAST_ELEMENTS, and value is Smi.
|
||||
__ bind(&smi_element);
|
||||
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
|
||||
__ mov(FieldOperand(ebx, ecx, times_half_pointer_size,
|
||||
FixedArrayBase::kHeaderSize), eax);
|
||||
// Fall through
|
||||
__ bind(&element_done);
|
||||
__ ret(0);
|
||||
}
|
||||
__ push(edx);
|
||||
__ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset));
|
||||
__ StoreNumberToDoubleElements(eax,
|
||||
edx,
|
||||
ecx,
|
||||
edi,
|
||||
xmm0,
|
||||
&slow_elements_from_double,
|
||||
false);
|
||||
__ pop(edx);
|
||||
__ ret(0);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
@ -119,6 +119,18 @@ PropertyDetails PropertyDetails::AsDeleted() {
|
||||
}
|
||||
|
||||
|
||||
bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
|
||||
ElementsKind to_kind) {
|
||||
if (to_kind == FAST_ELEMENTS) {
|
||||
return from_kind == FAST_SMI_ONLY_ELEMENTS ||
|
||||
from_kind == FAST_DOUBLE_ELEMENTS;
|
||||
} else {
|
||||
return to_kind == FAST_DOUBLE_ELEMENTS &&
|
||||
from_kind == FAST_SMI_ONLY_ELEMENTS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsFixedArrayBase() {
|
||||
return IsFixedArray() || IsFixedDoubleArray();
|
||||
}
|
||||
|
@ -9501,6 +9501,9 @@ MUST_USE_RESULT MaybeObject* JSObject::TransitionElementsKind(
|
||||
MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS);
|
||||
Map* new_map;
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
if (FLAG_trace_elements_transitions) {
|
||||
PrintElementsTransition(stdout, from_kind, elms, FAST_ELEMENTS, elms);
|
||||
}
|
||||
set_map(new_map);
|
||||
return this;
|
||||
}
|
||||
|
@ -167,6 +167,8 @@ static const int kElementsKindCount =
|
||||
|
||||
void PrintElementsKind(FILE* out, ElementsKind kind);
|
||||
|
||||
inline bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
|
||||
ElementsKind to_kind);
|
||||
|
||||
// Setter that skips the write barrier if mode is SKIP_WRITE_BARRIER.
|
||||
enum WriteBarrierMode { SKIP_WRITE_BARRIER, UPDATE_WRITE_BARRIER };
|
||||
|
@ -5971,16 +5971,14 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
|
||||
Label slow_elements;
|
||||
Label fast_elements;
|
||||
|
||||
if (!FLAG_trace_elements_transitions) {
|
||||
__ CheckFastElements(rdi, &double_elements);
|
||||
__ CheckFastElements(rdi, &double_elements);
|
||||
|
||||
// FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
|
||||
__ JumpIfSmi(rax, &smi_element);
|
||||
__ CheckFastSmiOnlyElements(rdi, &fast_elements);
|
||||
// FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
|
||||
__ JumpIfSmi(rax, &smi_element);
|
||||
__ CheckFastSmiOnlyElements(rdi, &fast_elements);
|
||||
|
||||
// Store into the array literal requires a elements transition. Call into
|
||||
// the runtime.
|
||||
}
|
||||
// Store into the array literal requires a elements transition. Call into
|
||||
// the runtime.
|
||||
|
||||
__ bind(&slow_elements);
|
||||
__ pop(rdi); // Pop return address and remember to put back later for tail
|
||||
@ -5995,44 +5993,40 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
|
||||
// place.
|
||||
__ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
|
||||
|
||||
if (!FLAG_trace_elements_transitions) {
|
||||
// Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
|
||||
__ bind(&double_elements);
|
||||
// Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
|
||||
__ bind(&fast_elements);
|
||||
__ SmiToInteger32(kScratchRegister, rcx);
|
||||
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
|
||||
__ lea(rcx, FieldOperand(rbx, kScratchRegister, times_pointer_size,
|
||||
FixedArrayBase::kHeaderSize));
|
||||
__ movq(Operand(rcx, 0), rax);
|
||||
// Update the write barrier for the array store.
|
||||
__ RecordWrite(rbx, rcx, rax,
|
||||
kDontSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ ret(0);
|
||||
|
||||
__ movq(r9, FieldOperand(rbx, JSObject::kElementsOffset));
|
||||
__ SmiToInteger32(r11, rcx);
|
||||
__ StoreNumberToDoubleElements(rax,
|
||||
r9,
|
||||
r11,
|
||||
xmm0,
|
||||
&slow_elements);
|
||||
__ jmp(&element_done);
|
||||
// Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
|
||||
// FAST_ELEMENTS, and value is Smi.
|
||||
__ bind(&smi_element);
|
||||
__ SmiToInteger32(kScratchRegister, rcx);
|
||||
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
|
||||
__ movq(FieldOperand(rbx, kScratchRegister, times_pointer_size,
|
||||
FixedArrayBase::kHeaderSize), rax);
|
||||
__ ret(0);
|
||||
|
||||
// Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
|
||||
__ bind(&fast_elements);
|
||||
__ SmiToInteger32(kScratchRegister, rcx);
|
||||
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
|
||||
__ lea(rcx, FieldOperand(rbx, kScratchRegister, times_pointer_size,
|
||||
FixedArrayBase::kHeaderSize));
|
||||
__ movq(Operand(rcx, 0), rax);
|
||||
// Update the write barrier for the array store.
|
||||
__ RecordWrite(rbx, rcx, rax,
|
||||
kDontSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ jmp(&element_done);
|
||||
// Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
|
||||
__ bind(&double_elements);
|
||||
|
||||
// Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
|
||||
// FAST_ELEMENTS, and value is Smi.
|
||||
__ bind(&smi_element);
|
||||
__ SmiToInteger32(kScratchRegister, rcx);
|
||||
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
|
||||
__ movq(FieldOperand(rbx, kScratchRegister, times_pointer_size,
|
||||
FixedArrayBase::kHeaderSize), rax);
|
||||
// Fall through
|
||||
__ bind(&element_done);
|
||||
__ ret(0);
|
||||
}
|
||||
__ movq(r9, FieldOperand(rbx, JSObject::kElementsOffset));
|
||||
__ SmiToInteger32(r11, rcx);
|
||||
__ StoreNumberToDoubleElements(rax,
|
||||
r9,
|
||||
r11,
|
||||
xmm0,
|
||||
&slow_elements);
|
||||
__ ret(0);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
Loading…
Reference in New Issue
Block a user