Recording array buffer views.
R=hpayer@chromium.org BUG= Review URL: https://codereview.chromium.org/15562008 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15000 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a0f786f022
commit
b3282c290e
@ -6173,6 +6173,14 @@ Float64Array* Float64Array::Cast(v8::Value* value) {
|
||||
}
|
||||
|
||||
|
||||
Uint8ClampedArray* Uint8ClampedArray::Cast(v8::Value* value) {
|
||||
#ifdef V8_ENABLE_CHECKS
|
||||
CheckCast(value);
|
||||
#endif
|
||||
return static_cast<Uint8ClampedArray*>(value);
|
||||
}
|
||||
|
||||
|
||||
Function* Function::Cast(v8::Value* value) {
|
||||
#ifdef V8_ENABLE_CHECKS
|
||||
CheckCast(value);
|
||||
|
@ -6206,6 +6206,9 @@ i::Handle<i::JSTypedArray> NewTypedArray(
|
||||
|
||||
obj->set_buffer(*buffer);
|
||||
|
||||
obj->set_weak_next(buffer->weak_first_array());
|
||||
buffer->set_weak_first_array(*obj);
|
||||
|
||||
i::Handle<i::Object> byte_offset_object = isolate->factory()->NewNumber(
|
||||
static_cast<double>(byte_offset));
|
||||
obj->set_byte_offset(*byte_offset_object);
|
||||
|
@ -1324,8 +1324,7 @@ void Genesis::InitializeExperimentalGlobal() {
|
||||
Handle<JSFunction> array_buffer_fun =
|
||||
InstallFunction(
|
||||
global, "ArrayBuffer", JS_ARRAY_BUFFER_TYPE,
|
||||
JSArrayBuffer::kSize +
|
||||
v8::ArrayBuffer::kInternalFieldCount * kPointerSize,
|
||||
JSArrayBuffer::kSizeWithInternalFields,
|
||||
isolate()->initial_object_prototype(),
|
||||
Builtins::kIllegal, true, true);
|
||||
native_context()->set_array_buffer_fun(*array_buffer_fun);
|
||||
|
119
src/heap.cc
119
src/heap.cc
@ -180,6 +180,7 @@ Heap::Heap()
|
||||
|
||||
memset(roots_, 0, sizeof(roots_[0]) * kRootListLength);
|
||||
native_contexts_list_ = NULL;
|
||||
array_buffers_list_ = Smi::FromInt(0);
|
||||
mark_compact_collector_.heap_ = this;
|
||||
external_string_table_.heap_ = this;
|
||||
// Put a dummy entry in the remembered pages so we can find the list the
|
||||
@ -1539,11 +1540,6 @@ static Object* ProcessFunctionWeakReferences(Heap* heap,
|
||||
|
||||
|
||||
void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
|
||||
Object* undefined = undefined_value();
|
||||
Object* head = undefined;
|
||||
Context* tail = NULL;
|
||||
Object* candidate = native_contexts_list_;
|
||||
|
||||
// We don't record weak slots during marking or scavenges.
|
||||
// Instead we do it once when we complete mark-compact cycle.
|
||||
// Note that write barrier has no effect if we are already in the middle of
|
||||
@ -1551,6 +1547,16 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
|
||||
bool record_slots =
|
||||
gc_state() == MARK_COMPACT &&
|
||||
mark_compact_collector()->is_compacting();
|
||||
ProcessArrayBuffers(retainer, record_slots);
|
||||
ProcessNativeContexts(retainer, record_slots);
|
||||
}
|
||||
|
||||
void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer,
|
||||
bool record_slots) {
|
||||
Object* undefined = undefined_value();
|
||||
Object* head = undefined;
|
||||
Context* tail = NULL;
|
||||
Object* candidate = native_contexts_list_;
|
||||
|
||||
while (candidate != undefined) {
|
||||
// Check whether to keep the candidate in the list.
|
||||
@ -1619,6 +1625,101 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
struct WeakListVisitor;
|
||||
|
||||
|
||||
template <class T>
|
||||
static Object* VisitWeakList(Object* list,
|
||||
MarkCompactCollector* collector,
|
||||
WeakObjectRetainer* retainer, bool record_slots) {
|
||||
Object* head = Smi::FromInt(0);
|
||||
T* tail = NULL;
|
||||
while (list != Smi::FromInt(0)) {
|
||||
Object* retained = retainer->RetainAs(list);
|
||||
if (retained != NULL) {
|
||||
if (head == Smi::FromInt(0)) {
|
||||
head = retained;
|
||||
} else {
|
||||
ASSERT(tail != NULL);
|
||||
WeakListVisitor<T>::set_weak_next(tail, retained);
|
||||
if (record_slots) {
|
||||
Object** next_slot =
|
||||
HeapObject::RawField(tail, WeakListVisitor<T>::kWeakNextOffset);
|
||||
collector->RecordSlot(next_slot, next_slot, retained);
|
||||
}
|
||||
}
|
||||
tail = reinterpret_cast<T*>(retained);
|
||||
WeakListVisitor<T>::VisitLiveObject(
|
||||
tail, collector, retainer, record_slots);
|
||||
}
|
||||
list = WeakListVisitor<T>::get_weak_next(reinterpret_cast<T*>(list));
|
||||
}
|
||||
if (tail != NULL) {
|
||||
tail->set_weak_next(Smi::FromInt(0));
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
struct WeakListVisitor<JSTypedArray> {
|
||||
static void set_weak_next(JSTypedArray* obj, Object* next) {
|
||||
obj->set_weak_next(next);
|
||||
}
|
||||
|
||||
static Object* get_weak_next(JSTypedArray* obj) {
|
||||
return obj->weak_next();
|
||||
}
|
||||
|
||||
static void VisitLiveObject(JSTypedArray* obj,
|
||||
MarkCompactCollector* collector,
|
||||
WeakObjectRetainer* retainer,
|
||||
bool record_slots) {}
|
||||
|
||||
static const int kWeakNextOffset = JSTypedArray::kWeakNextOffset;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct WeakListVisitor<JSArrayBuffer> {
|
||||
static void set_weak_next(JSArrayBuffer* obj, Object* next) {
|
||||
obj->set_weak_next(next);
|
||||
}
|
||||
|
||||
static Object* get_weak_next(JSArrayBuffer* obj) {
|
||||
return obj->weak_next();
|
||||
}
|
||||
|
||||
static void VisitLiveObject(JSArrayBuffer* array_buffer,
|
||||
MarkCompactCollector* collector,
|
||||
WeakObjectRetainer* retainer,
|
||||
bool record_slots) {
|
||||
Object* typed_array_obj =
|
||||
VisitWeakList<JSTypedArray>(array_buffer->weak_first_array(),
|
||||
collector, retainer, record_slots);
|
||||
array_buffer->set_weak_first_array(typed_array_obj);
|
||||
if (typed_array_obj != Smi::FromInt(0) && record_slots) {
|
||||
Object** slot = HeapObject::RawField(
|
||||
array_buffer, JSArrayBuffer::kWeakFirstArrayOffset);
|
||||
collector->RecordSlot(slot, slot, typed_array_obj);
|
||||
}
|
||||
}
|
||||
|
||||
static const int kWeakNextOffset = JSArrayBuffer::kWeakNextOffset;
|
||||
};
|
||||
|
||||
|
||||
void Heap::ProcessArrayBuffers(WeakObjectRetainer* retainer,
|
||||
bool record_slots) {
|
||||
Object* array_buffer_obj =
|
||||
VisitWeakList<JSArrayBuffer>(array_buffers_list(),
|
||||
mark_compact_collector(),
|
||||
retainer, record_slots);
|
||||
set_array_buffers_list(array_buffer_obj);
|
||||
}
|
||||
|
||||
|
||||
void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
|
||||
@ -1794,6 +1895,14 @@ class ScavengingVisitor : public StaticVisitorBase {
|
||||
&ObjectEvacuationStrategy<POINTER_OBJECT>::
|
||||
Visit);
|
||||
|
||||
table_.Register(kVisitJSArrayBuffer,
|
||||
&ObjectEvacuationStrategy<POINTER_OBJECT>::
|
||||
Visit);
|
||||
|
||||
table_.Register(kVisitJSTypedArray,
|
||||
&ObjectEvacuationStrategy<POINTER_OBJECT>::
|
||||
Visit);
|
||||
|
||||
table_.Register(kVisitJSRegExp,
|
||||
&ObjectEvacuationStrategy<POINTER_OBJECT>::
|
||||
Visit);
|
||||
|
11
src/heap.h
11
src/heap.h
@ -1352,6 +1352,12 @@ class Heap {
|
||||
}
|
||||
Object* native_contexts_list() { return native_contexts_list_; }
|
||||
|
||||
void set_array_buffers_list(Object* object) {
|
||||
array_buffers_list_ = object;
|
||||
}
|
||||
Object* array_buffers_list() { return array_buffers_list_; }
|
||||
|
||||
|
||||
// Number of mark-sweeps.
|
||||
unsigned int ms_count() { return ms_count_; }
|
||||
|
||||
@ -2022,6 +2028,8 @@ class Heap {
|
||||
|
||||
Object* native_contexts_list_;
|
||||
|
||||
Object* array_buffers_list_;
|
||||
|
||||
StoreBufferRebuilder store_buffer_rebuilder_;
|
||||
|
||||
struct StringTypeTable {
|
||||
@ -2165,6 +2173,9 @@ class Heap {
|
||||
// Code to be run before and after mark-compact.
|
||||
void MarkCompactPrologue();
|
||||
|
||||
void ProcessNativeContexts(WeakObjectRetainer* retainer, bool record_slots);
|
||||
void ProcessArrayBuffers(WeakObjectRetainer* retainer, bool record_slots);
|
||||
|
||||
// Record statistics before and after garbage collection.
|
||||
void ReportStatisticsBeforeGC();
|
||||
void ReportStatisticsAfterGC();
|
||||
|
@ -5330,10 +5330,15 @@ void JSArrayBuffer::set_is_external(bool value) {
|
||||
}
|
||||
|
||||
|
||||
ACCESSORS(JSArrayBuffer, weak_next, Object, kWeakNextOffset)
|
||||
ACCESSORS(JSArrayBuffer, weak_first_array, Object, kWeakFirstArrayOffset)
|
||||
|
||||
|
||||
ACCESSORS(JSTypedArray, buffer, Object, kBufferOffset)
|
||||
ACCESSORS(JSTypedArray, byte_offset, Object, kByteOffsetOffset)
|
||||
ACCESSORS(JSTypedArray, byte_length, Object, kByteLengthOffset)
|
||||
ACCESSORS(JSTypedArray, length, Object, kLengthOffset)
|
||||
ACCESSORS(JSTypedArray, weak_next, Object, kWeakNextOffset)
|
||||
|
||||
ACCESSORS(JSRegExp, data, Object, kDataOffset)
|
||||
|
||||
|
@ -540,8 +540,6 @@ static const char* TypeToString(InstanceType type) {
|
||||
case JS_FUNCTION_TYPE: return "JS_FUNCTION";
|
||||
case CODE_TYPE: return "CODE";
|
||||
case JS_ARRAY_TYPE: return "JS_ARRAY";
|
||||
case JS_ARRAY_BUFFER_TYPE: return "JS_ARRAY_BUFFER";
|
||||
case JS_TYPED_ARRAY_TYPE: return "JS_TYPED_ARRAY";
|
||||
case JS_PROXY_TYPE: return "JS_PROXY";
|
||||
case JS_WEAK_MAP_TYPE: return "JS_WEAK_MAP";
|
||||
case JS_REGEXP_TYPE: return "JS_REGEXP";
|
||||
@ -549,6 +547,8 @@ static const char* TypeToString(InstanceType type) {
|
||||
case JS_GLOBAL_OBJECT_TYPE: return "JS_GLOBAL_OBJECT";
|
||||
case JS_BUILTINS_OBJECT_TYPE: return "JS_BUILTINS_OBJECT";
|
||||
case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY";
|
||||
case JS_TYPED_ARRAY_TYPE: return "JS_TYPED_ARRAY";
|
||||
case JS_ARRAY_BUFFER_TYPE: return "JS_ARRAY_BUFFER";
|
||||
case FOREIGN_TYPE: return "FOREIGN";
|
||||
case JS_MESSAGE_OBJECT_TYPE: return "JS_MESSAGE_OBJECT_TYPE";
|
||||
#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME;
|
||||
|
@ -79,6 +79,10 @@ void StaticNewSpaceVisitor<StaticVisitor>::Initialize() {
|
||||
|
||||
table_.Register(kVisitJSFunction, &VisitJSFunction);
|
||||
|
||||
table_.Register(kVisitJSArrayBuffer, &VisitJSArrayBuffer);
|
||||
|
||||
table_.Register(kVisitJSTypedArray, &VisitJSTypedArray);
|
||||
|
||||
table_.Register(kVisitFreeSpace, &VisitFreeSpace);
|
||||
|
||||
table_.Register(kVisitJSWeakMap, &JSObjectVisitor::Visit);
|
||||
@ -98,6 +102,43 @@ void StaticNewSpaceVisitor<StaticVisitor>::Initialize() {
|
||||
}
|
||||
|
||||
|
||||
template<typename StaticVisitor>
|
||||
int StaticNewSpaceVisitor<StaticVisitor>::VisitJSArrayBuffer(
|
||||
Map* map, HeapObject* object) {
|
||||
Heap* heap = map->GetHeap();
|
||||
|
||||
STATIC_ASSERT(
|
||||
JSArrayBuffer::kWeakFirstArrayOffset ==
|
||||
JSArrayBuffer::kWeakNextOffset + kPointerSize);
|
||||
VisitPointers(
|
||||
heap,
|
||||
HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset),
|
||||
HeapObject::RawField(object, JSArrayBuffer::kWeakNextOffset));
|
||||
VisitPointers(
|
||||
heap,
|
||||
HeapObject::RawField(object,
|
||||
JSArrayBuffer::kWeakNextOffset + 2 * kPointerSize),
|
||||
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
|
||||
return JSArrayBuffer::kSizeWithInternalFields;
|
||||
}
|
||||
|
||||
|
||||
template<typename StaticVisitor>
|
||||
int StaticNewSpaceVisitor<StaticVisitor>::VisitJSTypedArray(
|
||||
Map* map, HeapObject* object) {
|
||||
VisitPointers(
|
||||
map->GetHeap(),
|
||||
HeapObject::RawField(object, JSTypedArray::BodyDescriptor::kStartOffset),
|
||||
HeapObject::RawField(object, JSTypedArray::kWeakNextOffset));
|
||||
VisitPointers(
|
||||
map->GetHeap(),
|
||||
HeapObject::RawField(object,
|
||||
JSTypedArray::kWeakNextOffset + kPointerSize),
|
||||
HeapObject::RawField(object, JSTypedArray::kSize));
|
||||
return JSTypedArray::kSize;
|
||||
}
|
||||
|
||||
|
||||
template<typename StaticVisitor>
|
||||
void StaticMarkingVisitor<StaticVisitor>::Initialize() {
|
||||
table_.Register(kVisitShortcutCandidate,
|
||||
@ -149,6 +190,10 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() {
|
||||
|
||||
table_.Register(kVisitJSFunction, &VisitJSFunction);
|
||||
|
||||
table_.Register(kVisitJSArrayBuffer, &VisitJSArrayBuffer);
|
||||
|
||||
table_.Register(kVisitJSTypedArray, &VisitJSTypedArray);
|
||||
|
||||
// Registration for kVisitJSRegExp is done by StaticVisitor.
|
||||
|
||||
table_.Register(kVisitPropertyCell,
|
||||
@ -400,6 +445,41 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSRegExp(
|
||||
}
|
||||
|
||||
|
||||
template<typename StaticVisitor>
|
||||
void StaticMarkingVisitor<StaticVisitor>::VisitJSArrayBuffer(
|
||||
Map* map, HeapObject* object) {
|
||||
Heap* heap = map->GetHeap();
|
||||
|
||||
STATIC_ASSERT(
|
||||
JSArrayBuffer::kWeakFirstArrayOffset ==
|
||||
JSArrayBuffer::kWeakNextOffset + kPointerSize);
|
||||
StaticVisitor::VisitPointers(
|
||||
heap,
|
||||
HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset),
|
||||
HeapObject::RawField(object, JSArrayBuffer::kWeakNextOffset));
|
||||
StaticVisitor::VisitPointers(
|
||||
heap,
|
||||
HeapObject::RawField(object,
|
||||
JSArrayBuffer::kWeakNextOffset + 2 * kPointerSize),
|
||||
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
|
||||
}
|
||||
|
||||
|
||||
template<typename StaticVisitor>
|
||||
void StaticMarkingVisitor<StaticVisitor>::VisitJSTypedArray(
|
||||
Map* map, HeapObject* object) {
|
||||
StaticVisitor::VisitPointers(
|
||||
map->GetHeap(),
|
||||
HeapObject::RawField(object, JSTypedArray::BodyDescriptor::kStartOffset),
|
||||
HeapObject::RawField(object, JSTypedArray::kWeakNextOffset));
|
||||
StaticVisitor::VisitPointers(
|
||||
map->GetHeap(),
|
||||
HeapObject::RawField(object,
|
||||
JSTypedArray::kWeakNextOffset + kPointerSize),
|
||||
HeapObject::RawField(object, JSTypedArray::kSize));
|
||||
}
|
||||
|
||||
|
||||
template<typename StaticVisitor>
|
||||
void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(
|
||||
Heap* heap, Map* map) {
|
||||
|
@ -134,6 +134,12 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
case FILLER_TYPE:
|
||||
return kVisitDataObjectGeneric;
|
||||
|
||||
case JS_ARRAY_BUFFER_TYPE:
|
||||
return kVisitJSArrayBuffer;
|
||||
|
||||
case JS_TYPED_ARRAY_TYPE:
|
||||
return kVisitJSTypedArray;
|
||||
|
||||
case JS_OBJECT_TYPE:
|
||||
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
|
||||
case JS_GENERATOR_OBJECT_TYPE:
|
||||
@ -145,8 +151,6 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
case JS_GLOBAL_OBJECT_TYPE:
|
||||
case JS_BUILTINS_OBJECT_TYPE:
|
||||
case JS_MESSAGE_OBJECT_TYPE:
|
||||
case JS_ARRAY_BUFFER_TYPE:
|
||||
case JS_TYPED_ARRAY_TYPE:
|
||||
return GetVisitorIdForSize(kVisitJSObject,
|
||||
kVisitJSObjectGeneric,
|
||||
instance_size);
|
||||
|
@ -92,6 +92,8 @@ class StaticVisitorBase : public AllStatic {
|
||||
V(SharedFunctionInfo) \
|
||||
V(JSFunction) \
|
||||
V(JSWeakMap) \
|
||||
V(JSArrayBuffer) \
|
||||
V(JSTypedArray) \
|
||||
V(JSRegExp)
|
||||
|
||||
// For data objects, JS objects and structs along with generic visitor which
|
||||
@ -333,6 +335,9 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
|
||||
return FreeSpace::cast(object)->Size();
|
||||
}
|
||||
|
||||
INLINE(static int VisitJSArrayBuffer(Map* map, HeapObject* object));
|
||||
INLINE(static int VisitJSTypedArray(Map* map, HeapObject* object));
|
||||
|
||||
class DataObjectVisitor {
|
||||
public:
|
||||
template<int object_size>
|
||||
@ -407,6 +412,8 @@ class StaticMarkingVisitor : public StaticVisitorBase {
|
||||
INLINE(static void VisitSharedFunctionInfo(Map* map, HeapObject* object));
|
||||
INLINE(static void VisitJSFunction(Map* map, HeapObject* object));
|
||||
INLINE(static void VisitJSRegExp(Map* map, HeapObject* object));
|
||||
INLINE(static void VisitJSArrayBuffer(Map* map, HeapObject* object));
|
||||
INLINE(static void VisitJSTypedArray(Map* map, HeapObject* object));
|
||||
INLINE(static void VisitNativeContext(Map* map, HeapObject* object));
|
||||
|
||||
// Mark pointers in a Map and its TransitionArray together, possibly
|
||||
|
@ -8786,6 +8786,12 @@ class JSArrayBuffer: public JSObject {
|
||||
inline bool is_external();
|
||||
inline void set_is_external(bool value);
|
||||
|
||||
// [weak_next]: linked list of array buffers.
|
||||
DECL_ACCESSORS(weak_next, Object)
|
||||
|
||||
// [weak_first_array]: weak linked list of typed arrays.
|
||||
DECL_ACCESSORS(weak_first_array, Object)
|
||||
|
||||
// Casting.
|
||||
static inline JSArrayBuffer* cast(Object* obj);
|
||||
|
||||
@ -8796,7 +8802,12 @@ class JSArrayBuffer: public JSObject {
|
||||
static const int kBackingStoreOffset = JSObject::kHeaderSize;
|
||||
static const int kByteLengthOffset = kBackingStoreOffset + kPointerSize;
|
||||
static const int kFlagOffset = kByteLengthOffset + kPointerSize;
|
||||
static const int kSize = kFlagOffset + kPointerSize;
|
||||
static const int kWeakNextOffset = kFlagOffset + kPointerSize;
|
||||
static const int kWeakFirstArrayOffset = kWeakNextOffset + kPointerSize;
|
||||
static const int kSize = kWeakFirstArrayOffset + kPointerSize;
|
||||
|
||||
static const int kSizeWithInternalFields =
|
||||
kSize + v8::ArrayBuffer::kInternalFieldCount * kPointerSize;
|
||||
|
||||
private:
|
||||
// Bit position in a flag
|
||||
@ -8820,6 +8831,9 @@ class JSTypedArray: public JSObject {
|
||||
// [length]: length of typed array in elements.
|
||||
DECL_ACCESSORS(length, Object)
|
||||
|
||||
// [weak_next]: linked list of typed arrays over the same array buffer.
|
||||
DECL_ACCESSORS(weak_next, Object)
|
||||
|
||||
// Casting.
|
||||
static inline JSTypedArray* cast(Object* obj);
|
||||
|
||||
@ -8834,7 +8848,8 @@ class JSTypedArray: public JSObject {
|
||||
static const int kByteOffsetOffset = kBufferOffset + kPointerSize;
|
||||
static const int kByteLengthOffset = kByteOffsetOffset + kPointerSize;
|
||||
static const int kLengthOffset = kByteLengthOffset + kPointerSize;
|
||||
static const int kSize = kLengthOffset + kPointerSize;
|
||||
static const int kWeakNextOffset = kLengthOffset + kPointerSize;
|
||||
static const int kSize = kWeakNextOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray);
|
||||
|
@ -687,6 +687,10 @@ void Runtime::SetupArrayBuffer(Isolate* isolate,
|
||||
isolate->factory()->NewNumberFromSize(allocated_length);
|
||||
CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
|
||||
array_buffer->set_byte_length(*byte_length);
|
||||
|
||||
array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
|
||||
isolate->heap()->set_array_buffers_list(*array_buffer);
|
||||
array_buffer->set_weak_first_array(Smi::FromInt(0));
|
||||
}
|
||||
|
||||
|
||||
@ -855,6 +859,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
|
||||
|
||||
Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
|
||||
holder->set_length(*length_obj);
|
||||
holder->set_weak_next(buffer->weak_first_array());
|
||||
buffer->set_weak_first_array(*holder);
|
||||
|
||||
Handle<ExternalArray> elements =
|
||||
isolate->factory()->NewExternalArray(
|
||||
|
@ -103,7 +103,8 @@
|
||||
'test-unbound-queue.cc',
|
||||
'test-utils.cc',
|
||||
'test-version.cc',
|
||||
'test-weakmaps.cc'
|
||||
'test-weakmaps.cc',
|
||||
'test-weaktypedarrays.cc'
|
||||
],
|
||||
'conditions': [
|
||||
['v8_target_arch=="ia32"', {
|
||||
|
380
test/cctest/test-weaktypedarrays.cc
Normal file
380
test/cctest/test-weaktypedarrays.cc
Normal file
@ -0,0 +1,380 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "v8.h"
|
||||
#include "api.h"
|
||||
#include "heap.h"
|
||||
#include "objects.h"
|
||||
|
||||
#include "cctest.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
|
||||
static Isolate* GetIsolateFrom(LocalContext* context) {
|
||||
return reinterpret_cast<Isolate*>((*context)->GetIsolate());
|
||||
}
|
||||
|
||||
|
||||
static int CountArrayBuffersInWeakList(Heap* heap) {
|
||||
int count = 0;
|
||||
for (Object* o = heap->array_buffers_list();
|
||||
o != Smi::FromInt(0);
|
||||
o = JSArrayBuffer::cast(o)->weak_next()) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static bool HasArrayBufferInWeakList(Heap* heap, JSArrayBuffer* ab) {
|
||||
for (Object* o = heap->array_buffers_list();
|
||||
o != Smi::FromInt(0);
|
||||
o = JSArrayBuffer::cast(o)->weak_next()) {
|
||||
if (ab == o) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int CountTypedArrays(JSArrayBuffer* array_buffer) {
|
||||
int count = 0;
|
||||
for (Object* o = array_buffer->weak_first_array();
|
||||
o != Smi::FromInt(0);
|
||||
o = JSTypedArray::cast(o)->weak_next()) {
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool HasTypedArrayInWeakList(JSArrayBuffer* array_buffer,
|
||||
JSTypedArray* ta) {
|
||||
for (Object* o = array_buffer->weak_first_array();
|
||||
o != Smi::FromInt(0);
|
||||
o = JSTypedArray::cast(o)->weak_next()) {
|
||||
if (ta == o) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
TEST(WeakArrayBuffersFromApi) {
|
||||
v8::V8::Initialize();
|
||||
LocalContext context;
|
||||
Isolate* isolate = GetIsolateFrom(&context);
|
||||
|
||||
CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
{
|
||||
v8::HandleScope s1(context->GetIsolate());
|
||||
v8::Handle<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(256);
|
||||
{
|
||||
v8::HandleScope s2(context->GetIsolate());
|
||||
v8::Handle<v8::ArrayBuffer> ab2 = v8::ArrayBuffer::New(128);
|
||||
|
||||
Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
|
||||
Handle<JSArrayBuffer> iab2 = v8::Utils::OpenHandle(*ab2);
|
||||
CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1));
|
||||
CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab2));
|
||||
}
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
{
|
||||
HandleScope scope2(isolate);
|
||||
Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
|
||||
|
||||
CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1));
|
||||
}
|
||||
}
|
||||
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
}
|
||||
|
||||
|
||||
TEST(WeakArrayBuffersFromScript) {
|
||||
v8::V8::Initialize();
|
||||
LocalContext context;
|
||||
Isolate* isolate = GetIsolateFrom(&context);
|
||||
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
// Create 3 array buffers, make i-th of them garbage,
|
||||
// validate correct state of array buffer weak list.
|
||||
CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
{
|
||||
v8::HandleScope scope(context->GetIsolate());
|
||||
|
||||
{
|
||||
v8::HandleScope s1(context->GetIsolate());
|
||||
CompileRun("var ab1 = new ArrayBuffer(256);"
|
||||
"var ab2 = new ArrayBuffer(256);"
|
||||
"var ab3 = new ArrayBuffer(256);");
|
||||
v8::Handle<v8::ArrayBuffer> ab1(
|
||||
v8::ArrayBuffer::Cast(*CompileRun("ab1")));
|
||||
v8::Handle<v8::ArrayBuffer> ab2(
|
||||
v8::ArrayBuffer::Cast(*CompileRun("ab2")));
|
||||
v8::Handle<v8::ArrayBuffer> ab3(
|
||||
v8::ArrayBuffer::Cast(*CompileRun("ab3")));
|
||||
|
||||
CHECK_EQ(3, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
CHECK(HasArrayBufferInWeakList(isolate->heap(),
|
||||
*v8::Utils::OpenHandle(*ab1)));
|
||||
CHECK(HasArrayBufferInWeakList(isolate->heap(),
|
||||
*v8::Utils::OpenHandle(*ab2)));
|
||||
CHECK(HasArrayBufferInWeakList(isolate->heap(),
|
||||
*v8::Utils::OpenHandle(*ab3)));
|
||||
}
|
||||
|
||||
i::ScopedVector<char> source(1024);
|
||||
i::OS::SNPrintF(source, "ab%d = null;", i);
|
||||
CompileRun(source.start());
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
|
||||
CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
|
||||
{
|
||||
v8::HandleScope s2(context->GetIsolate());
|
||||
for (int j = 1; j <= 3; j++) {
|
||||
if (j == i) continue;
|
||||
i::OS::SNPrintF(source, "ab%d", j);
|
||||
v8::Handle<v8::ArrayBuffer> ab(
|
||||
v8::ArrayBuffer::Cast(*CompileRun(source.start())));
|
||||
CHECK(HasArrayBufferInWeakList(isolate->heap(),
|
||||
*v8::Utils::OpenHandle(*ab)));
|
||||
}
|
||||
}
|
||||
|
||||
CompileRun("ab1 = null; ab2 = null; ab3 = null;");
|
||||
}
|
||||
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TypedArray>
|
||||
void TestTypedArrayFromApi() {
|
||||
v8::V8::Initialize();
|
||||
LocalContext context;
|
||||
Isolate* isolate = GetIsolateFrom(&context);
|
||||
|
||||
v8::HandleScope s1(context->GetIsolate());
|
||||
v8::Handle<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(2048);
|
||||
Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
|
||||
{
|
||||
v8::HandleScope s2(context->GetIsolate());
|
||||
v8::Handle<TypedArray> ta1 = TypedArray::New(ab, 0, 256);
|
||||
{
|
||||
v8::HandleScope s3(context->GetIsolate());
|
||||
v8::Handle<TypedArray> ta2 = TypedArray::New(ab, 0, 128);
|
||||
|
||||
Handle<JSTypedArray> ita1 = v8::Utils::OpenHandle(*ta1);
|
||||
Handle<JSTypedArray> ita2 = v8::Utils::OpenHandle(*ta2);
|
||||
CHECK_EQ(2, CountTypedArrays(*iab));
|
||||
CHECK(HasTypedArrayInWeakList(*iab, *ita1));
|
||||
CHECK(HasTypedArrayInWeakList(*iab, *ita2));
|
||||
}
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
CHECK_EQ(1, CountTypedArrays(*iab));
|
||||
Handle<JSTypedArray> ita1 = v8::Utils::OpenHandle(*ta1);
|
||||
CHECK(HasTypedArrayInWeakList(*iab, *ita1));
|
||||
}
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
|
||||
CHECK_EQ(0, CountTypedArrays(*iab));
|
||||
}
|
||||
|
||||
|
||||
TEST(Uint8ArrayFromApi) {
|
||||
TestTypedArrayFromApi<v8::Uint8Array>();
|
||||
}
|
||||
|
||||
|
||||
TEST(Int8ArrayFromApi) {
|
||||
TestTypedArrayFromApi<v8::Int8Array>();
|
||||
}
|
||||
|
||||
|
||||
TEST(Uint16ArrayFromApi) {
|
||||
TestTypedArrayFromApi<v8::Uint16Array>();
|
||||
}
|
||||
|
||||
|
||||
TEST(Int16ArrayFromApi) {
|
||||
TestTypedArrayFromApi<v8::Int16Array>();
|
||||
}
|
||||
|
||||
|
||||
TEST(Uint32ArrayFromApi) {
|
||||
TestTypedArrayFromApi<v8::Uint32Array>();
|
||||
}
|
||||
|
||||
|
||||
TEST(Int32ArrayFromApi) {
|
||||
TestTypedArrayFromApi<v8::Int32Array>();
|
||||
}
|
||||
|
||||
|
||||
TEST(Float32ArrayFromApi) {
|
||||
TestTypedArrayFromApi<v8::Float32Array>();
|
||||
}
|
||||
|
||||
|
||||
TEST(Float64ArrayFromApi) {
|
||||
TestTypedArrayFromApi<v8::Float64Array>();
|
||||
}
|
||||
|
||||
|
||||
TEST(Uint8ClampedArrayFromApi) {
|
||||
TestTypedArrayFromApi<v8::Uint8ClampedArray>();
|
||||
}
|
||||
|
||||
template <typename TypedArray>
|
||||
static void TestTypedArrayFromScript(const char* constructor) {
|
||||
v8::V8::Initialize();
|
||||
LocalContext context;
|
||||
Isolate* isolate = GetIsolateFrom(&context);
|
||||
v8::HandleScope scope(context->GetIsolate());
|
||||
CompileRun("var ab = new ArrayBuffer(2048);");
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
// Create 3 typed arrays, make i-th of them garbage,
|
||||
// validate correct state of typed array weak list.
|
||||
v8::HandleScope s0(context->GetIsolate());
|
||||
i::ScopedVector<char> source(2048);
|
||||
|
||||
CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
|
||||
{
|
||||
v8::HandleScope s1(context->GetIsolate());
|
||||
i::OS::SNPrintF(source,
|
||||
"var ta1 = new %s(ab);"
|
||||
"var ta2 = new %s(ab);"
|
||||
"var ta3 = new %s(ab)",
|
||||
constructor, constructor, constructor);
|
||||
|
||||
CompileRun(source.start());
|
||||
v8::Handle<v8::ArrayBuffer> ab(v8::ArrayBuffer::Cast(*CompileRun("ab")));
|
||||
v8::Handle<TypedArray> ta1(TypedArray::Cast(*CompileRun("ta1")));
|
||||
v8::Handle<TypedArray> ta2(TypedArray::Cast(*CompileRun("ta2")));
|
||||
v8::Handle<TypedArray> ta3(TypedArray::Cast(*CompileRun("ta3")));
|
||||
CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
|
||||
CHECK_EQ(3, CountTypedArrays(*iab));
|
||||
CHECK(HasTypedArrayInWeakList(*iab, *v8::Utils::OpenHandle(*ta1)));
|
||||
CHECK(HasTypedArrayInWeakList(*iab, *v8::Utils::OpenHandle(*ta2)));
|
||||
CHECK(HasTypedArrayInWeakList(*iab, *v8::Utils::OpenHandle(*ta3)));
|
||||
}
|
||||
|
||||
i::OS::SNPrintF(source, "ta%d = null;", i);
|
||||
CompileRun(source.start());
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
|
||||
CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
|
||||
{
|
||||
v8::HandleScope s2(context->GetIsolate());
|
||||
v8::Handle<v8::ArrayBuffer> ab(v8::ArrayBuffer::Cast(*CompileRun("ab")));
|
||||
Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
|
||||
CHECK_EQ(2, CountTypedArrays(*iab));
|
||||
for (int j = 1; j <= 3; j++) {
|
||||
if (j == i) continue;
|
||||
i::OS::SNPrintF(source, "ta%d", j);
|
||||
v8::Handle<TypedArray> ta(
|
||||
TypedArray::Cast(*CompileRun(source.start())));
|
||||
CHECK(HasTypedArrayInWeakList(*iab, *v8::Utils::OpenHandle(*ta)));
|
||||
}
|
||||
}
|
||||
|
||||
CompileRun("ta1 = null; ta2 = null; ta3 = null;");
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
|
||||
CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
|
||||
|
||||
{
|
||||
v8::HandleScope s3(context->GetIsolate());
|
||||
v8::Handle<v8::ArrayBuffer> ab(v8::ArrayBuffer::Cast(*CompileRun("ab")));
|
||||
Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
|
||||
CHECK_EQ(0, CountTypedArrays(*iab));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Uint8ArrayFromScript) {
|
||||
TestTypedArrayFromScript<v8::Uint8Array>("Uint8Array");
|
||||
}
|
||||
|
||||
|
||||
TEST(Int8ArrayFromScript) {
|
||||
TestTypedArrayFromScript<v8::Int8Array>("Int8Array");
|
||||
}
|
||||
|
||||
|
||||
TEST(Uint16ArrayFromScript) {
|
||||
TestTypedArrayFromScript<v8::Uint16Array>("Uint16Array");
|
||||
}
|
||||
|
||||
|
||||
TEST(Int16ArrayFromScript) {
|
||||
TestTypedArrayFromScript<v8::Int16Array>("Int16Array");
|
||||
}
|
||||
|
||||
|
||||
TEST(Uint32ArrayFromScript) {
|
||||
TestTypedArrayFromScript<v8::Uint32Array>("Uint32Array");
|
||||
}
|
||||
|
||||
|
||||
TEST(Int32ArrayFromScript) {
|
||||
TestTypedArrayFromScript<v8::Int32Array>("Int32Array");
|
||||
}
|
||||
|
||||
|
||||
TEST(Float32ArrayFromScript) {
|
||||
TestTypedArrayFromScript<v8::Float32Array>("Float32Array");
|
||||
}
|
||||
|
||||
|
||||
TEST(Float64ArrayFromScript) {
|
||||
TestTypedArrayFromScript<v8::Float64Array>("Float64Array");
|
||||
}
|
||||
|
||||
|
||||
TEST(Uint8ClampedArrayFromScript) {
|
||||
TestTypedArrayFromScript<v8::Uint8ClampedArray>("Uint8ClampedArray");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user