Commit a9fd19f4 authored by jkummerow's avatar jkummerow Committed by Commit bot

[elements, turbofan] Implement simple GrowElements

Unlike Crankshaft, Turbofan does not provide a context when trying to grow
elements. Depending on the code path we might end up updating transitioning
elements kinds in allocation sites for which we need access to the current
context. Unlike GrowCapacityAndConvert, the newly introduced GrowCapacity simply
returns false in cases where map transitions are involved.

BUG=chromium:637279

Patch by Camillo Bruni <cbruni@chromium.org>,
originally reviewed at https://codereview.chromium.org/2244983004/

Review-Url: https://codereview.chromium.org/2252393002
Cr-Commit-Position: refs/heads/master@{#38901}
parent b2734f6a
......@@ -911,6 +911,30 @@ class ElementsAccessorBase : public ElementsAccessor {
Subclass::GrowCapacityAndConvertImpl(object, capacity);
}
bool GrowCapacity(Handle<JSObject> object, uint32_t index) final {
// This function is intended to be called from optimized code. We don't
// want to trigger lazy deopts there, so refuse to handle cases that would.
if (object->map()->is_prototype_map() ||
object->WouldConvertToSlowElements(index)) {
return false;
}
Handle<FixedArrayBase> old_elements(object->elements());
uint32_t new_capacity = JSObject::NewElementsCapacity(index + 1);
DCHECK(static_cast<uint32_t>(old_elements->length()) < new_capacity);
Handle<FixedArrayBase> elements =
ConvertElementsWithCapacity(object, old_elements, kind(), new_capacity);
DCHECK_EQ(object->GetElementsKind(), kind());
// Transition through the allocation site as well if present.
if (JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
object, kind())) {
return false;
}
object->set_elements(*elements);
return true;
}
void Delete(Handle<JSObject> obj, uint32_t entry) final {
Subclass::DeleteImpl(obj, entry);
}
......
......@@ -114,6 +114,9 @@ class ElementsAccessor {
Handle<Map> map) = 0;
virtual void GrowCapacityAndConvert(Handle<JSObject> object,
uint32_t capacity) = 0;
// Unlike GrowCapacityAndConvert do not attempt to convert the backing store
// and simply return false in this case.
virtual bool GrowCapacity(Handle<JSObject> object, uint32_t index) = 0;
static void InitializeOncePerProcess();
static void TearDown();
......
......@@ -15487,10 +15487,11 @@ bool AllocationSite::IsNestedSite() {
return false;
}
void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
template <AllocationSiteUpdateMode update_or_check>
bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
ElementsKind to_kind) {
Isolate* isolate = site->GetIsolate();
bool result = false;
if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
Handle<JSArray> transition_info =
......@@ -15506,6 +15507,9 @@ void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
uint32_t length = 0;
CHECK(transition_info->length()->ToArrayLength(&length));
if (length <= kMaximumArrayBytesToPretransition) {
if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
return true;
}
if (FLAG_trace_track_allocation_sites) {
bool is_nested = site->IsNestedSite();
PrintF(
......@@ -15518,6 +15522,7 @@ void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
JSObject::TransitionElementsKind(transition_info, to_kind);
site->dependent_code()->DeoptimizeDependentCodeGroup(
isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
result = true;
}
}
} else {
......@@ -15527,6 +15532,7 @@ void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
to_kind = GetHoleyElementsKind(to_kind);
}
if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
if (FLAG_trace_track_allocation_sites) {
PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
reinterpret_cast<void*>(*site),
......@@ -15536,8 +15542,10 @@ void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
site->SetElementsKind(to_kind);
site->dependent_code()->DeoptimizeDependentCodeGroup(
isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
result = true;
}
}
return result;
}
......@@ -15553,13 +15561,13 @@ const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
return NULL;
}
void JSObject::UpdateAllocationSite(Handle<JSObject> object,
template <AllocationSiteUpdateMode update_or_check>
bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
ElementsKind to_kind) {
if (!object->IsJSArray()) return;
if (!object->IsJSArray()) return false;
Heap* heap = object->GetHeap();
if (!heap->InNewSpace(*object)) return;
if (!heap->InNewSpace(*object)) return false;
Handle<AllocationSite> site;
{
......@@ -15567,14 +15575,21 @@ void JSObject::UpdateAllocationSite(Handle<JSObject> object,
AllocationMemento* memento =
heap->FindAllocationMemento<Heap::kForRuntime>(*object);
if (memento == NULL) return;
if (memento == NULL) return false;
// Walk through to the Allocation Site
site = handle(memento->GetAllocationSite());
}
AllocationSite::DigestTransitionFeedback(site, to_kind);
return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
to_kind);
}
template bool
JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
Handle<JSObject> object, ElementsKind to_kind);
template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
Handle<JSObject> object, ElementsKind to_kind);
void JSObject::TransitionElementsKind(Handle<JSObject> object,
ElementsKind to_kind) {
......
......@@ -1850,6 +1850,8 @@ enum class KeyCollectionMode {
static_cast<int>(v8::KeyCollectionMode::kIncludePrototypes)
};
enum class AllocationSiteUpdateMode { kUpdate, kCheckOnly };
// JSReceiver includes types on which properties can be defined, i.e.,
// JSObject and JSProxy.
class JSReceiver: public HeapObject {
......@@ -2300,7 +2302,9 @@ class JSObject: public JSReceiver {
}
// These methods do not perform access checks!
static void UpdateAllocationSite(Handle<JSObject> object,
template <AllocationSiteUpdateMode update_or_check =
AllocationSiteUpdateMode::kUpdate>
static bool UpdateAllocationSite(Handle<JSObject> object,
ElementsKind to_kind);
// Lookup interceptors are used for handling properties controlled by host
......@@ -8662,7 +8666,9 @@ class AllocationSite: public Struct {
inline bool SitePointsToLiteral();
static void DigestTransitionFeedback(Handle<AllocationSite> site,
template <AllocationSiteUpdateMode update_or_check =
AllocationSiteUpdateMode::kUpdate>
static bool DigestTransitionFeedback(Handle<AllocationSite> site,
ElementsKind to_kind);
DECLARE_PRINTER(AllocationSite)
......
......@@ -375,15 +375,9 @@ RUNTIME_FUNCTION(Runtime_GrowArrayElements) {
uint32_t index = static_cast<uint32_t>(key);
if (index >= capacity) {
if (object->map()->is_prototype_map() ||
object->WouldConvertToSlowElements(index)) {
// We don't want to allow operations that cause lazy deopt. Return a Smi
// as a signal that optimized code should eagerly deoptimize.
if (!object->GetElementsAccessor()->GrowCapacity(object, index)) {
return Smi::FromInt(0);
}
uint32_t new_capacity = JSObject::NewElementsCapacity(index + 1);
object->GetElementsAccessor()->GrowCapacityAndConvert(object, new_capacity);
}
// On success, return the fixed array elements.
......
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