Skip to content

Commit

Permalink
[MERGE #1449 @dilijev] Fastpath for hasOwnProperty == true.
Browse files Browse the repository at this point in the history
Merge pull request #1449 from dilijev:hasown

Adds a fastpath for the case when `Object.hasOwnProperty` returns `true` (meaning the property was found on the current object).

This optimization was inspired by the observation that a very common pattern to use `Object.hasOwnProperty` in the following manner:

```
for (var x in obj) {
    if (obj.hasOwnProperty(x)) {
        // do something
    }
}
```

From our observations, most instances of these patterns are used with shallow objects (objects with most of their enumerable properties on the object itself, rather than in the prototype chain), so most of the time, `Object.hasOwnProperty` would return true when invoked via the above pattern. Additionally, we have already created a property cache containing the type that a property was enumerated from, so we can use that information to trivially know whether the `this` parameter of `hasOwnProperty` was the same object on which we looked up that property, and if so, we know the answer is `true`.
  • Loading branch information
dilijev committed Aug 17, 2016
2 parents ade59a0 + c1e972d commit 6959e13
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 7 deletions.
19 changes: 15 additions & 4 deletions lib/Runtime/Base/ScriptContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1454,22 +1454,33 @@ if (!sourceList)
return NULL;
}


PropertyString* ScriptContext::GetPropertyString(PropertyId propertyId)
PropertyString* ScriptContext::TryGetPropertyString(PropertyId propertyId)
{
PropertyStringCacheMap* propertyStringMap = this->GetLibrary()->EnsurePropertyStringMap();

PropertyString *string;
RecyclerWeakReference<PropertyString>* stringReference;
if (propertyStringMap->TryGetValue(propertyId, &stringReference))
{
string = stringReference->Get();
PropertyString *string = stringReference->Get();
if (string != nullptr)
{
return string;
}
}

return nullptr;
}

PropertyString* ScriptContext::GetPropertyString(PropertyId propertyId)
{
PropertyString *string = TryGetPropertyString(propertyId);
if (string != nullptr)
{
return string;
}

PropertyStringCacheMap* propertyStringMap = this->GetLibrary()->EnsurePropertyStringMap();

const Js::PropertyRecord* propertyName = this->GetPropertyName(propertyId);
string = this->GetLibrary()->CreatePropertyString(propertyName);
propertyStringMap->Item(propertyId, recycler->CreateWeakReferenceHandle(string));
Expand Down
1 change: 1 addition & 0 deletions lib/Runtime/Base/ScriptContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,7 @@ namespace Js
void SetDisposeDisposeByFaultInjectionEventHandler(EventHandler eventHandler);
#endif
EnumeratedObjectCache* GetEnumeratedObjectCache() { return &(cache->enumObjCache); }
PropertyString* TryGetPropertyString(PropertyId propertyId);
PropertyString* GetPropertyString(PropertyId propertyId);
void InvalidatePropertyStringCache(PropertyId propertyId, Type* type);
JavascriptString* GetIntegerString(Var aValue);
Expand Down
17 changes: 14 additions & 3 deletions lib/Runtime/Language/JavascriptOperators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1075,10 +1075,9 @@ namespace Js

BOOL JavascriptOperators::HasOwnProperty(Var instance, PropertyId propertyId, ScriptContext *requestContext)
{
BOOL result;
if (TaggedNumber::Is(instance))
{
result = false;
return FALSE;
}
else
{
Expand All @@ -1091,10 +1090,22 @@ namespace Js
}
else
{
PropertyString *propString = requestContext->TryGetPropertyString(propertyId);
if (propString != nullptr)
{
const PropertyCache *propCache = propString->GetPropertyCache();
if (object->GetType() == propCache->type)
{
// The type cached for the property was the same as the type of this object
// (i.e. obj in obj.hasOwnProperty), so we know the answer is "true".
Assert(TRUE == (object && object->HasOwnProperty(propertyId))); // sanity check on the fastpath result
return TRUE;
}
}

return object && object->HasOwnProperty(propertyId);
}
}
return result;
}

BOOL JavascriptOperators::GetOwnAccessors(Var instance, PropertyId propertyId, Var* getter, Var* setter, ScriptContext * requestContext)
Expand Down

0 comments on commit 6959e13

Please sign in to comment.