Browse Source

Revert "typed arrays: only share ArrayBuffer backing store"

We're going to fix this differently. The real bug is that
Buffer::HasInstance() returns true for typed arrays.

This reverts commit 01ee551e70.
v0.9.10-release
Ben Noordhuis 12 years ago
parent
commit
144e21ed30
  1. 98
      src/v8_typed_array.cc
  2. 33
      test/simple/test-typed-arrays.js

98
src/v8_typed_array.cc

@ -35,41 +35,11 @@ using node::ThrowRangeError;
using node::ThrowTypeError; using node::ThrowTypeError;
using node::ThrowError; using node::ThrowError;
template <unsigned int TBytes, v8::ExternalArrayType TEAType>
class TypedArray;
typedef TypedArray<1, v8::kExternalByteArray> Int8Array;
typedef TypedArray<1, v8::kExternalUnsignedByteArray> Uint8Array;
typedef TypedArray<1, v8::kExternalPixelArray> Uint8ClampedArray;
typedef TypedArray<2, v8::kExternalShortArray> Int16Array;
typedef TypedArray<2, v8::kExternalUnsignedShortArray> Uint16Array;
typedef TypedArray<4, v8::kExternalIntArray> Int32Array;
typedef TypedArray<4, v8::kExternalUnsignedIntArray> Uint32Array;
typedef TypedArray<4, v8::kExternalFloatArray> Float32Array;
typedef TypedArray<8, v8::kExternalDoubleArray> Float64Array;
struct BatchedMethods { struct BatchedMethods {
const char* name; const char* name;
v8::Handle<v8::Value> (*func)(const v8::Arguments& args); v8::Handle<v8::Value> (*func)(const v8::Arguments& args);
}; };
void WeakCallback(v8::Persistent<v8::Value> value, void* data) {
v8::Object* obj = v8::Object::Cast(*value);
void* ptr = obj->GetIndexedPropertiesExternalArrayData();
int element_size = v8_typed_array::SizeOfArrayElementForType(
obj->GetIndexedPropertiesExternalArrayDataType());
int size =
obj->GetIndexedPropertiesExternalArrayDataLength() * element_size;
v8::V8::AdjustAmountOfExternalAllocatedMemory(-size);
value.ClearWeak();
value.Dispose();
free(ptr);
}
class ArrayBuffer { class ArrayBuffer {
public: public:
static v8::Persistent<v8::FunctionTemplate> GetTemplate() { static v8::Persistent<v8::FunctionTemplate> GetTemplate() {
@ -99,6 +69,23 @@ class ArrayBuffer {
} }
private: private:
static void WeakCallback(v8::Persistent<v8::Value> value, void* data) {
v8::Object* obj = v8::Object::Cast(*value);
void* ptr = obj->GetIndexedPropertiesExternalArrayData();
int element_size = v8_typed_array::SizeOfArrayElementForType(
obj->GetIndexedPropertiesExternalArrayDataType());
int size =
obj->GetIndexedPropertiesExternalArrayDataLength() * element_size;
v8::V8::AdjustAmountOfExternalAllocatedMemory(-size);
value.ClearWeak();
value.Dispose();
free(ptr);
}
static v8::Handle<v8::Value> V8New(const v8::Arguments& args) { static v8::Handle<v8::Value> V8New(const v8::Arguments& args) {
if (!args.IsConstructCall()) if (!args.IsConstructCall())
return ThrowTypeError("Constructor cannot be called as a function."); return ThrowTypeError("Constructor cannot be called as a function.");
@ -138,7 +125,7 @@ class ArrayBuffer {
v8::Persistent<v8::Object> persistent = v8::Persistent<v8::Object> persistent =
v8::Persistent<v8::Object>::New(args.This()); v8::Persistent<v8::Object>::New(args.This());
persistent.MakeWeak(NULL, WeakCallback); persistent.MakeWeak(NULL, &ArrayBuffer::WeakCallback);
return args.This(); return args.This();
} }
@ -264,23 +251,12 @@ class TypedArray {
unsigned int length = 0; unsigned int length = 0;
unsigned int byte_offset = 0; unsigned int byte_offset = 0;
if (node::Buffer::HasInstance(args[0]) || // [m1k3] added support for Buffer constructor
ArrayBuffer::HasInstance(args[0])) { if (node::Buffer::HasInstance(args[0])
|| ArrayBuffer::HasInstance(args[0])) { // ArrayBuffer constructor.
buffer = v8::Local<v8::Object>::Cast(args[0]); buffer = v8::Local<v8::Object>::Cast(args[0]);
size_t buflen = buffer->GetIndexedPropertiesExternalArrayDataLength(); size_t buflen =
buffer->GetIndexedPropertiesExternalArrayDataLength();
// Try to short-circuit as early as possible. Assume that in most
// `new TypedArray(other_array)` calls, the old and the new array
// have the same type.
bool make_copy = HasInstance(buffer) ||
Int8Array::HasInstance(buffer) ||
Uint8Array::HasInstance(buffer) ||
Int16Array::HasInstance(buffer) ||
Uint16Array::HasInstance(buffer) ||
Int32Array::HasInstance(buffer) ||
Uint32Array::HasInstance(buffer) ||
Float32Array::HasInstance(buffer) ||
Float64Array::HasInstance(buffer);
if (!args[1]->IsUndefined() && args[1]->Int32Value() < 0) if (!args[1]->IsUndefined() && args[1]->Int32Value() < 0)
return ThrowRangeError("Byte offset out of range."); return ThrowRangeError("Byte offset out of range.");
@ -305,23 +281,6 @@ class TypedArray {
} }
void* buf = buffer->GetIndexedPropertiesExternalArrayData(); void* buf = buffer->GetIndexedPropertiesExternalArrayData();
if (make_copy) {
void* dst = malloc(length);
if (dst == NULL)
return ThrowError("Out of memory.");
v8::V8::AdjustAmountOfExternalAllocatedMemory(length);
memcpy(dst, static_cast<const char*>(buf) + byte_offset, length);
v8::Persistent<v8::Object> persistent =
v8::Persistent<v8::Object>::New(args.This());
persistent->SetIndexedPropertiesToExternalArrayData(dst,
TEAType,
length);
persistent.MakeWeak(NULL, WeakCallback);
}
else {
char* begin = reinterpret_cast<char*>(buf) + byte_offset; char* begin = reinterpret_cast<char*>(buf) + byte_offset;
if (!checkAlignment(reinterpret_cast<uintptr_t>(begin), TBytes)) if (!checkAlignment(reinterpret_cast<uintptr_t>(begin), TBytes))
@ -330,7 +289,6 @@ class TypedArray {
args.This()->SetIndexedPropertiesToExternalArrayData( args.This()->SetIndexedPropertiesToExternalArrayData(
begin, TEAType, length); begin, TEAType, length);
} }
}
else if (args[0]->IsObject()) { // TypedArray / type[] constructor. else if (args[0]->IsObject()) { // TypedArray / type[] constructor.
v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(args[0]); v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(args[0]);
length = obj->Get(v8::String::New("length"))->Uint32Value(); length = obj->Get(v8::String::New("length"))->Uint32Value();
@ -503,6 +461,16 @@ class TypedArray {
} }
}; };
class Int8Array : public TypedArray<1, v8::kExternalByteArray> { };
class Uint8Array : public TypedArray<1, v8::kExternalUnsignedByteArray> { };
class Uint8ClampedArray : public TypedArray<1, v8::kExternalPixelArray> { };
class Int16Array : public TypedArray<2, v8::kExternalShortArray> { };
class Uint16Array : public TypedArray<2, v8::kExternalUnsignedShortArray> { };
class Int32Array : public TypedArray<4, v8::kExternalIntArray> { };
class Uint32Array : public TypedArray<4, v8::kExternalUnsignedIntArray> { };
class Float32Array : public TypedArray<4, v8::kExternalFloatArray> { };
class Float64Array : public TypedArray<8, v8::kExternalDoubleArray> { };
template <typename T> template <typename T>
v8::Handle<v8::Value> cTypeToValue(T) { v8::Handle<v8::Value> cTypeToValue(T) {
return v8::Undefined(); return v8::Undefined();

33
test/simple/test-typed-arrays.js

@ -201,36 +201,3 @@ assert.throws(function() {
view.setUint16(0, 1); view.setUint16(0, 1);
assert.equal(view.getUint16(0), 1); assert.equal(view.getUint16(0), 1);
})(); })();
(function() {
// Backing store should not be shared.
var a = new Uint8Array(1);
var b = new Uint8Array(a);
a[0] = 0;
b[0] = 1;
assert.equal(a[0], 0);
assert.equal(b[0], 1);
})();
(function() {
// Backing store should not be shared.
var a = new Uint8Array(2);
var b = new Uint16Array(a);
a[0] = 0;
a[1] = 0;
b[0] = 257;
assert.equal(a[0], 0);
assert.equal(a[1], 0);
assert.equal(b[0], 257);
})();
(function() {
// Backing store should be shared.
var abuf = new ArrayBuffer(32);
var a = new Uint8Array(abuf);
var b = new Uint8Array(abuf);
a[0] = 0;
b[0] = 1;
assert.equal(a[0], 1);
assert.equal(b[0], 1);
})();

Loading…
Cancel
Save