Commit cd07b473 authored by fpizlo@apple.com's avatar fpizlo@apple.com

Assertion failure in JSC::SlotVisitor::copyLater when marking JSDataView

https://bugs.webkit.org/show_bug.cgi?id=120099

Source/JavaScriptCore: 

Reviewed by Mark Hahnenberg.
        
JSDataView should not store the ArrayBuffer* in the butterfly indexing header, since
JSDataView may have ordinary JS indexed properties.

* runtime/ClassInfo.h:
* runtime/JSArrayBufferView.cpp:
(JSC::JSArrayBufferView::ConstructionContext::ConstructionContext):
(JSC::JSArrayBufferView::finishCreation):
* runtime/JSArrayBufferView.h:
(JSC::hasArrayBuffer):
* runtime/JSArrayBufferViewInlines.h:
(JSC::JSArrayBufferView::buffer):
(JSC::JSArrayBufferView::neuter):
(JSC::JSArrayBufferView::byteOffset):
* runtime/JSCell.cpp:
(JSC::JSCell::slowDownAndWasteMemory):
* runtime/JSCell.h:
* runtime/JSDataView.cpp:
(JSC::JSDataView::JSDataView):
(JSC::JSDataView::create):
(JSC::JSDataView::slowDownAndWasteMemory):
* runtime/JSDataView.h:
(JSC::JSDataView::buffer):
* runtime/JSGenericTypedArrayView.h:
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::::visitChildren):
(JSC::::slowDownAndWasteMemory):

LayoutTests: 

Reviewed by Mark Hahnenberg.

