Commit 048dbc64 authored by Jaroslav Sevcik's avatar Jaroslav Sevcik Committed by Commit Bot

Port WeakMap.prototype.(has|get) to CSA.

In many cases, this is performance neutral because we can fall off 
the JavaScript monomorphic fast path for the hash lookup.
Once we store the hash code in known fixed position, this should
get much faster.

Change-Id: I3bb52ee6482fe2c35b7abe70c1d0c21935c6cc1d
Reviewed-on: https://chromium-review.googlesource.com/566679
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46692}
parent 26e835b1
......@@ -3132,6 +3132,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
// Setup %WeakMapPrototype%.
Handle<JSObject> prototype(JSObject::cast(cons->instance_prototype()));
SimpleInstallFunction(prototype, "get", Builtins::kWeakMapGet, 1, true);
SimpleInstallFunction(prototype, "has", Builtins::kWeakMapHas, 1, true);
JSObject::AddProperty(
prototype, factory->to_string_tag_symbol(),
factory->NewStringFromAsciiChecked("WeakMap"),
......
......@@ -1225,5 +1225,107 @@ TF_BUILTIN(MapLookupHashIndex, CollectionsBuiltinsAssembler) {
Return(result.value());
}
TF_BUILTIN(WeakMapLookupHashIndex, CollectionsBuiltinsAssembler) {
Node* const table = Parameter(Descriptor::kTable);
Node* const key = Parameter(Descriptor::kKey);
Label if_found(this), if_not_found(this);
Node* const capacity =
SmiUntag(LoadFixedArrayElement(table, WeakHashTable::kCapacityIndex));
Node* const mask = IntPtrSub(capacity, IntPtrConstant(1));
Node* const hash = SmiUntag(CallGetHashRaw(key));
GotoIf(IntPtrLessThan(hash, IntPtrConstant(0)), &if_not_found);
// See HashTable::FirstProbe().
Node* entry = WordAnd(hash, mask);
VARIABLE(var_count, MachineType::PointerRepresentation(), IntPtrConstant(0));
VARIABLE(var_entry, MachineType::PointerRepresentation(), entry);
Variable* loop_vars[] = {&var_count, &var_entry};
Label loop(this, arraysize(loop_vars), loop_vars);
Goto(&loop);
BIND(&loop);
Node* index;
{
Node* entry = var_entry.value();
index = IntPtrMul(entry, IntPtrConstant(WeakHashTable::kEntrySize));
index =
IntPtrAdd(index, IntPtrConstant(WeakHashTable::kElementsStartIndex));
Node* current = LoadFixedArrayElement(table, index);
GotoIf(WordEqual(current, UndefinedConstant()), &if_not_found);
GotoIf(WordEqual(current, key), &if_found);
// See HashTable::NextProbe().
Increment(var_count);
entry = WordAnd(IntPtrAdd(entry, var_count.value()), mask);
var_entry.Bind(entry);
Goto(&loop);
}
BIND(&if_not_found);
Return(SmiConstant(-1));
BIND(&if_found);
Return(SmiTag(IntPtrAdd(index, IntPtrConstant(1))));
}
TF_BUILTIN(WeakMapGet, CollectionsBuiltinsAssembler) {
Node* const receiver = Parameter(Descriptor::kReceiver);
Node* const key = Parameter(Descriptor::kKey);
Node* const context = Parameter(Descriptor::kContext);
Label return_undefined(this);
ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
"WeakMap.prototype.get");
GotoIf(TaggedIsSmi(key), &return_undefined);
GotoIfNot(IsJSReceiver(key), &return_undefined);
Node* const table = LoadObjectField(receiver, JSWeakCollection::kTableOffset);
Node* const index =
CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key);
GotoIf(WordEqual(index, SmiConstant(-1)), &return_undefined);
Return(LoadFixedArrayElement(table, SmiUntag(index)));
BIND(&return_undefined);
Return(UndefinedConstant());
}
TF_BUILTIN(WeakMapHas, CollectionsBuiltinsAssembler) {
Node* const receiver = Parameter(Descriptor::kReceiver);
Node* const key = Parameter(Descriptor::kKey);
Node* const context = Parameter(Descriptor::kContext);
Label return_false(this);
ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
"WeakMap.prototype.get");
GotoIf(TaggedIsSmi(key), &return_false);
GotoIfNot(IsJSReceiver(key), &return_false);
Node* const table = LoadObjectField(receiver, JSWeakCollection::kTableOffset);
Node* const index =
CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key);
GotoIf(WordEqual(index, SmiConstant(-1)), &return_false);
Return(TrueConstant());
BIND(&return_false);
Return(FalseConstant());
}
} // namespace internal
} // namespace v8
......@@ -1033,6 +1033,11 @@ namespace internal {
TFC(ThrowWasmTrapFuncInvalid, WasmRuntimeCall, 1) \
TFC(ThrowWasmTrapFuncSigMismatch, WasmRuntimeCall, 1) \
\
/* WeakMap */ \
TFS(WeakMapLookupHashIndex, kTable, kKey) \
TFJ(WeakMapGet, 1, kKey) \
TFJ(WeakMapHas, 1, kKey) \
\
/* AsyncGenerator */ \
\
TFS(AsyncGeneratorResolve, kGenerator, kValue, kDone) \
......
......@@ -50,17 +50,6 @@ function WeakMapConstructor(iterable) {
DEFINE_METHODS(
GlobalWeakMap.prototype,
{
get(key) {
if (!IS_WEAKMAP(this)) {
throw %make_type_error(kIncompatibleMethodReceiver,
'WeakMap.prototype.get', this);
}
if (!IS_RECEIVER(key)) return UNDEFINED;
var hash = GetExistingHash(key);
if (IS_UNDEFINED(hash)) return UNDEFINED;
return %WeakCollectionGet(this, key, hash);
}
set(key, value) {
if (!IS_WEAKMAP(this)) {
throw %make_type_error(kIncompatibleMethodReceiver,
......@@ -70,17 +59,6 @@ DEFINE_METHODS(
return %WeakCollectionSet(this, key, value, GetHash(key));
}
has(key) {
if (!IS_WEAKMAP(this)) {
throw %make_type_error(kIncompatibleMethodReceiver,
'WeakMap.prototype.has', this);
}
if (!IS_RECEIVER(key)) return false;
var hash = GetExistingHash(key);
if (IS_UNDEFINED(hash)) return false;
return %WeakCollectionHas(this, key, hash);
}
delete(key) {
if (!IS_WEAKMAP(this)) {
throw %make_type_error(kIncompatibleMethodReceiver,
......
......@@ -143,22 +143,6 @@ RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) {
}
RUNTIME_FUNCTION(Runtime_WeakCollectionGet) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
CONVERT_SMI_ARG_CHECKED(hash, 2)
CHECK(key->IsJSReceiver() || key->IsSymbol());
Handle<ObjectHashTable> table(
ObjectHashTable::cast(weak_collection->table()));
CHECK(table->IsKey(isolate, *key));
Handle<Object> lookup(table->Lookup(key, hash), isolate);
return lookup->IsTheHole(isolate) ? isolate->heap()->undefined_value()
: *lookup;
}
RUNTIME_FUNCTION(Runtime_WeakCollectionHas) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
......
......@@ -104,7 +104,6 @@ namespace internal {
F(MapIteratorClone, 1, 1) \
F(GetWeakMapEntries, 2, 1) \
F(WeakCollectionInitialize, 1, 1) \
F(WeakCollectionGet, 3, 1) \
F(WeakCollectionHas, 3, 1) \
F(WeakCollectionDelete, 3, 1) \
F(WeakCollectionSet, 4, 1) \
......
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