[runtime] Immediately set the array-index hash in Uint32ToString and convert to string in ForInPrepare

This speeds up for/in over arrays. E.g.,:

function f(a) {
  for (let i in a) {
    if (a[i] != a[i]) print(false);
  }
}
var a = new Array(10000000);
a.fill(1);
f(a);

runs 3x faster after the change.

BUG=chromium:703226

Change-Id: Iabc5e931d985a03f89440cd702b2feb3eb9f5c18
Reviewed-on: https://chromium-review.googlesource.com/459538
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44108}
This commit is contained in:
Toon Verwaest 2017-03-24 13:37:51 +01:00 committed by Commit Bot
parent 9a3b029b6c
commit 97300c5c38
4 changed files with 22 additions and 20 deletions

View File

@ -21,28 +21,18 @@ typedef compiler::Node Node;
Node* ForInBuiltinsAssembler::ForInFilter(Node* key, Node* object,
Node* context) {
Label return_undefined(this, Label::kDeferred), return_to_name(this),
end(this);
CSA_ASSERT(this, IsName(key));
Variable var_result(this, MachineRepresentation::kTagged);
Variable var_result(this, MachineRepresentation::kTagged, key);
Node* has_property =
HasProperty(object, key, context, Runtime::kForInHasProperty);
Branch(WordEqual(has_property, BooleanConstant(true)), &return_to_name,
&return_undefined);
Label end(this);
GotoIf(WordEqual(has_property, BooleanConstant(true)), &end);
Bind(&return_to_name);
{
var_result.Bind(ToName(context, key));
Goto(&end);
}
Bind(&return_undefined);
{
var_result.Bind(UndefinedConstant());
Goto(&end);
}
var_result.Bind(UndefinedConstant());
Goto(&end);
Bind(&end);
return var_result.value();

View File

@ -671,7 +671,14 @@ class V8_EXPORT_PRIVATE Factory final {
bool check_number_string_cache = true);
Handle<String> Uint32ToString(uint32_t value) {
return NumberToString(NewNumberFromUint(value));
Handle<String> result = NumberToString(NewNumberFromUint(value));
if (result->length() <= String::kMaxArrayIndexSize) {
uint32_t field =
StringHasher::MakeArrayIndexHash(value, result->length());
result->set_hash_field(field);
}
return result;
}
Handle<JSFunction> InstallMembers(Handle<JSFunction> function);

View File

@ -18549,8 +18549,13 @@ Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
for (int i = 0; i < length; i++) {
int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize);
Object* key = table->get(index);
if (convert == GetKeysConversion::kConvertToString && key->IsNumber()) {
key = *isolate->factory()->NumberToString(handle(key, isolate));
if (convert == GetKeysConversion::kConvertToString) {
uint32_t index_value;
if (key->ToArrayIndex(&index_value)) {
key = *isolate->factory()->Uint32ToString(index_value);
} else {
CHECK(key->IsName());
}
}
result->set(i, key);
}

View File

@ -31,7 +31,7 @@ MaybeHandle<HeapObject> Enumerate(Handle<JSReceiver> receiver) {
if (!accumulator.is_receiver_simple_enum()) {
Handle<FixedArray> keys;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, keys, accumulator.GetKeys(GetKeysConversion::kKeepNumbers),
isolate, keys, accumulator.GetKeys(GetKeysConversion::kConvertToString),
HeapObject);
// Test again, since cache may have been built by GetKeys() calls above.
if (!accumulator.is_receiver_simple_enum()) return keys;