* fast/js/regress/ArrayBuffer-DataView-alloc-large-long-lived-expected.txt: Added.
* fast/js/regress/ArrayBuffer-DataView-alloc-large-long-lived.html: Added.
* fast/js/regress/ArrayBuffer-DataView-alloc-long-lived-expected.txt: Added.
* fast/js/regress/ArrayBuffer-DataView-alloc-long-lived.html: Added.
* fast/js/regress/DataView-custom-properties-expected.txt: Added.
* fast/js/regress/DataView-custom-properties.html: Added.
* fast/js/regress/script-tests/ArrayBuffer-DataView-alloc-large-long-lived.js: Added.
* fast/js/regress/script-tests/ArrayBuffer-DataView-alloc-long-lived.js: Added.
* fast/js/regress/script-tests/DataView-custom-properties.js: Added.
* platform/mac/TestExpectations: 



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@154408 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent a61dc64e
2013-08-21 Filip Pizlo <fpizlo@apple.com>
Assertion failure in JSC::SlotVisitor::copyLater when marking JSDataView
https://bugs.webkit.org/show_bug.cgi?id=120099
Reviewed by Mark Hahnenberg.
* fast/js/regress/ArrayBuffer-DataView-alloc-large-long-lived-expected.txt: Added.
* fast/js/regress/ArrayBuffer-DataView-alloc-large-long-lived.html: Added.
* fast/js/regress/ArrayBuffer-DataView-alloc-long-lived-expected.txt: Added.
* fast/js/regress/ArrayBuffer-DataView-alloc-long-lived.html: Added.
* fast/js/regress/DataView-custom-properties-expected.txt: Added.
* fast/js/regress/DataView-custom-properties.html: Added.
* fast/js/regress/script-tests/ArrayBuffer-DataView-alloc-large-long-lived.js: Added.
* fast/js/regress/script-tests/ArrayBuffer-DataView-alloc-long-lived.js: Added.
* fast/js/regress/script-tests/DataView-custom-properties.js: Added.
* platform/mac/TestExpectations:
2013-08-21 Mark Hahnenberg <mhahnenberg@apple.com>
Remove incorrect ASSERT from CopyVisitor::visitItem
JSRegress/ArrayBuffer-DataView-alloc-large-long-lived
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/ArrayBuffer-DataView-alloc-large-long-lived.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/ArrayBuffer-DataView-alloc-long-lived
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/ArrayBuffer-DataView-alloc-long-lived.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/DataView-custom-properties
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/DataView-custom-properties.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../resources/js-test-post.js"></script>
</body>
</html>
var array = new Array(10000);
for (var i = 0; i < 100000; ++i)
array[i % array.length] = new DataView(new ArrayBuffer(1000));
for (var i = 0; i < array.length; ++i) {
if (array[i].byteLength != 1000)
throw "Error: bad length: " + array[i].byteLength;
if (array[i].buffer.byteLength != 1000)
throw "Error: bad buffer.byteLength: " + array[i].buffer.byteLength;
}
var array = new Array(10000);
for (var i = 0; i < 70000; ++i)
array[i % array.length] = new DataView(new ArrayBuffer(10));
for (var i = 0; i < array.length; ++i) {
if (array[i].byteLength != 10)
throw "Error: bad length: " + array[i].byteLength;
if (array[i].buffer.byteLength != 10)
throw "Error: bad buffer.byteLength: " + array[i].buffer.byteLength;
}
var array = new Array(10000);
for (var i = 0; i < 100000; ++i) {
var thingy = new DataView(new ArrayBuffer(1000));
switch (i % 3) {
case 0:
break;
case 1:
thingy.f = 42;
break;
case 2:
thingy[0] = 42;
break;
}
array[i % array.length] = thingy;
}
for (var i = 0; i < array.length; ++i) {
if (array[i].byteLength != 1000)
throw "Error: bad length: " + array[i].byteLength;
if (array[i].buffer.byteLength != 1000)
throw "Error: bad buffer.byteLength: " + array[i].buffer.byteLength;
switch (i % 3) {
case 0:
break;
case 1:
if (array[i].f != 42)
throw "Error: bad field 'f': " + array[i].f;
break;
case 2:
if (array[i][0] != 42)
throw "Error: bad element 0: " + array[i][0];
break;
}
}
......@@ -1312,4 +1312,3 @@ webkit.org/b/120085 [ Lion ] http/tests/inspector/resource-tree/resource-tree-do
webkit.org/b/120087 [ Lion ] fast/forms/submit-to-url-fragment.html [ Pass Crash ]
webkit.org/b/120099 [ Debug ] fast/canvas/webgl/array-message-passing.html [ Crash ]
2013-08-21 Filip Pizlo <fpizlo@apple.com>
Assertion failure in JSC::SlotVisitor::copyLater when marking JSDataView
https://bugs.webkit.org/show_bug.cgi?id=120099
Reviewed by Mark Hahnenberg.
JSDataView should not store the ArrayBuffer* in the butterfly indexing header, since
JSDataView may have ordinary JS indexed properties.
* runtime/ClassInfo.h:
* runtime/JSArrayBufferView.cpp:
(JSC::JSArrayBufferView::ConstructionContext::ConstructionContext):
(JSC::JSArrayBufferView::finishCreation):
* runtime/JSArrayBufferView.h:
(JSC::hasArrayBuffer):
* runtime/JSArrayBufferViewInlines.h:
(JSC::JSArrayBufferView::buffer):
(JSC::JSArrayBufferView::neuter):
(JSC::JSArrayBufferView::byteOffset):
* runtime/JSCell.cpp:
(JSC::JSCell::slowDownAndWasteMemory):
* runtime/JSCell.h:
* runtime/JSDataView.cpp:
(JSC::JSDataView::JSDataView):
(JSC::JSDataView::create):
(JSC::JSDataView::slowDownAndWasteMemory):
* runtime/JSDataView.h:
(JSC::JSDataView::buffer):
* runtime/JSGenericTypedArrayView.h:
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::::visitChildren):
(JSC::::slowDownAndWasteMemory):
2013-08-21 Mark Hahnenberg <mhahnenberg@apple.com>
Remove incorrect ASSERT from CopyVisitor::visitItem
......
......@@ -95,7 +95,7 @@ struct MethodTable {
typedef bool (*DefineOwnPropertyFunctionPtr)(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool);
DefineOwnPropertyFunctionPtr defineOwnProperty;
typedef void (*SlowDownAndWasteMemory)(JSArrayBufferView*);
typedef ArrayBuffer* (*SlowDownAndWasteMemory)(JSArrayBufferView*);
SlowDownAndWasteMemory slowDownAndWasteMemory;
typedef PassRefPtr<ArrayBufferView> (*GetTypedArrayImpl)(JSArrayBufferView*);
......
......@@ -96,6 +96,17 @@ JSArrayBufferView::ConstructionContext::ConstructionContext(
m_butterfly = Butterfly::create(vm, 0, 0, 0, true, indexingHeader, 0);
}
JSArrayBufferView::ConstructionContext::ConstructionContext(
Structure* structure, PassRefPtr<ArrayBuffer> arrayBuffer,
unsigned byteOffset, unsigned length, DataViewTag)
: m_structure(structure)
, m_vector(static_cast<uint8_t*>(arrayBuffer->data()) + byteOffset)
, m_length(length)
, m_mode(DataViewMode)
, m_butterfly(0)
{
}
JSArrayBufferView::JSArrayBufferView(VM& vm, ConstructionContext& context)
: Base(vm, context.structure(), context.butterfly())
, m_vector(context.vector())
......@@ -116,6 +127,10 @@ void JSArrayBufferView::finishCreation(VM& vm)
case WastefulTypedArray:
vm.heap.addReference(this, butterfly()->indexingHeader()->arrayBuffer());
return;
case DataViewMode:
ASSERT(!butterfly());
vm.heap.addReference(this, jsCast<JSDataView*>(this)->buffer());
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
......
......@@ -70,8 +70,19 @@ enum TypedArrayMode {
// vector allocated using who-knows-what, and M = WastefulTypedArray.
// The view does not own the vector.
WastefulTypedArray,
// A data view. B is unused, V points to a vector allocated using who-
// knows-what, and M = DataViewMode. The view does not own the vector.
// There is an extra field (in JSDataView) that points to the
// ArrayBuffer.
DataViewMode
};
inline bool hasArrayBuffer(TypedArrayMode mode)
{
return mode >= WastefulTypedArray;
}
// When WebCore uses a JSArrayBufferView, it expects to be able to get the native
// ArrayBuffer and little else. This requires slowing down and wasting memory,
// and then accessing things via the Butterfly. When JS uses a JSArrayBufferView
......@@ -110,6 +121,11 @@ protected:
VM&, Structure*, PassRefPtr<ArrayBuffer>,
unsigned byteOffset, unsigned length);
enum DataViewTag { DataView };
ConstructionContext(
Structure*, PassRefPtr<ArrayBuffer>,
unsigned byteOffset, unsigned length, DataViewTag);
bool operator!() const { return !m_structure; }
Structure* structure() const { return m_structure; }
......@@ -137,10 +153,6 @@ protected:
static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
public:
// Allocates the full-on native buffer. Also moves the data into the C heap
// if necessary.
void slowDownAndWasteMemoryIfNecessary();
TypedArrayMode mode() const { return m_mode; }
ArrayBuffer* buffer();
PassRefPtr<ArrayBufferView> impl();
......
......@@ -28,19 +28,20 @@
#include "ArrayBufferView.h"
#include "JSArrayBufferView.h"
#include "JSDataView.h"
namespace JSC {
inline void JSArrayBufferView::slowDownAndWasteMemoryIfNecessary()
{
if (m_mode != WastefulTypedArray)
methodTable()->slowDownAndWasteMemory(this);
}
inline ArrayBuffer* JSArrayBufferView::buffer()
{
slowDownAndWasteMemoryIfNecessary();
return butterfly()->indexingHeader()->arrayBuffer();
switch (m_mode) {
case WastefulTypedArray:
return butterfly()->indexingHeader()->arrayBuffer();
case DataViewMode:
return jsCast<JSDataView*>(this)->buffer();
default:
return methodTable()->slowDownAndWasteMemory(this);
}
}
inline PassRefPtr<ArrayBufferView> JSArrayBufferView::impl()
......@@ -50,17 +51,15 @@ inline PassRefPtr<ArrayBufferView> JSArrayBufferView::impl()
inline void JSArrayBufferView::neuter()
{
ASSERT(m_mode == WastefulTypedArray);
ASSERT(hasArrayBuffer(m_mode));
m_length = 0;
m_vector = 0;
}
inline unsigned JSArrayBufferView::byteOffset()
{
if (m_mode != WastefulTypedArray) {
ASSERT(m_mode == FastTypedArray || m_mode == OversizeTypedArray);
if (!hasArrayBuffer(m_mode))
return 0;
}
ptrdiff_t delta =
static_cast<uint8_t*>(m_vector) - static_cast<uint8_t*>(buffer()->data());
......
......@@ -218,9 +218,10 @@ bool JSCell::defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDesc
return false;
}
void JSCell::slowDownAndWasteMemory(JSArrayBufferView*)
ArrayBuffer* JSCell::slowDownAndWasteMemory(JSArrayBufferView*)
{
RELEASE_ASSERT_NOT_REACHED();
return 0;
}
PassRefPtr<ArrayBufferView> JSCell::getTypedArrayImpl(JSArrayBufferView*)
......
......@@ -167,7 +167,7 @@ protected:
static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
JS_EXPORT_PRIVATE static NO_RETURN_DUE_TO_CRASH void slowDownAndWasteMemory(JSArrayBufferView*);
JS_EXPORT_PRIVATE static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*);
JS_EXPORT_PRIVATE static PassRefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*);
private:
......
......@@ -36,8 +36,9 @@ namespace JSC {
const ClassInfo JSDataView::s_info = {
"DataView", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSDataView)};
JSDataView::JSDataView(VM& vm, ConstructionContext& context)
JSDataView::JSDataView(VM& vm, ConstructionContext& context, ArrayBuffer* buffer)
: Base(vm, context)
, m_buffer(buffer)
{
}
......@@ -52,10 +53,11 @@ JSDataView* JSDataView::create(
return 0;
}
VM& vm = exec->vm();
ConstructionContext context(vm, structure, buffer, byteOffset, byteLength);
ConstructionContext context(
structure, buffer, byteOffset, byteLength, ConstructionContext::DataView);
ASSERT(context);
JSDataView* result =
new (NotNull, allocateCell<JSDataView>(vm.heap)) JSDataView(vm, context);
new (NotNull, allocateCell<JSDataView>(vm.heap)) JSDataView(vm, context, buffer.get());
result->finishCreation(vm);
return result;
}
......@@ -95,9 +97,10 @@ bool JSDataView::getOwnPropertySlot(
return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
}
void JSDataView::slowDownAndWasteMemory(JSArrayBufferView*)
ArrayBuffer* JSDataView::slowDownAndWasteMemory(JSArrayBufferView*)
{
UNREACHABLE_FOR_PLATFORM();
return 0;
}
PassRefPtr<ArrayBufferView> JSDataView::getTypedArrayImpl(JSArrayBufferView* object)
......
......@@ -37,7 +37,7 @@ public:
static const unsigned elementSize = 1;
protected:
JSDataView(VM&, ConstructionContext&);
JSDataView(VM&, ConstructionContext&, ArrayBuffer*);
public:
static JSDataView* create(
......@@ -50,6 +50,8 @@ public:
static JSDataView* create(ExecState*, Structure*, unsigned length);
bool set(ExecState*, JSObject*, unsigned offset, unsigned length);
ArrayBuffer* buffer() const { return m_buffer; }
PassRefPtr<DataView> typedImpl();
static const TypedArrayType TypedArrayStorageType = TypeDataView;
......@@ -57,13 +59,16 @@ public:
protected:
static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
static void slowDownAndWasteMemory(JSArrayBufferView*);
static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*);
static PassRefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*);
public:
static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
DECLARE_EXPORT_INFO;
private:
ArrayBuffer* m_buffer;
};
} // namespace JSC
......
......@@ -244,7 +244,7 @@ protected:
// Allocates the full-on native buffer and moves data into the C heap if
// necessary. Note that this never allocates in the GC heap.
static void slowDownAndWasteMemory(JSArrayBufferView*);
static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*);
static PassRefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*);
};
......
......@@ -379,6 +379,10 @@ void JSGenericTypedArrayView<Adaptor>::visitChildren(JSCell* cell, SlotVisitor&
case WastefulTypedArray:
break;
case DataViewMode:
RELEASE_ASSERT_NOT_REACHED();
break;
}
Base::visitChildren(thisObject, visitor);
......@@ -403,7 +407,7 @@ void JSGenericTypedArrayView<Adaptor>::copyBackingStore(
}
template<typename Adaptor>
void JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBufferView* object)
ArrayBuffer* JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBufferView* object)
{
JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
......@@ -451,7 +455,7 @@ void JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBufferView*
buffer = ArrayBuffer::createAdopted(thisObject->m_vector, thisObject->byteLength());
break;
case WastefulTypedArray:
default:
RELEASE_ASSERT_NOT_REACHED();
break;
}
......@@ -460,6 +464,8 @@ void JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBufferView*
thisObject->m_vector = buffer->data();
thisObject->m_mode = WastefulTypedArray;
heap->addReference(thisObject, buffer.get());
return buffer.get();
}
template<typename Adaptor>
......
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