Handlify PrepareSlowElementsForSort and JSArrayUpdateLengthFromIndex.

R=mvstanton@chromium.org

Review URL: https://codereview.chromium.org/238713003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20757 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-04-15 10:29:56 +00:00
parent b5cec2b72f
commit 134c2e75ad
2 changed files with 62 additions and 95 deletions

View File

@ -13089,26 +13089,15 @@ bool Map::IsValidElementsTransition(ElementsKind from_kind,
void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array,
uint32_t index,
Handle<Object> value) {
CALL_HEAP_FUNCTION_VOID(array->GetIsolate(),
array->JSArrayUpdateLengthFromIndex(index, *value));
}
MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
Object* value) {
uint32_t old_len = 0;
CHECK(length()->ToArrayIndex(&old_len));
CHECK(array->length()->ToArrayIndex(&old_len));
// Check to see if we need to update the length. For now, we make
// sure that the length stays within 32-bits (unsigned).
if (index >= old_len && index != 0xffffffff) {
Object* len;
{ MaybeObject* maybe_len =
GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
if (!maybe_len->ToObject(&len)) return maybe_len;
}
set_length(len);
Handle<Object> len = array->GetIsolate()->factory()->NewNumber(
static_cast<double>(index) + 1);
array->set_length(*len);
}
return value;
}
@ -14526,107 +14515,88 @@ Handle<NameDictionary> NameDictionary::AddNameEntry(Handle<NameDictionary> dict,
Handle<Object> JSObject::PrepareSlowElementsForSort(
Handle<JSObject> object, uint32_t limit) {
CALL_HEAP_FUNCTION(object->GetIsolate(),
object->PrepareSlowElementsForSort(limit),
Object);
}
// Collates undefined and unexisting elements below limit from position
// zero of the elements. The object stays in Dictionary mode.
MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
ASSERT(HasDictionaryElements());
ASSERT(object->HasDictionaryElements());
Isolate* isolate = object->GetIsolate();
// Must stay in dictionary mode, either because of requires_slow_elements,
// or because we are not going to sort (and therefore compact) all of the
// elements.
SeededNumberDictionary* dict = element_dictionary();
HeapNumber* result_double = NULL;
if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
// Allocate space for result before we start mutating the object.
Object* new_double;
{ MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
}
result_double = HeapNumber::cast(new_double);
}
Object* obj;
{ MaybeObject* maybe_obj =
SeededNumberDictionary::Allocate(GetHeap(), dict->NumberOfElements());
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
DisallowHeapAllocation no_alloc;
Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
Handle<SeededNumberDictionary> new_dict =
isolate->factory()->NewSeededNumberDictionary(dict->NumberOfElements());
uint32_t pos = 0;
uint32_t undefs = 0;
int capacity = dict->Capacity();
Handle<Smi> bailout(Smi::FromInt(-1), isolate);
// Entry to the new dictionary does not cause it to grow, as we have
// allocated one that is large enough for all entries.
DisallowHeapAllocation no_gc;
for (int i = 0; i < capacity; i++) {
Object* k = dict->KeyAt(i);
if (dict->IsKey(k)) {
ASSERT(k->IsNumber());
ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
Object* value = dict->ValueAt(i);
PropertyDetails details = dict->DetailsAt(i);
if (details.type() == CALLBACKS || details.IsReadOnly()) {
// Bail out and do the sorting of undefineds and array holes in JS.
// Also bail out if the element is not supposed to be moved.
return Smi::FromInt(-1);
}
uint32_t key = NumberToUint32(k);
// In the following we assert that adding the entry to the new dictionary
// does not cause GC. This is the case because we made sure to allocate
// the dictionary big enough above, so it need not grow.
if (key < limit) {
if (value->IsUndefined()) {
undefs++;
} else {
if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
// Adding an entry with the key beyond smi-range requires
// allocation. Bailout.
return Smi::FromInt(-1);
}
new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
pos++;
}
if (!dict->IsKey(k)) continue;
ASSERT(k->IsNumber());
ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
HandleScope scope(isolate);
Handle<Object> value(dict->ValueAt(i), isolate);
PropertyDetails details = dict->DetailsAt(i);
if (details.type() == CALLBACKS || details.IsReadOnly()) {
// Bail out and do the sorting of undefineds and array holes in JS.
// Also bail out if the element is not supposed to be moved.
return bailout;
}
uint32_t key = NumberToUint32(k);
if (key < limit) {
if (value->IsUndefined()) {
undefs++;
} else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
// Adding an entry with the key beyond smi-range requires
// allocation. Bailout.
return bailout;
} else {
if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
// Adding an entry with the key beyond smi-range requires
// allocation. Bailout.
return Smi::FromInt(-1);
}
new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
new_dict, pos, value, details);
ASSERT(result.is_identical_to(new_dict));
USE(result);
pos++;
}
} else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
// Adding an entry with the key beyond smi-range requires
// allocation. Bailout.
return bailout;
} else {
Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
new_dict, key, value, details);
ASSERT(result.is_identical_to(new_dict));
USE(result);
}
}
uint32_t result = pos;
PropertyDetails no_details = PropertyDetails(NONE, NORMAL, 0);
Heap* heap = GetHeap();
while (undefs > 0) {
if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
// Adding an entry with the key beyond smi-range requires
// allocation. Bailout.
return Smi::FromInt(-1);
return bailout;
}
new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
ToObjectUnchecked();
HandleScope scope(isolate);
Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
new_dict, pos, isolate->factory()->undefined_value(), no_details);
ASSERT(result.is_identical_to(new_dict));
USE(result);
pos++;
undefs--;
}
set_elements(new_dict);
object->set_elements(*new_dict);
if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
return Smi::FromInt(static_cast<int>(result));
}
ASSERT_NE(NULL, result_double);
result_double->set_value(static_cast<double>(result));
return result_double;
AllowHeapAllocation allocate_return_value;
return isolate->factory()->NewNumberFromUint(result);
}

View File

@ -2242,10 +2242,10 @@ class JSObject: public JSReceiver {
static Handle<Object> PrepareElementsForSort(Handle<JSObject> object,
uint32_t limit);
// As PrepareElementsForSort, but only on objects where elements is
// a dictionary, and it will stay a dictionary.
// a dictionary, and it will stay a dictionary. Collates undefined and
// unexisting elements below limit from position zero of the elements.
static Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object,
uint32_t limit);
MUST_USE_RESULT MaybeObject* PrepareSlowElementsForSort(uint32_t limit);
MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithCallback(
Handle<JSObject> object,
@ -10274,9 +10274,6 @@ class JSArray: public JSObject {
uint32_t index,
Handle<Object> value);
MUST_USE_RESULT MaybeObject* JSArrayUpdateLengthFromIndex(uint32_t index,
Object* value);
// Initialize the array with the given capacity. The function may
// fail due to out-of-memory situations, but only if the requested
// capacity is non-zero.