case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
void MacroAssembler::CheckFastElements(Register map,
Register scratch,
Label* fail) {
- STATIC_ASSERT(FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 1);
ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue));
b(hi, fail);
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
}
break;
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
}
break;
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
}
-void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
- bool is_js_array) {
+void KeyedStoreStubCompiler::GenerateStoreFastElement(
+ MacroAssembler* masm,
+ bool is_js_array,
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : key
Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize));
__ str(value_reg, MemOperand(scratch));
__ mov(receiver_reg, value_reg);
+ ASSERT(elements_kind == FAST_ELEMENTS);
__ RecordWrite(elements_reg, // Object.
scratch, // Address.
receiver_reg, // Value.
elements->set(0, *array);
array = factory->NewFixedArray(0);
elements->set(1, *array);
+ Handle<Map> non_strict_arguments_elements_map =
+ factory->GetElementsTransitionMap(result,
+ NON_STRICT_ARGUMENTS_ELEMENTS);
+ result->set_map(*non_strict_arguments_elements_map);
+ ASSERT(result->HasNonStrictArgumentsElements());
result->set_elements(*elements);
global_context()->set_aliased_arguments_boilerplate(*result);
}
isolate()->builtins()->builtin(Builtins::kArrayConstructCode));
array_function->shared()->DontAdaptArguments();
+ // InternalArrays should not use Smi-Only array optimizations. There are too
+ // many places in the C++ runtime code (e.g. RegEx) that assume that
+ // elements in InternalArrays can be set to non-Smi values without going
+ // through a common bottleneck that would make the SMI_ONLY -> FAST_ELEMENT
+ // transition easy to trap. Moreover, they rarely are smi-only.
+ MaybeObject* maybe_map =
+ array_function->initial_map()->CopyDropTransitions();
+ Map* new_map;
+ if (!maybe_map->To<Map>(&new_map)) return maybe_map;
+ new_map->set_elements_kind(FAST_ELEMENTS);
+ array_function->set_initial_map(new_map);
+
// Make "length" magic on instances.
Handle<DescriptorArray> array_descriptors =
factory()->CopyAppendForeignDescriptor(
}
// 'array' now contains the JSArray we should initialize.
- ASSERT(array->HasFastElements());
+ ASSERT(array->HasFastTypeElements());
// Optimize the case where there is one argument and the argument is a
// small smi.
{ MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- array->SetContent(FixedArray::cast(obj));
+ MaybeObject* maybe_obj = array->SetContent(FixedArray::cast(obj));
+ if (maybe_obj->IsFailure()) return maybe_obj;
return array;
}
}
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
+ // Set length and elements on the array.
+ if (FLAG_smi_only_arrays) {
+ MaybeObject* maybe_object =
+ array->EnsureCanContainElements(FixedArray::cast(obj));
+ if (maybe_object->IsFailure()) return maybe_object;
+ }
+
AssertNoAllocation no_gc;
FixedArray* elms = FixedArray::cast(obj);
WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
elms->set(index, args[index+1], mode);
}
- // Set length and elements on the array.
array->set_elements(FixedArray::cast(obj));
array->set_length(len);
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
- array->set_elements(elms);
}
+ MaybeObject* maybe = array->EnsureCanContainElements(&args, 1, to_add);
+ if (maybe->IsFailure()) return maybe;
+
// Add the provided values.
AssertNoAllocation no_gc;
WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
elms->set(index + len, args[index + 1], mode);
}
+ if (elms != array->elements()) {
+ array->set_elements(elms);
+ }
+
// Set the length.
array->set_length(Smi::FromInt(new_length));
return Smi::FromInt(new_length);
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastElements());
+ ASSERT(array->HasFastTypeElements());
int len = Smi::cast(array->length())->value();
if (len == 0) return heap->undefined_value();
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastElements());
+ ASSERT(array->HasFastTypeElements());
int len = Smi::cast(array->length())->value();
int to_add = args.length() - 1;
// we should never hit this case.
ASSERT(to_add <= (Smi::kMaxValue - len));
+ if (FLAG_smi_only_arrays) {
+ MaybeObject* maybe_object =
+ array->EnsureCanContainElements(&args, 1, to_add);
+ if (maybe_object->IsFailure()) return maybe_object;
+ }
+
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* new_elms = FixedArray::cast(obj);
-
AssertNoAllocation no_gc;
if (len > 0) {
CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len);
}
FillWithHoles(heap, new_elms, new_length, capacity);
-
elms = new_elms;
array->set_elements(elms);
} else {
}
FixedArray* result_elms = FixedArray::cast(result);
+ if (FLAG_smi_only_arrays) {
+ MaybeObject* maybe_object =
+ result_array->EnsureCanContainElements(result_elms);
+ if (maybe_object->IsFailure()) return maybe_object;
+ }
+
AssertNoAllocation no_gc;
CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len);
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastElements());
+ ASSERT(array->HasFastTypeElements());
int len = Smi::cast(array->length())->value();
int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
+ if (FLAG_smi_only_arrays) {
+ MaybeObject* maybe = array->EnsureCanContainElements(&args, 3, item_count);
+ if (maybe->IsFailure()) return maybe;
+ }
+
int new_length = len - actual_delete_count + item_count;
+ bool elms_changed = false;
if (item_count < actual_delete_count) {
// Shrink the array.
const bool trim_array = !heap->lo_space()->Contains(elms) &&
}
elms = LeftTrimFixedArray(heap, elms, delta);
- array->set_elements(elms);
+
+ elms_changed = true;
} else {
AssertNoAllocation no_gc;
MoveElements(heap, &no_gc,
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
- array->set_elements(elms);
+ elms_changed = true;
} else {
AssertNoAllocation no_gc;
MoveElements(heap, &no_gc,
elms->set(k, args[3 + k - actual_start], mode);
}
+ if (elms_changed) {
+ array->set_elements(elms);
+ }
+
// Set the length.
array->set_length(Smi::FromInt(new_length));
}
FixedArray* result_elms = FixedArray::cast(result);
+ if (FLAG_smi_only_arrays) {
+ for (int i = 0; i < n_arguments; i++) {
+ JSArray* array = JSArray::cast(args[i]);
+ int len = Smi::cast(array->length())->value();
+ if (len > 0) {
+ FixedArray* elms = FixedArray::cast(array->elements());
+ MaybeObject* maybe_object =
+ result_array->EnsureCanContainElements(elms);
+ if (maybe_object->IsFailure()) return maybe_object;
+ }
+ }
+ }
+
// Copy data.
AssertNoAllocation no_gc;
int start_pos = 0;
void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
break;
case FAST_DOUBLE_ELEMENTS:
void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
case FAST_ELEMENTS:
- KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
+ case FAST_SMI_ONLY_ELEMENTS: {
+ KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
+ is_js_array_,
+ elements_kind_);
+ }
break;
case FAST_DOUBLE_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
public:
static MaybeObject* DeleteCommon(JSObject* obj,
uint32_t key) {
- ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements());
+ ASSERT(obj->HasFastElements() ||
+ obj->HasFastSmiOnlyElements() ||
+ obj->HasFastArgumentsElements());
Heap* heap = obj->GetHeap();
FixedArray* backing_store = FixedArray::cast(obj->elements());
if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
void ElementsAccessor::InitializeOncePerProcess() {
static struct ConcreteElementsAccessors {
+ // Use the fast element handler for smi-only arrays. The implementation is
+ // currently identical.
+ FastElementsAccessor fast_smi_elements_handler;
FastElementsAccessor fast_elements_handler;
FastDoubleElementsAccessor fast_double_elements_handler;
DictionaryElementsAccessor dictionary_elements_handler;
} element_accessors;
static ElementsAccessor* accessor_array[] = {
+ &element_accessors.fast_smi_elements_handler,
&element_accessors.fast_elements_handler,
&element_accessors.fast_double_elements_handler,
&element_accessors.dictionary_elements_handler,
&element_accessors.pixel_elements_handler
};
+ STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
+ kElementsKindCount);
+
elements_accessors_ = accessor_array;
}
}
-Handle<Map> Factory::NewMap(InstanceType type, int instance_size) {
+Handle<Map> Factory::NewMap(InstanceType type,
+ int instance_size,
+ ElementsKind elements_kind) {
CALL_HEAP_FUNCTION(
isolate(),
- isolate()->heap()->AllocateMap(type, instance_size),
+ isolate()->heap()->AllocateMap(type, instance_size, elements_kind),
Map);
}
if (force_initial_map ||
type != JS_OBJECT_TYPE ||
instance_size != JSObject::kHeaderSize) {
- Handle<Map> initial_map = NewMap(type, instance_size);
+ ElementsKind default_elements_kind = FLAG_smi_only_arrays
+ ? FAST_SMI_ONLY_ELEMENTS
+ : FAST_ELEMENTS;
+ Handle<Map> initial_map = NewMap(type,
+ instance_size,
+ default_elements_kind);
function->set_initial_map(*initial_map);
initial_map->set_constructor(*function);
}
Handle<JSArray> result =
Handle<JSArray>::cast(NewJSObject(isolate()->array_function(),
pretenure));
- result->SetContent(*elements);
+ SetContent(result, elements);
return result;
}
+void Factory::SetContent(Handle<JSArray> array,
+ Handle<FixedArray> elements) {
+ CALL_HEAP_FUNCTION_VOID(
+ isolate(),
+ array->SetContent(*elements));
+}
+
+
+void Factory::EnsureCanContainNonSmiElements(Handle<JSArray> array) {
+ CALL_HEAP_FUNCTION_VOID(
+ isolate(),
+ array->EnsureCanContainNonSmiElements());
+}
+
+
Handle<JSProxy> Factory::NewJSProxy(Handle<Object> handler,
Handle<Object> prototype) {
CALL_HEAP_FUNCTION(
Handle<JSGlobalPropertyCell> NewJSGlobalPropertyCell(
Handle<Object> value);
- Handle<Map> NewMap(InstanceType type, int instance_size);
+ Handle<Map> NewMap(InstanceType type,
+ int instance_size,
+ ElementsKind elements_kind = FAST_ELEMENTS);
Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
Handle<FixedArray> elements,
PretenureFlag pretenure = NOT_TENURED);
+ void SetContent(Handle<JSArray> array, Handle<FixedArray> elements);
+
+ void EnsureCanContainNonSmiElements(Handle<JSArray> array);
+
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
// Change the type of the argument into a JS object/function and reinitialize.
// Flags for experimental implementation features.
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
+DEFINE_bool(smi_only_arrays, false, "tracks arrays with only smi values")
DEFINE_bool(string_slices, false, "use string slices")
// Flags for Crankshaft.
}
-MaybeObject* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
+MaybeObject* Heap::AllocateMap(InstanceType instance_type,
+ int instance_size,
+ ElementsKind elements_kind) {
Object* result;
{ MaybeObject* maybe_result = AllocateRawMap();
if (!maybe_result->ToObject(&result)) return maybe_result;
map->set_unused_property_fields(0);
map->set_bit_field(0);
map->set_bit_field2(1 << Map::kIsExtensible);
- map->set_elements_kind(FAST_ELEMENTS);
+ map->set_elements_kind(elements_kind);
// If the map object is aligned fill the padding area with Smi 0 objects.
if (Map::kPadStart < Map::kSize) {
{ MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
if (!maybe_obj->ToObject(&obj)) return false;
}
- set_neander_map(Map::cast(obj));
+ // Don't use Smi-only elements optimizations for objects with the neander
+ // map. There are too many cases where element values are set directly with a
+ // bottleneck to trap the Smi-only -> fast elements transition, and there
+ // appears to be no benefit for optimize this case.
+ Map* new_neander_map = Map::cast(obj);
+ new_neander_map->set_elements_kind(FAST_ELEMENTS);
+ set_neander_map(new_neander_map);
{ MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map());
if (!maybe_obj->ToObject(&obj)) return false;
InitializeJSObjectFromMap(JSObject::cast(obj),
FixedArray::cast(properties),
map);
- ASSERT(JSObject::cast(obj)->HasFastElements());
+ ASSERT(JSObject::cast(obj)->HasFastSmiOnlyElements() ||
+ JSObject::cast(obj)->HasFastElements());
return obj;
}
object_size);
}
+ ASSERT(JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
FixedArray* properties = FixedArray::cast(source->properties());
// Update elements if necessary.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT MaybeObject* AllocateMap(InstanceType instance_type,
- int instance_size);
+ MUST_USE_RESULT MaybeObject* AllocateMap(
+ InstanceType instance_type,
+ int instance_size,
+ ElementsKind elements_kind = FAST_ELEMENTS);
// Allocates a partial map for bootstrapping.
MUST_USE_RESULT MaybeObject* AllocatePartialMap(InstanceType instance_type,
stream->Add("pixel");
break;
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS:
stream->Add("pixel");
break;
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
HValue* key = AddInstruction(
new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)),
Representation::Integer32()));
- AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value));
+ if (FLAG_smi_only_arrays) {
+ AddInstruction(BuildStoreKeyedGeneric(literal, key, value));
+ } else {
+ AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value));
+ }
+
AddSimulate(expr->GetIdForElement(i));
}
return ast_context()->ReturnValue(Pop());
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
break;
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
HLoadExternalArrayPointer* external_elements = NULL;
HInstruction* checked_key = NULL;
- // FAST_ELEMENTS is assumed to be the first case.
- STATIC_ASSERT(FAST_ELEMENTS == 0);
+ // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS,
+ // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS are handled before external
+ // arrays.
+ STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ STATIC_ASSERT(FAST_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
- for (ElementsKind elements_kind = FAST_ELEMENTS;
+ for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND;
elements_kind <= LAST_ELEMENTS_KIND;
elements_kind = ElementsKind(elements_kind + 1)) {
- // After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we
- // need to add some code that's executed for all external array cases.
+ // After having handled FAST_ELEMENTS, FAST_SMI_ELEMENTS,
+ // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code
+ // that's executed for all external array cases.
STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND ==
LAST_ELEMENTS_KIND);
if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
set_current_block(if_true);
HInstruction* access;
- if (elements_kind == FAST_ELEMENTS ||
+ if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
+ elements_kind == FAST_ELEMENTS ||
elements_kind == FAST_DOUBLE_ELEMENTS) {
bool fast_double_elements =
elements_kind == FAST_DOUBLE_ELEMENTS;
- if (is_store && elements_kind == FAST_ELEMENTS) {
+ if (is_store && !fast_double_elements) {
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map(),
elements_kind_branch));
current_block()->Finish(typecheck);
set_current_block(if_jsarray);
- HInstruction* length = new(zone()) HJSArrayLength(object, typecheck);
- AddInstruction(length);
- checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
- if (is_store) {
- if (fast_double_elements) {
- access = AddInstruction(
- new(zone()) HStoreKeyedFastDoubleElement(elements,
- checked_key,
- val));
- } else {
- access = AddInstruction(
- new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
- }
+ HInstruction* length;
+ if (is_store && elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ // For now, fall back to the generic stub for
+ // FAST_SMI_ONLY_ELEMENTS
+ access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
} else {
- if (fast_double_elements) {
- access = AddInstruction(
- new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key));
+ length = new(zone()) HJSArrayLength(object, typecheck);
+ AddInstruction(length);
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ if (is_store) {
+ if (fast_double_elements) {
+ access = AddInstruction(
+ new(zone()) HStoreKeyedFastDoubleElement(elements,
+ checked_key,
+ val));
+ } else {
+ access = AddInstruction(
+ new(zone()) HStoreKeyedFastElement(elements,
+ checked_key,
+ val));
+ }
} else {
- access = AddInstruction(
- new(zone()) HLoadKeyedFastElement(elements, checked_key));
+ if (fast_double_elements) {
+ access = AddInstruction(
+ new(zone()) HLoadKeyedFastDoubleElement(elements,
+ checked_key));
+ } else {
+ access = AddInstruction(
+ new(zone()) HLoadKeyedFastElement(elements, checked_key));
+ }
+ Push(access);
}
- Push(access);
}
+
*has_side_effects |= access->HasSideEffects();
if (position != -1) {
access->set_position(position);
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ mov(FieldOperand(ebx, offset), result_register());
+ Label no_map_change;
+ __ JumpIfSmi(result_register(), &no_map_change);
// Update the write barrier for the array store.
- __ RecordWriteField(ebx, offset, result_register(), ecx, kDontSaveFPRegs);
+ __ RecordWriteField(ebx, offset, result_register(), ecx,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ if (FLAG_smi_only_arrays) {
+ __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
+ __ CheckFastSmiOnlyElements(edi, &no_map_change, Label::kNear);
+ __ push(Operand(esp, 0));
+ __ CallRuntime(Runtime::kNonSmiElementStored, 1);
+ }
+ __ bind(&no_map_change);
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
}
// ecx: key (a smi)
// edx: receiver
// edi: FixedArray receiver->elements
+
+ if (FLAG_smi_only_arrays) {
+ Label not_smi_only;
+ // Make sure the elements are smi-only.
+ __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ CheckFastSmiOnlyElements(ebx, ¬_smi_only, Label::kNear);
+ // Non-smis need to call into the runtime if the array is smi only.
+ __ JumpIfNotSmi(eax, &slow);
+ __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);
+ __ ret(0);
+ __ bind(¬_smi_only);
+ }
+
__ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);
// Update write barrier for the elements array address.
break;
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
break;
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
void MacroAssembler::CheckFastElements(Register map,
Label* fail,
Label::Distance distance) {
- STATIC_ASSERT(FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 1);
cmpb(FieldOperand(map, Map::kBitField2Offset),
Map::kMaximumBitField2FastElementValue);
j(above, fail, distance);
}
+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),
+ Map::kMaximumBitField2FastSmiOnlyElementValue);
+ j(below_equal, fail, distance);
+ cmpb(FieldOperand(map, Map::kBitField2Offset),
+ 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),
+ 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)
__ j(not_equal, &call_builtin);
if (argc == 1) { // Otherwise fall through to call builtin.
- Label exit, attempt_to_grow_elements, with_write_barrier;
+ Label attempt_to_grow_elements, with_write_barrier;
// Get the array's length into eax and calculate new length.
__ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
__ cmp(eax, Operand(ecx));
__ j(greater, &attempt_to_grow_elements);
+ // Check if value is a smi.
+ __ mov(ecx, Operand(esp, argc * kPointerSize));
+ __ JumpIfNotSmi(ecx, &with_write_barrier);
+
// Save new length.
__ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
__ lea(edx, FieldOperand(ebx,
eax, times_half_pointer_size,
FixedArray::kHeaderSize - argc * kPointerSize));
- __ mov(ecx, Operand(esp, argc * kPointerSize));
__ mov(Operand(edx, 0), ecx);
- // Check if value is a smi.
- __ JumpIfNotSmi(ecx, &with_write_barrier);
-
- __ bind(&exit);
__ ret((argc + 1) * kPointerSize);
__ bind(&with_write_barrier);
+ if (FLAG_smi_only_arrays) {
+ __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
+ __ CheckFastObjectElements(edi, &call_builtin);
+ }
+
+ // Save new length.
+ __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
+
+ // Push the element.
+ __ lea(edx, FieldOperand(ebx,
+ eax, times_half_pointer_size,
+ FixedArray::kHeaderSize - argc * kPointerSize));
+ __ mov(Operand(edx, 0), ecx);
+
__ RecordWrite(
ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ jmp(&call_builtin);
}
+ __ mov(edi, Operand(esp, 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(edi, &no_fast_elements_check);
+ __ mov(esi, FieldOperand(edx, HeapObject::kMapOffset));
+ __ CheckFastObjectElements(esi, &call_builtin, Label::kFar);
+ __ bind(&no_fast_elements_check);
+ }
+
// We could be lucky and the elements array could be at the top of
// new-space. In this case we can just grow it in place by moving the
// allocation pointer up.
// We fit and could grow elements.
__ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
- __ mov(ecx, Operand(esp, argc * kPointerSize));
// Push the argument...
- __ mov(Operand(edx, 0), ecx);
+ __ mov(Operand(edx, 0), edi);
// ... and fill the rest with holes.
for (int i = 1; i < kAllocationDelta; i++) {
__ mov(Operand(edx, i * kPointerSize),
// 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(ebx, edx, ecx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
+ __ RecordWrite(ebx, edx, edi, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
// Restore receiver to edx as finish sequence assumes it's here.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
}
-void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
- bool is_js_array) {
+void KeyedStoreStubCompiler::GenerateStoreFastElement(
+ MacroAssembler* masm,
+ bool is_js_array,
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
__ j(above_equal, &miss_force_generic);
}
- // Do the store and update the write barrier.
- __ lea(ecx, FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize));
- __ mov(Operand(ecx, 0), eax);
- // Make sure to preserve the value in register eax.
- __ mov(edx, Operand(eax));
- __ RecordWrite(edi, ecx, edx, kDontSaveFPRegs);
+ 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
+ // times_pointer_size
+ __ mov(FieldOperand(edi,
+ ecx,
+ times_half_pointer_size,
+ FixedArray::kHeaderSize), eax);
+ } 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
+ // times_pointer_size
+ __ lea(ecx, FieldOperand(edi,
+ ecx,
+ times_half_pointer_size,
+ FixedArray::kHeaderSize));
+ __ mov(Operand(ecx, 0), eax);
+ // Make sure to preserve the value in register eax.
+ __ mov(edx, Operand(eax));
+ __ RecordWrite(edi, ecx, edx, kDontSaveFPRegs);
+ }
// Done.
__ ret(0);
} else {
ASSERT(receiver_map->has_dictionary_elements() ||
receiver_map->has_fast_elements() ||
+ receiver_map->has_fast_smi_only_elements() ||
receiver_map->has_fast_double_elements() ||
receiver_map->has_external_array_elements());
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
return 3;
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
// Allocate the JSArray of the elements.
Handle<JSObject> elements = factory->NewJSObject(isolate->array_function());
if (elements->IsFailure()) return Object::cast(*elements);
- Handle<JSArray>::cast(elements)->SetContent(*elements_arr);
+
+ maybe_result = Handle<JSArray>::cast(elements)->SetContent(*elements_arr);
+ if (maybe_result->IsFailure()) return maybe_result;
// Set body.elements.
Handle<String> elements_sym = factory->LookupAsciiSymbol("elements");
Handle<JSObject> summary_obj =
factory->NewJSObject(isolate->array_function());
if (summary_obj->IsFailure()) return Object::cast(*summary_obj);
- Handle<JSArray>::cast(summary_obj)->SetContent(*summary_arr);
+
+ maybe_result = Handle<JSArray>::cast(summary_obj)->SetContent(*summary_arr);
+ if (maybe_result->IsFailure()) return maybe_result;
// Create the body object.
Handle<JSObject> body = factory->NewJSObject(isolate->object_function());
// Return the result as a JS array.
Handle<JSObject> lols = factory->NewJSObject(isolate->array_function());
- Handle<JSArray>::cast(lols)->SetContent(*list);
+
+ maybe_result = Handle<JSArray>::cast(lols)->SetContent(*list);
+ if (maybe_result->IsFailure()) return maybe_result;
Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
if (result->IsFailure()) return Object::cast(*result);
void MacroAssembler::CheckFastElements(Register map,
Register scratch,
Label* fail) {
- STATIC_ASSERT(FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 1);
lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
Branch(fail, hi, scratch, Operand(Map::kMaximumBitField2FastElementValue));
}
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
(map()->inobject_properties() + properties()->length() -
map()->NextFreePropertyIndex()));
}
- ASSERT_EQ(map()->has_fast_elements(),
+ ASSERT_EQ((map()->has_fast_elements() || map()->has_fast_smi_only_elements()),
(elements()->map() == GetHeap()->fixed_array_map() ||
elements()->map() == GetHeap()->fixed_cow_array_map()));
ASSERT(map()->has_fast_elements() == HasFastElements());
double value = get_scalar(i);
ASSERT(!isnan(value) ||
(BitCast<uint64_t>(value) ==
- BitCast<uint64_t>(canonical_not_the_hole_nan_as_double())));
+ BitCast<uint64_t>(canonical_not_the_hole_nan_as_double())) ||
+ ((BitCast<uint64_t>(value) & Double::kSignMask) != 0));
}
}
}
return static_cast<FixedArrayBase*>(array);
}
+void JSObject::ValidateSmiOnlyElements() {
+#if DEBUG
+ if (FLAG_smi_only_arrays &&
+ map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS) {
+ Heap* heap = GetHeap();
+ // Don't use elements, since integrity checks will fail if there
+ // are filler pointers in the array.
+ FixedArray* fixed_array =
+ reinterpret_cast<FixedArray*>(READ_FIELD(this, kElementsOffset));
+ Map* map = fixed_array->map();
+ // Arrays that have been shifted in place can't be verified.
+ if (map != heap->raw_unchecked_one_pointer_filler_map() &&
+ map != heap->raw_unchecked_two_pointer_filler_map() &&
+ map != heap->free_space_map()) {
+ for (int i = 0; i < fixed_array->length(); i++) {
+ Object* current = fixed_array->get(i);
+ ASSERT(current->IsSmi() || current == heap->the_hole_value());
+ }
+ }
+ }
+#endif
+}
+
+
+MaybeObject* JSObject::EnsureCanContainNonSmiElements() {
+#if DEBUG
+ ValidateSmiOnlyElements();
+#endif
+ if (FLAG_smi_only_arrays &&
+ (map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS)) {
+ Object* obj;
+ MaybeObject* maybe_obj = GetElementsTransitionMap(FAST_ELEMENTS);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ set_map(Map::cast(obj));
+ }
+ return this;
+}
+
+
+MaybeObject* JSObject::EnsureCanContainElements(Object** objects,
+ uint32_t count) {
+ if (FLAG_smi_only_arrays &&
+ map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS) {
+ for (uint32_t i = 0; i < count; ++i) {
+ Object* current = *objects++;
+ if (!current->IsSmi() && current != GetHeap()->the_hole_value()) {
+ return EnsureCanContainNonSmiElements();
+ }
+ }
+ }
+ return this;
+}
+
+
+MaybeObject* JSObject::EnsureCanContainElements(FixedArray* elements) {
+ if (FLAG_smi_only_arrays) {
+ Object** objects = reinterpret_cast<Object**>(
+ FIELD_ADDR(elements, elements->OffsetOfElementAt(0)));
+ return EnsureCanContainElements(objects, elements->length());
+ } else {
+ return this;
+ }
+}
+
void JSObject::set_elements(FixedArrayBase* value, WriteBarrierMode mode) {
- ASSERT(map()->has_fast_elements() ==
+ ASSERT((map()->has_fast_elements() ||
+ map()->has_fast_smi_only_elements()) ==
(value->map() == GetHeap()->fixed_array_map() ||
value->map() == GetHeap()->fixed_cow_array_map()));
ASSERT(map()->has_fast_double_elements() ==
value->IsFixedDoubleArray());
ASSERT(value->HasValidElements());
+#ifdef DEBUG
+ ValidateSmiOnlyElements();
+#endif
WRITE_FIELD(this, kElementsOffset, value);
CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kElementsOffset, value, mode);
}
void JSObject::initialize_elements() {
- ASSERT(map()->has_fast_elements());
+ ASSERT(map()->has_fast_elements() || map()->has_fast_smi_only_elements());
ASSERT(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array()));
WRITE_FIELD(this, kElementsOffset, GetHeap()->empty_fixed_array());
}
MaybeObject* JSObject::ResetElements() {
Object* obj;
- { MaybeObject* maybe_obj = GetElementsTransitionMap(FAST_ELEMENTS);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ ElementsKind elements_kind = FLAG_smi_only_arrays
+ ? FAST_SMI_ONLY_ELEMENTS
+ : FAST_ELEMENTS;
+ MaybeObject* maybe_obj = GetElementsTransitionMap(elements_kind);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
set_map(Map::cast(obj));
initialize_elements();
return this;
void FixedDoubleArray::Initialize(FixedArray* from) {
int old_length = from->length();
- ASSERT(old_length < length());
+ ASSERT(old_length <= length());
for (int i = 0; i < old_length; i++) {
Object* hole_or_object = from->get(i);
if (hole_or_object->IsTheHole()) {
ElementsKind JSObject::GetElementsKind() {
ElementsKind kind = map()->elements_kind();
- ASSERT((kind == FAST_ELEMENTS &&
- (elements()->map() == GetHeap()->fixed_array_map() ||
- elements()->map() == GetHeap()->fixed_cow_array_map())) ||
+#if DEBUG
+ FixedArrayBase* fixed_array =
+ reinterpret_cast<FixedArrayBase*>(READ_FIELD(this, kElementsOffset));
+ Map* map = fixed_array->map();
+ ASSERT(((kind == FAST_ELEMENTS || kind == FAST_SMI_ONLY_ELEMENTS) &&
+ (map == GetHeap()->fixed_array_map() ||
+ map == GetHeap()->fixed_cow_array_map())) ||
(kind == FAST_DOUBLE_ELEMENTS &&
- elements()->IsFixedDoubleArray()) ||
+ fixed_array->IsFixedDoubleArray()) ||
(kind == DICTIONARY_ELEMENTS &&
- elements()->IsFixedArray() &&
- elements()->IsDictionary()) ||
+ fixed_array->IsFixedArray() &&
+ fixed_array->IsDictionary()) ||
(kind > DICTIONARY_ELEMENTS));
+#endif
return kind;
}
}
+bool JSObject::HasFastSmiOnlyElements() {
+ return GetElementsKind() == FAST_SMI_ONLY_ELEMENTS;
+}
+
+
+bool JSObject::HasFastTypeElements() {
+ ElementsKind elements_kind = GetElementsKind();
+ return elements_kind == FAST_SMI_ONLY_ELEMENTS ||
+ elements_kind == FAST_ELEMENTS;
+}
+
+
bool JSObject::HasFastDoubleElements() {
return GetElementsKind() == FAST_DOUBLE_ELEMENTS;
}
}
+bool JSObject::HasNonStrictArgumentsElements() {
+ return GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS;
+}
+
+
bool JSObject::HasExternalArrayElements() {
HeapObject* array = elements();
ASSERT(array != NULL);
MaybeObject* JSObject::EnsureWritableFastElements() {
- ASSERT(HasFastElements());
+ ASSERT(HasFastTypeElements());
FixedArray* elems = FixedArray::cast(elements());
Isolate* isolate = GetIsolate();
if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
void JSArray::EnsureSize(int required_size) {
- ASSERT(HasFastElements());
+ ASSERT(HasFastTypeElements());
FixedArray* elts = FixedArray::cast(elements());
const int kArraySizeThatFitsComfortablyInNewSpace = 128;
if (elts->length() < required_size) {
}
-void JSArray::SetContent(FixedArray* storage) {
+MaybeObject* JSArray::SetContent(FixedArray* storage) {
+ MaybeObject* maybe_object = EnsureCanContainElements(storage);
+ if (maybe_object->IsFailure()) return maybe_object;
set_length(Smi::FromInt(storage->length()));
set_elements(storage);
+ return this;
}
case HEAP_NUMBER_TYPE:
HeapNumber::cast(this)->HeapNumberPrint(out);
break;
+ case FIXED_DOUBLE_ARRAY_TYPE:
+ FixedDoubleArray::cast(this)->FixedDoubleArrayPrint(out);
+ break;
case FIXED_ARRAY_TYPE:
FixedArray::cast(this)->FixedArrayPrint(out);
break;
}
+static void PrintElementsKind(FILE* out, ElementsKind kind) {
+ switch (kind) {
+ case FAST_SMI_ONLY_ELEMENTS:
+ PrintF(out, "FAST_SMI_ONLY_ELEMENTS");
+ break;
+ case FAST_ELEMENTS:
+ PrintF(out, "FAST_ELEMENTS");
+ break;
+ case FAST_DOUBLE_ELEMENTS:
+ PrintF(out, "FAST_DOUBLE_ELEMENTS");
+ break;
+ case DICTIONARY_ELEMENTS:
+ PrintF(out, "DICTIONARY_ELEMENTS");
+ break;
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
+ PrintF(out, "NON_STRICT_ARGUMENTS_ELEMENTS");
+ break;
+ case EXTERNAL_BYTE_ELEMENTS:
+ PrintF(out, "EXTERNAL_BYTE_ELEMENTS");
+ break;
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ PrintF(out, "EXTERNAL_UNSIGNED_BYTE_ELEMENTS");
+ break;
+ case EXTERNAL_SHORT_ELEMENTS:
+ PrintF(out, "EXTERNAL_SHORT_ELEMENTS");
+ break;
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ PrintF(out, "EXTERNAL_UNSIGNED_SHORT_ELEMENTS");
+ break;
+ case EXTERNAL_INT_ELEMENTS:
+ PrintF(out, "EXTERNAL_INT_ELEMENTS");
+ break;
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ PrintF(out, "EXTERNAL_UNSIGNED_INT_ELEMENTS");
+ break;
+ case EXTERNAL_FLOAT_ELEMENTS:
+ PrintF(out, "EXTERNAL_FLOAT_ELEMENTS");
+ break;
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ PrintF(out, "EXTERNAL_DOUBLE_ELEMENTS");
+ break;
+ case EXTERNAL_PIXEL_ELEMENTS:
+ PrintF(out, "EXTERNAL_DOUBLE_ELEMENTS");
+ break;
+ }
+}
+
+
void JSObject::PrintProperties(FILE* out) {
if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors();
PrintF(out, " (callback)\n");
break;
case ELEMENTS_TRANSITION:
- PrintF(out, " (elements transition)\n");
+ PrintF(out, "(elements transition to ");
+ PrintElementsKind(out,
+ Map::cast(descs->GetValue(i))->elements_kind());
+ PrintF(out, ")\n");
break;
case MAP_TRANSITION:
- PrintF(out, " (map transition)\n");
+ PrintF(out, "(map transition)\n");
break;
case CONSTANT_TRANSITION:
- PrintF(out, " (constant transition)\n");
+ PrintF(out, "(constant transition)\n");
break;
case NULL_DESCRIPTOR:
- PrintF(out, " (null descriptor)\n");
+ PrintF(out, "(null descriptor)\n");
break;
default:
UNREACHABLE();
void JSObject::PrintElements(FILE* out) {
- switch (GetElementsKind()) {
+ // Don't call GetElementsKind, its validation code can cause the printer to
+ // fail when debugging.
+ switch (map()->elements_kind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
// Print in array notation for non-sparse arrays.
FixedArray* p = FixedArray::cast(elements());
void JSObject::JSObjectPrint(FILE* out) {
PrintF(out, "%p: [JSObject]\n", reinterpret_cast<void*>(this));
- PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
- PrintF(out, " - prototype = %p\n", reinterpret_cast<void*>(GetPrototype()));
+ PrintF(out, " - map = %p [", reinterpret_cast<void*>(map()));
+ // Don't call GetElementsKind, its validation code can cause the printer to
+ // fail when debugging.
+ PrintElementsKind(out, this->map()->elements_kind());
+ PrintF(out,
+ "]\n - prototype = %p\n",
+ reinterpret_cast<void*>(GetPrototype()));
PrintF(out, " {\n");
PrintProperties(out);
PrintElements(out);
}
+void FixedDoubleArray::FixedDoubleArrayPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "FixedDoubleArray");
+ PrintF(out, " - length: %d", length());
+ for (int i = 0; i < length(); i++) {
+ PrintF(out, "\n [%d]: %g", i, get_scalar(i));
+ }
+ PrintF(out, "\n");
+}
+
+
void JSValue::JSValuePrint(FILE* out) {
HeapObject::PrintHeader(out, "ValueObject");
value()->Print(out);
if (array->IsDictionary()) return array;
ASSERT(HasFastElements() ||
+ HasFastSmiOnlyElements() ||
HasFastDoubleElements() ||
HasFastArgumentsElements());
// Compute the effective length and allocate a new backing store.
if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
}
} else {
- ASSERT(old_map->has_fast_elements());
+ ASSERT(old_map->has_fast_elements() ||
+ old_map->has_fast_smi_only_elements());
value = FixedArray::cast(array)->get(i);
}
PropertyDetails details = PropertyDetails(NONE, NORMAL);
bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
ElementsKind kind,
Object* object) {
- ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
+ ASSERT(kind == FAST_ELEMENTS ||
+ kind == DICTIONARY_ELEMENTS);
if (kind == FAST_ELEMENTS) {
int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value()
// Raw pixels and external arrays do not reference other
// objects.
break;
+ case FAST_SMI_ONLY_ELEMENTS:
+ break;
case FAST_ELEMENTS:
case DICTIONARY_ELEMENTS: {
FixedArray* elements = FixedArray::cast(this->elements());
if (is_element) {
switch (GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
break;
// Accessors overwrite previous callbacks (cf. with getters/setters).
switch (GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
break;
}
-MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
- int length) {
+MaybeObject* JSObject::SetFastElementsCapacityAndLength(
+ int capacity,
+ int length,
+ SetFastElementsCapacityMode set_capacity_mode) {
Heap* heap = GetHeap();
// We should never end in here with a pixel or external array.
ASSERT(!HasExternalArrayElements());
Map* new_map = NULL;
if (elements()->map() != heap->non_strict_arguments_elements_map()) {
Object* object;
- MaybeObject* maybe = GetElementsTransitionMap(FAST_ELEMENTS);
+ bool has_fast_smi_only_elements =
+ FLAG_smi_only_arrays &&
+ (set_capacity_mode == kAllowSmiOnlyElements) &&
+ (elements()->map()->has_fast_smi_only_elements() ||
+ elements() == heap->empty_fixed_array());
+ ElementsKind elements_kind = has_fast_smi_only_elements
+ ? FAST_SMI_ONLY_ELEMENTS
+ : FAST_ELEMENTS;
+ MaybeObject* maybe = GetElementsTransitionMap(elements_kind);
if (!maybe->ToObject(&object)) return maybe;
new_map = Map::cast(object);
}
- switch (GetElementsKind()) {
+ ElementsKind elements_kind = GetElementsKind();
+ switch (elements_kind) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
AssertNoAllocation no_gc;
- WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
+ WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc));
CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
set_map(new_map);
set_elements(new_elements);
AssertNoAllocation no_gc;
switch (GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
elems->Initialize(FixedArray::cast(elements()));
break;
uint32_t new_length = static_cast<uint32_t>(len->Number());
switch (GetElementsKind()) {
- case FAST_ELEMENTS: {
- case FAST_DOUBLE_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS: {
// Make sure we never try to shrink dense arrays into sparse arrays.
ASSERT(static_cast<uint32_t>(
FixedArrayBase::cast(elements())->length()) <= new_length);
Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
// Can't use this any more now because we may have had a GC!
for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
- self->SetContent(*new_backing);
+ GetIsolate()->factory()->SetContent(self, new_backing);
}
if (value < 0) return ArrayLengthRangeError(GetHeap());
ElementsKind elements_kind = GetElementsKind();
switch (elements_kind) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
int old_capacity = FixedArrayBase::cast(elements())->length();
if (value <= old_capacity) {
if (IsJSArray()) {
Object* obj;
- if (elements_kind == FAST_ELEMENTS) {
+ if (elements_kind == FAST_ELEMENTS ||
+ elements_kind == FAST_SMI_ONLY_ELEMENTS) {
MaybeObject* maybe_obj = EnsureWritableFastElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
} else {
Address filler_start;
int filler_size;
- if (GetElementsKind() == FAST_ELEMENTS) {
+ if (elements_kind == FAST_ELEMENTS ||
+ elements_kind == FAST_SMI_ONLY_ELEMENTS) {
FixedArray* fast_elements = FixedArray::cast(elements());
fast_elements->set_length(value);
filler_start = fast_elements->address() +
} else {
// Otherwise, fill the unused tail with holes.
int old_length = FastD2I(JSArray::cast(this)->length()->Number());
- if (GetElementsKind() == FAST_ELEMENTS) {
+ if (elements_kind == FAST_ELEMENTS ||
+ elements_kind == FAST_SMI_ONLY_ELEMENTS) {
FixedArray* fast_elements = FixedArray::cast(elements());
for (int i = value; i < old_length; i++) {
fast_elements->set_the_hole(i);
}
} else {
- ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ ASSERT(elements_kind == FAST_DOUBLE_ELEMENTS);
FixedDoubleArray* fast_double_elements =
FixedDoubleArray::cast(elements());
for (int i = value; i < old_length; i++) {
int new_capacity = value > min ? value : min;
if (!ShouldConvertToSlowElements(new_capacity)) {
MaybeObject* result;
- if (GetElementsKind() == FAST_ELEMENTS) {
- result = SetFastElementsCapacityAndLength(new_capacity, value);
+ if (elements_kind == FAST_ELEMENTS ||
+ elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ SetFastElementsCapacityMode set_capacity_mode =
+ elements_kind == FAST_SMI_ONLY_ELEMENTS
+ ? kAllowSmiOnlyElements
+ : kDontAllowSmiOnlyElements;
+ result = SetFastElementsCapacityAndLength(new_capacity,
+ value,
+ set_capacity_mode);
} else {
- ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ ASSERT(elements_kind == FAST_DOUBLE_ELEMENTS);
result = SetFastDoubleElementsCapacityAndLength(new_capacity,
value);
}
// len is not a number so make the array size one and
// set only element to len.
Object* obj;
- { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
FixedArray::cast(obj)->set(0, len);
+
+ maybe_obj = EnsureCanContainElements(&len, 1);
+ if (maybe_obj->IsFailure()) return maybe_obj;
+
if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
set_elements(FixedArray::cast(obj));
return this;
}
+MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
+ uint32_t first_arg,
+ uint32_t arg_count) {
+ return EnsureCanContainElements(args->arguments() - first_arg, arg_count);
+}
+
+
bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
switch (GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
uint32_t length = IsJSArray() ?
static_cast<uint32_t>
}
switch (GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
uint32_t length = IsJSArray() ?
static_cast<uint32_t>
ElementsKind kind = GetElementsKind();
switch (kind) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
uint32_t length = IsJSArray() ?
static_cast<uint32_t>
Object* value,
StrictModeFlag strict_mode,
bool check_prototype) {
- ASSERT(HasFastElements() || HasFastArgumentsElements());
+ ASSERT(HasFastTypeElements() ||
+ HasFastArgumentsElements());
FixedArray* backing_store = FixedArray::cast(elements());
if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
// Check whether there is extra space in fixed array.
if (index < length) {
+ if (HasFastSmiOnlyElements()) {
+ if (!value->IsSmi()) {
+ // If the value is a number, transition from smi-only to
+ // FastDoubleElements.
+ if (value->IsNumber()) {
+ MaybeObject* maybe =
+ SetFastDoubleElementsCapacityAndLength(length, length);
+ if (maybe->IsFailure()) return maybe;
+ FixedDoubleArray::cast(elements())->set(index, value->Number());
+ return value;
+ }
+ // Value is not a number, transition to generic fast elements.
+ MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS);
+ Map* new_map;
+ if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
+ set_map(new_map);
+ }
+ }
backing_store->set(index, value);
if (IsJSArray()) {
// Update the length of the array if needed.
if (!ShouldConvertToSlowElements(new_capacity)) {
ASSERT(static_cast<uint32_t>(new_capacity) > index);
Object* new_elements;
+ SetFastElementsCapacityMode set_capacity_mode =
+ value->IsSmi() && HasFastSmiOnlyElements()
+ ? kAllowSmiOnlyElements
+ : kDontAllowSmiOnlyElements;
MaybeObject* maybe =
- SetFastElementsCapacityAndLength(new_capacity, index + 1);
+ SetFastElementsCapacityAndLength(new_capacity,
+ index + 1,
+ set_capacity_mode);
if (!maybe->ToObject(&new_elements)) return maybe;
FixedArray::cast(new_elements)->set(index, value);
return value;
}
MaybeObject* result = CanConvertToFastDoubleElements()
? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
- : SetFastElementsCapacityAndLength(new_length, new_length);
+ : SetFastElementsCapacityAndLength(new_length,
+ new_length,
+ kDontAllowSmiOnlyElements);
if (result->IsFailure()) return result;
#ifdef DEBUG
if (FLAG_trace_normalization) {
if (IsJSArray()) {
CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
}
- MaybeObject* maybe_obj =
- SetFastElementsCapacityAndLength(elms_length, length);
+ MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
+ elms_length,
+ length,
+ kDontAllowSmiOnlyElements);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- return SetFastElement(index, value, strict_mode, check_prototype);
+ return SetFastElement(index,
+ value,
+ strict_mode,
+ check_prototype);
}
double double_value = value_is_smi
bool check_prototype) {
Isolate* isolate = GetIsolate();
switch (GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
return SetFastElement(index, value, strict_mode, check_prototype);
case FAST_DOUBLE_ELEMENTS:
break;
}
// Fall through.
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
backing_store = FixedArray::cast(backing_store_base);
*capacity = backing_store->length();
if (this->IsStringObjectWithCharacterAt(index)) return true;
switch (GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
uint32_t length = IsJSArray() ?
static_cast<uint32_t>(
PropertyAttributes filter) {
int counter = 0;
switch (GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
int length = IsJSArray() ?
Smi::cast(JSArray::cast(this)->length())->value() :
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
}
- ASSERT(HasFastElements() || HasFastDoubleElements());
+ ASSERT(HasFastTypeElements() ||
+ HasFastDoubleElements());
// Collect holes at the end, undefined before that and the rest at the
// start, and return the number of non-hole, non-undefined values.
namespace internal {
enum ElementsKind {
- // The "fast" kind for tagged values. Must be first to make it possible
- // to efficiently check maps if they have fast elements.
+ // The "fast" kind for elements that only contain SMI values. Must be first
+ // to make it possible to efficiently check maps for this kind.
+ FAST_SMI_ONLY_ELEMENTS,
+
+ // The "fast" kind for tagged values. Must be second to make it possible to
+ // efficiently check maps for this and the FAST_SMI_ONLY_ELEMENTS kind
+ // together at once.
FAST_ELEMENTS,
// The "fast" kind for unwrapped, non-tagged double values.
// Derived constants from ElementsKind
FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_BYTE_ELEMENTS,
LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS,
- FIRST_ELEMENTS_KIND = FAST_ELEMENTS,
+ FIRST_ELEMENTS_KIND = FAST_SMI_ONLY_ELEMENTS,
LAST_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS
};
MUST_USE_RESULT inline MaybeObject* ResetElements();
inline ElementsKind GetElementsKind();
inline ElementsAccessor* GetElementsAccessor();
+ inline bool HasFastSmiOnlyElements();
inline bool HasFastElements();
+ // Returns if an object has either FAST_ELEMENT or FAST_SMI_ONLY_ELEMENT
+ // elements. TODO(danno): Rename HasFastTypeElements to HasFastElements() and
+ // HasFastElements to HasFastObjectElements.
+ inline bool HasFastTypeElements();
inline bool HasFastDoubleElements();
+ inline bool HasNonStrictArgumentsElements();
inline bool HasDictionaryElements();
inline bool HasExternalPixelElements();
inline bool HasExternalArrayElements();
// Tests for the fast common case for property enumeration.
bool IsSimpleEnum();
+ inline void ValidateSmiOnlyElements();
+
+ // Makes sure that this object can contain non-smi Object as elements.
+ inline MaybeObject* EnsureCanContainNonSmiElements();
+
+ // Makes sure that this object can contain the specified elements.
+ inline MaybeObject* EnsureCanContainElements(Object** elements,
+ uint32_t count);
+ inline MaybeObject* EnsureCanContainElements(FixedArray* elements);
+ MaybeObject* EnsureCanContainElements(Arguments* arguments,
+ uint32_t first_arg,
+ uint32_t arg_count);
+
// Do we want to keep the elements in fast case when increasing the
// capacity?
bool ShouldConvertToSlowElements(int new_capacity);
Object* value,
StrictModeFlag strict_mode,
bool check_prototype);
+
MUST_USE_RESULT MaybeObject* SetDictionaryElement(uint32_t index,
Object* value,
StrictModeFlag strict_mode,
// The undefined object if index is out of bounds.
MaybeObject* GetElementWithInterceptor(Object* receiver, uint32_t index);
+ enum SetFastElementsCapacityMode {
+ kAllowSmiOnlyElements,
+ kDontAllowSmiOnlyElements
+ };
+
// Replace the elements' backing store with fast elements of the given
// capacity. Update the length for JSArrays. Returns the new backing
// store.
- MUST_USE_RESULT MaybeObject* SetFastElementsCapacityAndLength(int capacity,
- int length);
+ MUST_USE_RESULT MaybeObject* SetFastElementsCapacityAndLength(
+ int capacity,
+ int length,
+ SetFastElementsCapacityMode set_capacity_mode);
MUST_USE_RESULT MaybeObject* SetFastDoubleElementsCapacityAndLength(
int capacity,
int length);
(bit_field2() & kElementsKindMask) >> kElementsKindShift);
}
+ // Tells whether the instance has fast elements that are only Smis.
+ inline bool has_fast_smi_only_elements() {
+ return elements_kind() == FAST_SMI_ONLY_ELEMENTS;
+ }
+
// Tells whether the instance has fast elements.
- // Equivalent to instance->GetElementsKind() == FAST_ELEMENTS.
inline bool has_fast_elements() {
return elements_kind() == FAST_ELEMENTS;
}
return elements_kind() == FAST_DOUBLE_ELEMENTS;
}
+ inline bool has_non_strict_arguments_elements() {
+ return elements_kind() == NON_STRICT_ARGUMENTS_ELEMENTS;
+ }
+
inline bool has_external_array_elements() {
ElementsKind kind(elements_kind());
return kind >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
static const int kStringWrapperSafeForDefaultValueOf = 2;
static const int kAttachedToSharedFunctionInfo = 3;
// No bits can be used after kElementsKindFirstBit, they are all reserved for
- // storing ElementKind. for anything other than storing the ElementKind.
+ // storing ElementKind.
static const int kElementsKindShift = 4;
static const int kElementsKindBitCount = 4;
((1 << (kElementsKindShift + kElementsKindBitCount)) - 1);
static const int8_t kMaximumBitField2FastElementValue = static_cast<int8_t>(
(FAST_ELEMENTS + 1) << Map::kElementsKindShift) - 1;
+ static const int8_t kMaximumBitField2FastSmiOnlyElementValue =
+ static_cast<int8_t>((FAST_SMI_ONLY_ELEMENTS + 1) <<
+ Map::kElementsKindShift) - 1;
// Bit positions for bit field 3
static const int kIsShared = 0;
MUST_USE_RESULT MaybeObject* Initialize(int capacity);
// Set the content of the array to the content of storage.
- inline void SetContent(FixedArray* storage);
+ inline MaybeObject* SetContent(FixedArray* storage);
// Casting.
static inline JSArray* cast(Object* obj);
// Pixel elements cannot be created using an object literal.
ASSERT(!copy->HasExternalArrayElements());
switch (copy->GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
FixedArray* elements = FixedArray::cast(copy->elements());
if (elements->map() == heap->fixed_cow_array_map()) {
} else {
for (int i = 0; i < elements->length(); i++) {
Object* value = elements->get(i);
+ ASSERT(value->IsSmi() ||
+ value->IsTheHole() ||
+ (copy->GetElementsKind() == FAST_ELEMENTS));
if (value->IsJSObject()) {
JSObject* js_object = JSObject::cast(value);
{ MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
+ bool has_non_smi = false;
if (is_cow) {
-#ifdef DEBUG
// Copy-on-write arrays must be shallow (and simple).
- for (int i = 0; i < content->length(); i++) {
- ASSERT(!content->get(i)->IsFixedArray());
- }
+ if (FLAG_smi_only_arrays) {
+ for (int i = 0; i < content->length(); i++) {
+ Object* current = content->get(i);
+ ASSERT(!current->IsFixedArray());
+ if (!current->IsSmi()) {
+ has_non_smi = true;
+ }
+ }
+ } else {
+#if DEBUG
+ for (int i = 0; i < content->length(); i++) {
+ ASSERT(!content->get(i)->IsFixedArray());
+ }
#endif
+ }
} else {
for (int i = 0; i < content->length(); i++) {
- if (content->get(i)->IsFixedArray()) {
+ Object* current = content->get(i);
+ if (current->IsFixedArray()) {
// The value contains the constant_properties of a
// simple object or array literal.
Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
CreateLiteralBoilerplate(isolate, literals, fa);
if (result.is_null()) return result;
content->set(i, *result);
+ has_non_smi = true;
+ } else {
+ if (!current->IsSmi()) {
+ has_non_smi = true;
+ }
}
}
}
// Set the elements.
- Handle<JSArray>::cast(object)->SetContent(*content);
+ Handle<JSArray> js_object(Handle<JSArray>::cast(object));
+ isolate->factory()->SetContent(js_object, content);
+
+ if (FLAG_smi_only_arrays) {
+ if (has_non_smi && js_object->HasFastSmiOnlyElements()) {
+ isolate->factory()->EnsureCanContainNonSmiElements(js_object);
+ }
+ }
+
return object;
}
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_NonSmiElementStored) {
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSObject, object, 0);
+ if (FLAG_smi_only_arrays && object->HasFastSmiOnlyElements()) {
+ MaybeObject* maybe_map = object->GetElementsTransitionMap(FAST_ELEMENTS);
+ Map* map;
+ if (!maybe_map->To<Map>(&map)) return maybe_map;
+ object->set_map(Map::cast(map));
+ }
+ return *object;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
HandleScope scope(isolate);
ASSERT(args.length() == 4);
public:
explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
: array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
- length_(0) {
+ length_(0),
+ has_non_smi_elements_(false) {
// Require a non-zero initial size. Ensures that doubling the size to
// extend the array will work.
ASSERT(initial_capacity > 0);
explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
: array_(backing_store),
- length_(0) {
+ length_(0),
+ has_non_smi_elements_(false) {
// Require a non-zero initial size. Ensures that doubling the size to
// extend the array will work.
ASSERT(backing_store->length() > 0);
}
void Add(Object* value) {
+ ASSERT(!value->IsSmi());
ASSERT(length_ < capacity());
array_->set(length_, value);
length_++;
+ has_non_smi_elements_ = true;
}
void Add(Smi* value) {
+ ASSERT(value->IsSmi());
ASSERT(length_ < capacity());
array_->set(length_, value);
length_++;
}
Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
- target_array->set_elements(*array_);
+ FACTORY->SetContent(target_array, array_);
target_array->set_length(Smi::FromInt(length_));
return target_array;
}
private:
Handle<FixedArray> array_;
int length_;
+ bool has_non_smi_elements_;
};
int part_count = indices.length();
Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
+ MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
+ if (maybe_result->IsFailure()) return maybe_result;
result->set_length(Smi::FromInt(part_count));
ASSERT(result->HasFastElements());
// This assumption is used by the slice encoding in one or two smis.
ASSERT(Smi::kMaxValue >= String::kMaxLength);
+ MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
+ if (maybe_result->IsFailure()) return maybe_result;
+
int special_length = special->length();
if (!array->HasFastElements()) {
return isolate->Throw(isolate->heap()->illegal_argument_symbol());
NoHandleAllocation ha;
ASSERT(args.length() == 3);
CONVERT_CHECKED(JSArray, elements_array, args[0]);
- RUNTIME_ASSERT(elements_array->HasFastElements());
+ RUNTIME_ASSERT(elements_array->HasFastElements() ||
+ elements_array->HasFastSmiOnlyElements());
CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
CONVERT_CHECKED(String, separator, args[2]);
// elements_array is fast-mode JSarray of alternating positions
int bound_argc = 0;
if (!args[1]->IsNull()) {
CONVERT_ARG_CHECKED(JSArray, params, 1);
- RUNTIME_ASSERT(params->HasFastElements());
+ RUNTIME_ASSERT(params->HasFastTypeElements());
bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
bound_argc = Smi::cast(params->length())->value();
}
FlattenString(str);
CONVERT_ARG_CHECKED(JSArray, output, 1);
+
+ MaybeObject* maybe_result_array =
+ output->EnsureCanContainNonSmiElements();
+ if (maybe_result_array->IsFailure()) return maybe_result_array;
RUNTIME_ASSERT(output->HasFastElements());
AssertNoAllocation no_allocation;
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSArray, array, args[0]);
CONVERT_CHECKED(JSObject, element, args[1]);
- RUNTIME_ASSERT(array->HasFastElements());
+ RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
int length = Smi::cast(array->length())->value();
FixedArray* elements = FixedArray::cast(array->elements());
for (int i = 0; i < length; i++) {
List<uint32_t>* indices) {
ElementsKind kind = object->GetElementsKind();
switch (kind) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(object->elements()));
uint32_t length = static_cast<uint32_t>(elements->length());
ArrayConcatVisitor* visitor) {
uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
switch (receiver->GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
// Run through the elements FixedArray and use HasElement and GetElement
// to check the prototype for missing elements.
}
return *isolate->factory()->NewJSArrayWithElements(keys);
} else {
- ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
+ ASSERT(array->HasFastElements() ||
+ array->HasFastSmiOnlyElements() ||
+ array->HasFastDoubleElements());
Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
// -1 means start of array.
single_interval->set(0, Smi::FromInt(-1));
// Return result as a JS array.
Handle<JSObject> result =
isolate->factory()->NewJSObject(isolate->array_function());
- Handle<JSArray>::cast(result)->SetContent(*instances);
+ isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
return *result;
}
// Return result as JS array.
Object* result;
- { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
+ MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
isolate->context()->global_context()->array_function());
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- JSArray::cast(result)->SetContent(instances);
- return result;
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ return JSArray::cast(result)->SetContent(instances);
}
isolate->context()->global_context()->array_function());
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- JSArray::cast(result)->SetContent(instances);
- return result;
+ return JSArray::cast(result)->SetContent(instances);
}
return isolate->heap()->ToBoolean(obj->Has##Name()); \
}
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
F(InitializeConstContextSlot, 3, 1) \
F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
\
+ /* Arrays */ \
+ F(NonSmiElementStored, 1, 1) \
/* Debugging */ \
F(DebugPrint, 1, 1) \
F(DebugTrace, 0, 1) \
F(IS_VAR, 1, 1) \
\
/* expose boolean functions from objects-inl.h */ \
+ F(HasFastSmiOnlyElements, 1, 1) \
F(HasFastElements, 1, 1) \
F(HasFastDoubleElements, 1, 1) \
F(HasDictionaryElements, 1, 1) \
CodeList* handler_ics);
static void GenerateStoreFastElement(MacroAssembler* masm,
- bool is_js_array);
+ bool is_js_array,
+ ElementsKind element_kind);
static void GenerateStoreFastDoubleElement(MacroAssembler* masm,
bool is_js_array);
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
void MacroAssembler::CheckFastElements(Register map,
Label* fail,
Label::Distance distance) {
- STATIC_ASSERT(FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 1);
cmpb(FieldOperand(map, Map::kBitField2Offset),
Immediate(Map::kMaximumBitField2FastElementValue));
j(above, fail, distance);
__ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
break;
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
}
-void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
- bool is_js_array) {
+void KeyedStoreStubCompiler::GenerateStoreFastElement(
+ MacroAssembler* masm,
+ bool is_js_array,
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
__ 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);
// Done.
// Set array length to 0.
ok = array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
CHECK_EQ(Smi::FromInt(0), array->length());
- CHECK(array->HasFastElements()); // Must be in fast mode.
+ // Must be in fast mode.
+ CHECK(array->HasFastTypeElements());
// array[length] = name.
ok = array->SetElement(0, *name, kNonStrictMode, true)->ToObjectChecked();
// Flags: --allow-natives-syntax
// Test element kind of objects
+support_smi_only_arrays = %HasFastSmiOnlyElements([]);
+
var element_kind = {
+ fast_smi_only_elements : 0,
fast_elements : 1,
fast_double_elements : 2,
dictionary_elements : 3,
// We expect an object to only be of one element kind.
function assertKind(expected, obj){
- assertEquals(expected == element_kind.fast_elements,
- %HasFastElements(obj));
+ if (support_smi_only_arrays) {
+ assertEquals(expected == element_kind.fast_smi_only_elements,
+ %HasFastSmiOnlyElements(obj));
+ assertEquals(expected == element_kind.fast_elements,
+ %HasFastElements(obj));
+ } else {
+ assertEquals(expected == element_kind.fast_elements ||
+ expected == element_kind.fast_smi_only_elements,
+ %HasFastElements(obj));
+ }
assertEquals(expected == element_kind.fast_double_elements,
%HasFastDoubleElements(obj));
assertEquals(expected == element_kind.dictionary_elements,
me.drink = 0xC0C0A;
assertKind(element_kind.fast_elements, me);
+var too = [1,2,3];
+assertKind(element_kind.fast_smi_only_elements, too);
+too.dance = 0xD15C0;
+too.drink = 0xC0C0A;
+assertKind(element_kind.fast_smi_only_elements, too);
+
+// 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++) {
- you[i] = i;
+ var val = i;
+ if (i == 1336) {
+ assertKind(element_kind.fast_smi_only_elements, you);
+ val = new Object();
+ }
+ you[i] = val;
}
assertKind(element_kind.fast_elements, you);