DCHECK(ToRegister(instr->result()).is(r0));
__ mov(r0, Operand(instr->arity()));
- __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
+ if (instr->arity() == 1) {
+ // We only need the allocation site for the case we have a length argument.
+ // The case may bail out to the runtime, which will determine the correct
+ // elements kind with the site.
+ __ Move(r2, instr->hydrogen()->site());
+ } else {
+ __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
+ }
ElementsKind kind = instr->hydrogen()->elements_kind();
AllocationSiteOverrideMode override_mode =
(AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
DCHECK(ToRegister(instr->constructor()).is(x1));
__ Mov(x0, Operand(instr->arity()));
- __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
+ if (instr->arity() == 1) {
+ // We only need the allocation site for the case we have a length argument.
+ // The case may bail out to the runtime, which will determine the correct
+ // elements kind with the site.
+ __ Mov(x2, instr->hydrogen()->site());
+ } else {
+ __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
+ }
+
ElementsKind kind = instr->hydrogen()->elements_kind();
AllocationSiteOverrideMode override_mode =
class HCallNewArray FINAL : public HBinaryCall {
public:
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallNewArray,
- HValue*,
- int,
- ElementsKind);
+ DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int,
+ ElementsKind,
+ Handle<AllocationSite>);
HValue* context() { return first(); }
HValue* constructor() { return second(); }
std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
ElementsKind elements_kind() const { return elements_kind_; }
+ Handle<AllocationSite> site() const { return site_; }
DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
private:
HCallNewArray(HValue* context, HValue* constructor, int argument_count,
- ElementsKind elements_kind)
+ ElementsKind elements_kind, Handle<AllocationSite> site)
: HBinaryCall(context, constructor, argument_count),
- elements_kind_(elements_kind) {}
+ elements_kind_(elements_kind),
+ site_(site) {}
ElementsKind elements_kind_;
+ Handle<AllocationSite> site_;
};
}
HInstruction* call = PreProcessCall(New<HCallNewArray>(
- function, arguments_count + 1, site->GetElementsKind()));
+ function, arguments_count + 1, site->GetElementsKind(), site));
if (expression->IsCall()) {
Drop(1);
}
DCHECK(ToRegister(instr->result()).is(eax));
__ Move(eax, Immediate(instr->arity()));
- __ mov(ebx, isolate()->factory()->undefined_value());
+ if (instr->arity() == 1) {
+ // We only need the allocation site for the case we have a length argument.
+ // The case may bail out to the runtime, which will determine the correct
+ // elements kind with the site.
+ __ mov(ebx, instr->hydrogen()->site());
+ } else {
+ __ mov(ebx, isolate()->factory()->undefined_value());
+ }
+
ElementsKind kind = instr->hydrogen()->elements_kind();
AllocationSiteOverrideMode override_mode =
(AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
DCHECK(ToRegister(instr->result()).is(v0));
__ li(a0, Operand(instr->arity()));
- __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
+ if (instr->arity() == 1) {
+ // We only need the allocation site for the case we have a length argument.
+ // The case may bail out to the runtime, which will determine the correct
+ // elements kind with the site.
+ __ li(a2, instr->hydrogen()->site());
+ } else {
+ __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
+ }
ElementsKind kind = instr->hydrogen()->elements_kind();
AllocationSiteOverrideMode override_mode =
(AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
DCHECK(ToRegister(instr->result()).is(v0));
__ li(a0, Operand(instr->arity()));
- __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
+ if (instr->arity() == 1) {
+ // We only need the allocation site for the case we have a length argument.
+ // The case may bail out to the runtime, which will determine the correct
+ // elements kind with the site.
+ __ li(a2, instr->hydrogen()->site());
+ } else {
+ __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
+ }
ElementsKind kind = instr->hydrogen()->elements_kind();
AllocationSiteOverrideMode override_mode =
(AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
}
+bool JSArray::SetElementsLengthWouldNormalize(
+ Heap* heap, Handle<Object> new_length_handle) {
+ // If the new array won't fit in a some non-trivial fraction of the max old
+ // space size, then force it to go dictionary mode.
+ int max_fast_array_size =
+ static_cast<int>((heap->MaxOldGenerationSize() / kDoubleSize) / 4);
+ return new_length_handle->IsNumber() &&
+ NumberToInt32(*new_length_handle) >= max_fast_array_size;
+}
+
+
bool JSArray::AllowsSetElementsLength() {
bool result = elements()->IsFixedArray() || elements()->IsFixedDoubleArray();
DCHECK(result == !HasExternalArrayElements());
MaybeHandle<Object> JSArray::SetElementsLength(
Handle<JSArray> array,
Handle<Object> new_length_handle) {
- if (array->HasFastElements()) {
- // If the new array won't fit in a some non-trivial fraction of the max old
- // space size, then force it to go dictionary mode.
- int max_fast_array_size = static_cast<int>(
- (array->GetHeap()->MaxOldGenerationSize() / kDoubleSize) / 4);
- if (new_length_handle->IsNumber() &&
- NumberToInt32(*new_length_handle) >= max_fast_array_size) {
- NormalizeElements(array);
- }
+ if (array->HasFastElements() &&
+ SetElementsLengthWouldNormalize(array->GetHeap(), new_length_handle)) {
+ NormalizeElements(array);
}
// We should never end in here with a pixel or external array.
// capacity is non-zero.
static void Initialize(Handle<JSArray> array, int capacity, int length = 0);
+ // If the JSArray has fast elements, and new_length would result in
+ // normalization, returns true.
+ static inline bool SetElementsLengthWouldNormalize(
+ Heap* heap, Handle<Object> new_length_handle);
+
// Initializes the array to a certain length.
inline bool AllowsSetElementsLength();
// Can cause GC.
bool holey = false;
bool can_use_type_feedback = true;
+ bool can_inline_array_constructor = true;
if (caller_args->length() == 1) {
Handle<Object> argument_one = caller_args->at<Object>(0);
if (argument_one->IsSmi()) {
int value = Handle<Smi>::cast(argument_one)->value();
- if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
+ if (value < 0 || JSArray::SetElementsLengthWouldNormalize(isolate->heap(),
+ argument_one)) {
// the array is a dictionary in this case.
can_use_type_feedback = false;
} else if (value != 0) {
holey = true;
+ if (value >= JSObject::kInitialMaxFastElementArray) {
+ can_inline_array_constructor = false;
+ }
}
} else {
// Non-smi length argument produces a dictionary
RETURN_FAILURE_ON_EXCEPTION(
isolate, ArrayConstructInitializeElements(array, caller_args));
if (!site.is_null() &&
- (old_kind != array->GetElementsKind() || !can_use_type_feedback)) {
+ (old_kind != array->GetElementsKind() || !can_use_type_feedback ||
+ !can_inline_array_constructor)) {
// The arguments passed in caused a transition. This kind of complexity
// can't be dealt with in the inlined hydrogen array constructor case.
// We must mark the allocationsite as un-inlinable.
DCHECK(ToRegister(instr->result()).is(rax));
__ Set(rax, instr->arity());
- __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
+ if (instr->arity() == 1) {
+ // We only need the allocation site for the case we have a length argument.
+ // The case may bail out to the runtime, which will determine the correct
+ // elements kind with the site.
+ __ Move(rbx, instr->hydrogen()->site());
+ } else {
+ __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
+ }
+
ElementsKind kind = instr->hydrogen()->elements_kind();
AllocationSiteOverrideMode override_mode =
(AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
assertFalse(isHoley(a));
}
})();
+
+// Test: Make sure that crankshaft continues with feedback for large arrays.
+(function() {
+ function bar(len) { return new Array(len); }
+ var size = 100001;
+ // Perform a gc, because we are allocating a very large array and if a gc
+ // happens during the allocation we could lose our memento.
+ gc();
+ bar(size)[0] = 'string';
+ var res = bar(size);
+ assertKind(elements_kind.fast, bar(size));
+ %OptimizeFunctionOnNextCall(bar);
+ assertKind(elements_kind.fast, bar(size));
+ // But there is a limit, based on the size of the old generation, currently
+ // 22937600, but double it to prevent the test being too brittle.
+ var large_size = 22937600 * 2;
+ assertKind(elements_kind.dictionary, bar(large_size));
+})();
assertKind(elements_kind.fast, b);
a = create1(100000);
- assertKind(elements_kind.fast_smi_only, a);
+ assertKind(elements_kind.fast, a);
function create3(arg1, arg2, arg3) {
return Array(arg1, arg2, arg3);