Commit 25d36eac authored by cbruni's avatar cbruni Committed by Commit bot

[runtime] split up loops with HandleScopes

HandleScopes in for-loops are rather expensive and pose a significant overhead
to some builtin/runtime-functions. The FOR_WITH_HANDLE_SCOPE macro is used to
only create a new HandleScope every 1024th iteration.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#34856}
parent d47a4063
......@@ -804,20 +804,20 @@ class ArrayConcatVisitor {
Handle<SeededNumberDictionary> slow_storage(
SeededNumberDictionary::New(isolate_, current_storage->length()));
uint32_t current_length = static_cast<uint32_t>(current_storage->length());
for (uint32_t i = 0; i < current_length; i++) {
HandleScope loop_scope(isolate_);
Handle<Object> element(current_storage->get(i), isolate_);
if (!element->IsTheHole()) {
// The object holding this backing store has just been allocated, so
// it cannot yet be used as a prototype.
Handle<SeededNumberDictionary> new_storage =
SeededNumberDictionary::AtNumberPut(slow_storage, i, element,
false);
if (!new_storage.is_identical_to(slow_storage)) {
slow_storage = loop_scope.CloseAndEscape(new_storage);
}
}
}
FOR_WITH_HANDLE_SCOPE(
isolate_, uint32_t, i = 0, i, i < current_length, i++, {
Handle<Object> element(current_storage->get(i), isolate_);
if (!element->IsTheHole()) {
// The object holding this backing store has just been allocated, so
// it cannot yet be used as a prototype.
Handle<SeededNumberDictionary> new_storage =
SeededNumberDictionary::AtNumberPut(slow_storage, i, element,
false);
if (!new_storage.is_identical_to(slow_storage)) {
slow_storage = loop_scope.CloseAndEscape(new_storage);
}
}
});
clear_storage();
set_storage(*slow_storage);
set_fast_elements(false);
......@@ -970,8 +970,7 @@ void CollectElementIndices(Handle<JSObject> object, uint32_t range,
Handle<SeededNumberDictionary> dict(
SeededNumberDictionary::cast(object->elements()));
uint32_t capacity = dict->Capacity();
for (uint32_t j = 0; j < capacity; j++) {
HandleScope loop_scope(isolate);
FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, j = 0, j, j < capacity, j++, {
Handle<Object> k(dict->KeyAt(j), isolate);
if (dict->IsKey(*k)) {
DCHECK(k->IsNumber());
......@@ -980,7 +979,7 @@ void CollectElementIndices(Handle<JSObject> object, uint32_t range,
indices->Add(index);
}
}
}
});
break;
}
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
......@@ -1048,8 +1047,7 @@ void CollectElementIndices(Handle<JSObject> object, uint32_t range,
bool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver,
uint32_t length, ArrayConcatVisitor* visitor) {
for (uint32_t i = 0; i < length; ++i) {
HandleScope loop_scope(isolate);
FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, i = 0, i, i < length, ++i, {
Maybe<bool> maybe = JSReceiver::HasElement(receiver, i);
if (!maybe.IsJust()) return false;
if (maybe.FromJust()) {
......@@ -1059,7 +1057,7 @@ bool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver,
false);
if (!visitor->visit(i, element_value)) return false;
}
}
});
visitor->increase_index_offset(length);
return true;
}
......@@ -1112,9 +1110,8 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
// to check the prototype for missing elements.
Handle<FixedArray> elements(FixedArray::cast(array->elements()));
int fast_length = static_cast<int>(length);
DCHECK_LE(fast_length, elements->length());
for (int j = 0; j < fast_length; j++) {
HandleScope loop_scope(isolate);
DCHECK(fast_length <= elements->length());
FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, {
Handle<Object> element_value(elements->get(j), isolate);
if (!element_value->IsTheHole()) {
if (!visitor->visit(j, element_value)) return false;
......@@ -1130,7 +1127,7 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
if (!visitor->visit(j, element_value)) return false;
}
}
}
});
break;
}
case FAST_HOLEY_DOUBLE_ELEMENTS:
......@@ -1147,8 +1144,7 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
FixedDoubleArray::cast(array->elements()));
int fast_length = static_cast<int>(length);
DCHECK(fast_length <= elements->length());
for (int j = 0; j < fast_length; j++) {
HandleScope loop_scope(isolate);
FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, {
if (!elements->is_the_hole(j)) {
double double_value = elements->get_scalar(j);
Handle<Object> element_value =
......@@ -1167,7 +1163,7 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
if (!visitor->visit(j, element_value)) return false;
}
}
}
});
break;
}
......@@ -1178,10 +1174,8 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
// than length. This might introduce duplicates in the indices list.
CollectElementIndices(array, length, &indices);
indices.Sort(&compareUInt32);
int j = 0;
int n = indices.length();
while (j < n) {
HandleScope loop_scope(isolate);
FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < n, (void)0, {
uint32_t index = indices[j];
Handle<Object> element;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
......@@ -1192,19 +1186,19 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
do {
j++;
} while (j < n && indices[j] == index);
}
});
break;
}
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
for (uint32_t index = 0; index < length; index++) {
HandleScope loop_scope(isolate);
Handle<Object> element;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, element, JSReceiver::GetElement(isolate, array, index),
false);
if (!visitor->visit(index, element)) return false;
}
FOR_WITH_HANDLE_SCOPE(
isolate, uint32_t, index = 0, index, index < length, index++, {
Handle<Object> element;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, element, JSReceiver::GetElement(isolate, array, index),
false);
if (!visitor->visit(index, element)) return false;
});
break;
}
case NO_ELEMENTS:
......@@ -1259,8 +1253,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
uint32_t estimate_result_length = 0;
uint32_t estimate_nof_elements = 0;
for (int i = 0; i < argument_count; i++) {
HandleScope loop_scope(isolate);
FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < argument_count, i++, {
Handle<Object> obj((*args)[i], isolate);
uint32_t length_estimate;
uint32_t element_estimate;
......@@ -1292,7 +1285,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
} else {
estimate_nof_elements += element_estimate;
}
}
});
// If estimated number of elements is more than half of length, a
// fixed array (fast case) is more time and space-efficient than a
......
......@@ -2783,8 +2783,8 @@ void Isolate::RunMicrotasksInternal() {
set_pending_microtask_count(0);
heap()->set_microtask_queue(heap()->empty_fixed_array());
for (int i = 0; i < num_tasks; i++) {
HandleScope scope(this);
Isolate* isolate = this;
FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < num_tasks, i++, {
Handle<Object> microtask(queue->get(i), this);
if (microtask->IsJSFunction()) {
Handle<JSFunction> microtask_function =
......@@ -2811,7 +2811,7 @@ void Isolate::RunMicrotasksInternal() {
void* data = v8::ToCData<void*>(callback_info->data());
callback(data);
}
}
});
}
}
......
......@@ -178,6 +178,20 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
C(ExternalCaughtException, external_caught_exception) \
C(JSEntrySP, js_entry_sp)
#define FOR_WITH_HANDLE_SCOPE(isolate, loop_var_type, init, loop_var, \
limit_check, increment, body) \
do { \
loop_var_type init; \
loop_var_type for_with_handle_limit = loop_var; \
Isolate* for_with_handle_isolate = isolate; \
while (limit_check) { \
for_with_handle_limit += 1024; \
HandleScope loop_scope(for_with_handle_isolate); \
for (; limit_check && loop_var < for_with_handle_limit; increment) { \
body \
} \
} \
} while (false)
// Platform-independent, reliable thread identifier.
class ThreadId {
......
......@@ -158,19 +158,20 @@ MaybeHandle<Object> Runtime::CreateArrayLiteralBoilerplate(
Handle<FixedArray> fixed_array_values_copy =
isolate->factory()->CopyFixedArray(fixed_array_values);
copied_elements_values = fixed_array_values_copy;
for (int i = 0; i < fixed_array_values->length(); i++) {
HandleScope scope(isolate);
if (fixed_array_values->get(i)->IsFixedArray()) {
// The value contains the constant_properties of a
// simple object or array literal.
Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, CreateLiteralBoilerplate(isolate, literals, fa),
Object);
fixed_array_values_copy->set(i, *result);
}
}
FOR_WITH_HANDLE_SCOPE(
isolate, int, i = 0, i, i < fixed_array_values->length(), i++, {
if (fixed_array_values->get(i)->IsFixedArray()) {
// The value contains the constant_properties of a
// simple object or array literal.
Handle<FixedArray> fa(
FixedArray::cast(fixed_array_values->get(i)));
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
CreateLiteralBoilerplate(isolate, literals, fa), Object);
fixed_array_values_copy->set(i, *result);
}
});
}
}
object->set_elements(*copied_elements_values);
......
......@@ -734,9 +734,9 @@ RUNTIME_FUNCTION(Runtime_StringSplit) {
// Create JSArray of substrings separated by separator.
int part_count = indices.length();
Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
JSObject::EnsureCanContainHeapObjectElements(result);
result->set_length(Smi::FromInt(part_count));
Handle<JSArray> result =
isolate->factory()->NewJSArray(FAST_ELEMENTS, part_count, part_count,
INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
DCHECK(result->HasFastObjectElements());
......@@ -746,14 +746,13 @@ RUNTIME_FUNCTION(Runtime_StringSplit) {
elements->set(0, *subject);
} else {
int part_start = 0;
for (int i = 0; i < part_count; i++) {
HandleScope local_loop_handle(isolate);
FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < part_count, i++, {
int part_end = indices.at(i);
Handle<String> substring =
isolate->factory()->NewProperSubString(subject, part_start, part_end);
elements->set(i, *substring);
part_start = part_end + pattern_length;
}
});
}
if (limit == 0xffffffffu) {
......
......@@ -103,8 +103,7 @@ RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
// Traverse the name/value pairs and set the properties.
int length = pairs->length();
for (int i = 0; i < length; i += 2) {
HandleScope scope(isolate);
FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i += 2, {
Handle<String> name(String::cast(pairs->get(i)));
Handle<Object> initial_value(pairs->get(i + 1), isolate);
......@@ -143,7 +142,7 @@ RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
static_cast<PropertyAttributes>(attr),
is_var, is_const, is_function);
if (isolate->has_pending_exception()) return result;
}
});
return isolate->heap()->undefined_value();
}
......
......@@ -371,14 +371,13 @@ RUNTIME_FUNCTION(Runtime_StringMatch) {
Handle<String> substring =
isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1));
elements->set(0, *substring);
for (int i = 1; i < matches; i++) {
HandleScope temp_scope(isolate);
FOR_WITH_HANDLE_SCOPE(isolate, int, i = 1, i, i < matches, i++, {
int from = offsets.at(i * 2);
int to = offsets.at(i * 2 + 1);
Handle<String> substring =
isolate->factory()->NewProperSubString(subject, from, to);
elements->set(i, *substring);
}
});
Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
result->set_length(Smi::FromInt(matches));
return *result;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment