Commit ddc75cc1 authored by mlippautz's avatar mlippautz Committed by Commit bot

[heap] Track length for array buffers to avoid free-ing dependency

The dependency would only happen if we have a smi overflow for the length and
have create a heap number. In this case the heap number would've to survive
until the array buffer is collected.

To avoid this dependency we track the length (as we previously used to).

BUG=chromium:625748,chromium:625752
LOG=N
TEST=test/mjsunit/regress/regress-625752.js
R=hpayer@chromium.org

Review-Url: https://codereview.chromium.org/2122603004
Cr-Commit-Position: refs/heads/master@{#37530}
parent e0dd3119
...@@ -24,7 +24,7 @@ void ArrayBufferTracker::RegisterNew(Heap* heap, JSArrayBuffer* buffer) { ...@@ -24,7 +24,7 @@ void ArrayBufferTracker::RegisterNew(Heap* heap, JSArrayBuffer* buffer) {
tracker = page->local_tracker(); tracker = page->local_tracker();
} }
DCHECK_NOT_NULL(tracker); DCHECK_NOT_NULL(tracker);
tracker->Add(buffer); tracker->Add(buffer, length);
} }
// We may go over the limit of externally allocated memory here. We call the // We may go over the limit of externally allocated memory here. We call the
// api function to trigger a GC in this case. // api function to trigger a GC in this case.
...@@ -37,29 +37,31 @@ void ArrayBufferTracker::Unregister(Heap* heap, JSArrayBuffer* buffer) { ...@@ -37,29 +37,31 @@ void ArrayBufferTracker::Unregister(Heap* heap, JSArrayBuffer* buffer) {
if (!data) return; if (!data) return;
Page* page = Page::FromAddress(buffer->address()); Page* page = Page::FromAddress(buffer->address());
size_t length = NumberToSize(heap->isolate(), buffer->byte_length()); size_t length = 0;
{ {
base::LockGuard<base::Mutex> guard(page->mutex()); base::LockGuard<base::Mutex> guard(page->mutex());
LocalArrayBufferTracker* tracker = page->local_tracker(); LocalArrayBufferTracker* tracker = page->local_tracker();
DCHECK_NOT_NULL(tracker); DCHECK_NOT_NULL(tracker);
tracker->Remove(buffer); length = tracker->Remove(buffer);
} }
heap->update_external_memory(-static_cast<intptr_t>(length)); heap->update_external_memory(-static_cast<intptr_t>(length));
} }
void LocalArrayBufferTracker::Add(Key key) { void LocalArrayBufferTracker::Add(Key key, const Value& value) {
auto ret = array_buffers_.insert(key); auto ret = array_buffers_.insert(std::make_pair(key, value));
USE(ret); USE(ret);
// Check that we indeed inserted a new value and did not overwrite an existing // Check that we indeed inserted a new value and did not overwrite an existing
// one (which would be a bug). // one (which would be a bug).
DCHECK(ret.second); DCHECK(ret.second);
} }
void LocalArrayBufferTracker::Remove(Key key) { LocalArrayBufferTracker::Value LocalArrayBufferTracker::Remove(Key key) {
TrackingData::iterator it = array_buffers_.find(key); TrackingData::iterator it = array_buffers_.find(key);
// Check that we indeed find a key to remove. // Check that we indeed find a key to remove.
DCHECK(it != array_buffers_.end()); DCHECK(it != array_buffers_.end());
Value value = it->second;
array_buffers_.erase(it); array_buffers_.erase(it);
return value;
} }
} // namespace internal } // namespace internal
......
...@@ -18,10 +18,10 @@ void LocalArrayBufferTracker::Free() { ...@@ -18,10 +18,10 @@ void LocalArrayBufferTracker::Free() {
size_t freed_memory = 0; size_t freed_memory = 0;
for (TrackingData::iterator it = array_buffers_.begin(); for (TrackingData::iterator it = array_buffers_.begin();
it != array_buffers_.end();) { it != array_buffers_.end();) {
JSArrayBuffer* buffer = reinterpret_cast<JSArrayBuffer*>(*it); JSArrayBuffer* buffer = reinterpret_cast<JSArrayBuffer*>(it->first);
if ((free_mode == kFreeAll) || if ((free_mode == kFreeAll) ||
Marking::IsWhite(Marking::MarkBitFrom(buffer))) { Marking::IsWhite(Marking::MarkBitFrom(buffer))) {
const size_t len = NumberToSize(heap_->isolate(), buffer->byte_length()); const size_t len = it->second;
heap_->isolate()->array_buffer_allocator()->Free(buffer->backing_store(), heap_->isolate()->array_buffer_allocator()->Free(buffer->backing_store(),
len); len);
freed_memory += len; freed_memory += len;
...@@ -42,7 +42,7 @@ void LocalArrayBufferTracker::Process(Callback callback) { ...@@ -42,7 +42,7 @@ void LocalArrayBufferTracker::Process(Callback callback) {
size_t freed_memory = 0; size_t freed_memory = 0;
for (TrackingData::iterator it = array_buffers_.begin(); for (TrackingData::iterator it = array_buffers_.begin();
it != array_buffers_.end();) { it != array_buffers_.end();) {
const CallbackResult result = callback(*it, &new_buffer); const CallbackResult result = callback(it->first, &new_buffer);
if (result == kKeepEntry) { if (result == kKeepEntry) {
++it; ++it;
} else if (result == kUpdateEntry) { } else if (result == kUpdateEntry) {
...@@ -57,13 +57,13 @@ void LocalArrayBufferTracker::Process(Callback callback) { ...@@ -57,13 +57,13 @@ void LocalArrayBufferTracker::Process(Callback callback) {
tracker = target_page->local_tracker(); tracker = target_page->local_tracker();
} }
DCHECK_NOT_NULL(tracker); DCHECK_NOT_NULL(tracker);
tracker->Add(new_buffer); tracker->Add(new_buffer, it->second);
if (target_page->InNewSpace()) target_page->mutex()->Unlock(); if (target_page->InNewSpace()) target_page->mutex()->Unlock();
it = array_buffers_.erase(it); it = array_buffers_.erase(it);
} else if (result == kRemoveEntry) { } else if (result == kRemoveEntry) {
const size_t len = NumberToSize(heap_->isolate(), (*it)->byte_length()); const size_t len = it->second;
heap_->isolate()->array_buffer_allocator()->Free((*it)->backing_store(), heap_->isolate()->array_buffer_allocator()->Free(
len); it->first->backing_store(), len);
freed_memory += len; freed_memory += len;
it = array_buffers_.erase(it); it = array_buffers_.erase(it);
} else { } else {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#ifndef V8_HEAP_ARRAY_BUFFER_TRACKER_H_ #ifndef V8_HEAP_ARRAY_BUFFER_TRACKER_H_
#define V8_HEAP_ARRAY_BUFFER_TRACKER_H_ #define V8_HEAP_ARRAY_BUFFER_TRACKER_H_
#include <unordered_set> #include <unordered_map>
#include "src/allocation.h" #include "src/allocation.h"
#include "src/base/platform/mutex.h" #include "src/base/platform/mutex.h"
...@@ -60,6 +60,7 @@ class ArrayBufferTracker : public AllStatic { ...@@ -60,6 +60,7 @@ class ArrayBufferTracker : public AllStatic {
class LocalArrayBufferTracker { class LocalArrayBufferTracker {
public: public:
typedef JSArrayBuffer* Key; typedef JSArrayBuffer* Key;
typedef size_t Value;
enum CallbackResult { kKeepEntry, kUpdateEntry, kRemoveEntry }; enum CallbackResult { kKeepEntry, kUpdateEntry, kRemoveEntry };
enum FreeMode { kFreeDead, kFreeAll }; enum FreeMode { kFreeDead, kFreeAll };
...@@ -67,8 +68,8 @@ class LocalArrayBufferTracker { ...@@ -67,8 +68,8 @@ class LocalArrayBufferTracker {
explicit LocalArrayBufferTracker(Heap* heap) : heap_(heap) {} explicit LocalArrayBufferTracker(Heap* heap) : heap_(heap) {}
~LocalArrayBufferTracker(); ~LocalArrayBufferTracker();
inline void Add(Key key); inline void Add(Key key, const Value& value);
inline void Remove(Key key); inline Value Remove(Key key);
// Frees up array buffers determined by |free_mode|. // Frees up array buffers determined by |free_mode|.
template <FreeMode free_mode> template <FreeMode free_mode>
...@@ -89,7 +90,7 @@ class LocalArrayBufferTracker { ...@@ -89,7 +90,7 @@ class LocalArrayBufferTracker {
} }
private: private:
typedef std::unordered_set<Key> TrackingData; typedef std::unordered_map<Key, Value> TrackingData;
Heap* heap_; Heap* heap_;
TrackingData array_buffers_; TrackingData array_buffers_;
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
v3 = Math.floor(0xFFFFFFFF / 4) + 1;
Object.prototype.__defineGetter__(1, function() {
this[1] = Array(0x8000).join();
})
try { v38 = new ArrayBuffer(v3); } catch (e) {}
try { v41 = new Intl.DateTimeFormat(); } catch (e) {}
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