First cut at impementing ES6 TypedArrays in V8.
BUG= Review URL: https://codereview.chromium.org/13975012 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14285 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
266d2e6320
commit
c1a19275d3
@ -199,6 +199,8 @@ class Genesis BASE_EMBEDDED {
|
||||
const char* name,
|
||||
ElementsKind elements_kind);
|
||||
bool InstallNatives();
|
||||
|
||||
void InstallTypedArray(const char* name);
|
||||
bool InstallExperimentalNatives();
|
||||
void InstallBuiltinFunctionIds();
|
||||
void InstallJSFunctionResultCaches();
|
||||
@ -1258,6 +1260,14 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
}
|
||||
|
||||
|
||||
void Genesis::InstallTypedArray(const char* name) {
|
||||
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
|
||||
InstallFunction(global, name, JS_TYPED_ARRAY_TYPE,
|
||||
JSTypedArray::kSize, isolate()->initial_object_prototype(),
|
||||
Builtins::kIllegal, true);
|
||||
}
|
||||
|
||||
|
||||
void Genesis::InitializeExperimentalGlobal() {
|
||||
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
|
||||
|
||||
@ -1298,6 +1308,17 @@ void Genesis::InitializeExperimentalGlobal() {
|
||||
isolate()->initial_object_prototype(),
|
||||
Builtins::kIllegal, true);
|
||||
}
|
||||
{
|
||||
// -- T y p e d A r r a y s
|
||||
InstallTypedArray("__Int8Array");
|
||||
InstallTypedArray("__Uint8Array");
|
||||
InstallTypedArray("__Int16Array");
|
||||
InstallTypedArray("__Uint16Array");
|
||||
InstallTypedArray("__Int32Array");
|
||||
InstallTypedArray("__Uint32Array");
|
||||
InstallTypedArray("__Float32Array");
|
||||
InstallTypedArray("__Float64Array");
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_harmony_generators) {
|
||||
|
@ -102,6 +102,9 @@ var kMessages = {
|
||||
// RangeError
|
||||
invalid_array_length: ["Invalid array length"],
|
||||
invalid_array_buffer_length: ["Invalid array buffer length"],
|
||||
invalid_typed_array_offset: ["Start offset is too large"],
|
||||
invalid_typed_array_length: ["Length is too large"],
|
||||
invalid_typed_array_alignment: ["%0", "of", "%1", "should be a multiple of", "%3"],
|
||||
stack_overflow: ["Maximum call stack size exceeded"],
|
||||
invalid_time_value: ["Invalid time value"],
|
||||
// SyntaxError
|
||||
|
@ -201,6 +201,9 @@ void HeapObject::HeapObjectVerify() {
|
||||
case JS_ARRAY_BUFFER_TYPE:
|
||||
JSArrayBuffer::cast(this)->JSArrayBufferVerify();
|
||||
break;
|
||||
case JS_TYPED_ARRAY_TYPE:
|
||||
JSTypedArray::cast(this)->JSTypedArrayVerify();
|
||||
break;
|
||||
|
||||
#define MAKE_STRUCT_CASE(NAME, Name, name) \
|
||||
case NAME##_TYPE: \
|
||||
@ -738,6 +741,28 @@ void JSArrayBuffer::JSArrayBufferVerify() {
|
||||
}
|
||||
|
||||
|
||||
void JSTypedArray::JSTypedArrayVerify() {
|
||||
CHECK(IsJSTypedArray());
|
||||
JSObjectVerify();
|
||||
VerifyPointer(buffer());
|
||||
CHECK(buffer()->IsJSArrayBuffer() || buffer()->IsUndefined());
|
||||
|
||||
VerifyPointer(byte_offset());
|
||||
CHECK(byte_offset()->IsSmi() || byte_offset()->IsHeapNumber()
|
||||
|| byte_offset()->IsUndefined());
|
||||
|
||||
VerifyPointer(byte_length());
|
||||
CHECK(byte_length()->IsSmi() || byte_length()->IsHeapNumber()
|
||||
|| byte_length()->IsUndefined());
|
||||
|
||||
VerifyPointer(length());
|
||||
CHECK(length()->IsSmi() || length()->IsHeapNumber()
|
||||
|| length()->IsUndefined());
|
||||
|
||||
VerifyPointer(elements());
|
||||
}
|
||||
|
||||
|
||||
void Foreign::ForeignVerify() {
|
||||
CHECK(IsForeign());
|
||||
}
|
||||
|
@ -676,6 +676,7 @@ bool Object::IsBoolean() {
|
||||
|
||||
TYPE_CHECKER(JSArray, JS_ARRAY_TYPE)
|
||||
TYPE_CHECKER(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE)
|
||||
TYPE_CHECKER(JSTypedArray, JS_TYPED_ARRAY_TYPE)
|
||||
TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE)
|
||||
|
||||
|
||||
@ -1605,6 +1606,8 @@ int JSObject::GetHeaderSize() {
|
||||
return JSArray::kSize;
|
||||
case JS_ARRAY_BUFFER_TYPE:
|
||||
return JSArrayBuffer::kSize;
|
||||
case JS_TYPED_ARRAY_TYPE:
|
||||
return JSTypedArray::kSize;
|
||||
case JS_SET_TYPE:
|
||||
return JSSet::kSize;
|
||||
case JS_MAP_TYPE:
|
||||
@ -2492,6 +2495,7 @@ CAST_ACCESSOR(JSBuiltinsObject)
|
||||
CAST_ACCESSOR(Code)
|
||||
CAST_ACCESSOR(JSArray)
|
||||
CAST_ACCESSOR(JSArrayBuffer)
|
||||
CAST_ACCESSOR(JSTypedArray)
|
||||
CAST_ACCESSOR(JSRegExp)
|
||||
CAST_ACCESSOR(JSProxy)
|
||||
CAST_ACCESSOR(JSFunctionProxy)
|
||||
@ -5207,6 +5211,12 @@ void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) {
|
||||
ACCESSORS(JSArrayBuffer, byte_length, Object, kByteLengthOffset)
|
||||
|
||||
|
||||
ACCESSORS(JSTypedArray, buffer, Object, kBufferOffset)
|
||||
ACCESSORS(JSTypedArray, byte_offset, Object, kByteOffsetOffset)
|
||||
ACCESSORS(JSTypedArray, byte_length, Object, kByteLengthOffset)
|
||||
ACCESSORS(JSTypedArray, length, Object, kLengthOffset)
|
||||
|
||||
|
||||
ACCESSORS(JSRegExp, data, Object, kDataOffset)
|
||||
|
||||
|
||||
|
@ -187,6 +187,8 @@ void HeapObject::HeapObjectPrint(FILE* out) {
|
||||
break;
|
||||
case JS_ARRAY_BUFFER_TYPE:
|
||||
JSArrayBuffer::cast(this)->JSArrayBufferPrint(out);
|
||||
case JS_TYPED_ARRAY_TYPE:
|
||||
JSTypedArray::cast(this)->JSTypedArrayPrint(out);
|
||||
#define MAKE_STRUCT_CASE(NAME, Name, name) \
|
||||
case NAME##_TYPE: \
|
||||
Name::cast(this)->Name##Print(out); \
|
||||
@ -809,6 +811,22 @@ void JSArrayBuffer::JSArrayBufferPrint(FILE* out) {
|
||||
}
|
||||
|
||||
|
||||
void JSTypedArray::JSTypedArrayPrint(FILE* out) {
|
||||
HeapObject::PrintHeader(out, "JSTypedArray");
|
||||
PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
|
||||
PrintF(out, " - buffer =");
|
||||
buffer()->ShortPrint(out);
|
||||
PrintF(out, "\n - byte_offset = ");
|
||||
byte_offset()->ShortPrint(out);
|
||||
PrintF(out, "\n - byte_length = ");
|
||||
byte_length()->ShortPrint(out);
|
||||
PrintF(out, " - length = ");
|
||||
length()->ShortPrint(out);
|
||||
PrintF("\n");
|
||||
PrintElements(out);
|
||||
}
|
||||
|
||||
|
||||
void JSFunction::JSFunctionPrint(FILE* out) {
|
||||
HeapObject::PrintHeader(out, "Function");
|
||||
PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
|
||||
|
@ -146,6 +146,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
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);
|
||||
|
@ -1556,6 +1556,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
|
||||
case JS_DATE_TYPE:
|
||||
case JS_ARRAY_TYPE:
|
||||
case JS_ARRAY_BUFFER_TYPE:
|
||||
case JS_TYPED_ARRAY_TYPE:
|
||||
case JS_SET_TYPE:
|
||||
case JS_MAP_TYPE:
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
|
@ -57,6 +57,7 @@
|
||||
// - JSObject
|
||||
// - JSArray
|
||||
// - JSArrayBuffer
|
||||
// - JSTypedArray
|
||||
// - JSSet
|
||||
// - JSMap
|
||||
// - JSWeakMap
|
||||
@ -403,6 +404,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
|
||||
V(JS_GLOBAL_PROXY_TYPE) \
|
||||
V(JS_ARRAY_TYPE) \
|
||||
V(JS_ARRAY_BUFFER_TYPE) \
|
||||
V(JS_TYPED_ARRAY_TYPE) \
|
||||
V(JS_PROXY_TYPE) \
|
||||
V(JS_WEAK_MAP_TYPE) \
|
||||
V(JS_REGEXP_TYPE) \
|
||||
@ -735,6 +737,7 @@ enum InstanceType {
|
||||
JS_GLOBAL_PROXY_TYPE,
|
||||
JS_ARRAY_TYPE,
|
||||
JS_ARRAY_BUFFER_TYPE,
|
||||
JS_TYPED_ARRAY_TYPE,
|
||||
JS_SET_TYPE,
|
||||
JS_MAP_TYPE,
|
||||
JS_WEAK_MAP_TYPE,
|
||||
@ -982,6 +985,7 @@ class MaybeObject BASE_EMBEDDED {
|
||||
V(Boolean) \
|
||||
V(JSArray) \
|
||||
V(JSArrayBuffer) \
|
||||
V(JSTypedArray) \
|
||||
V(JSProxy) \
|
||||
V(JSFunctionProxy) \
|
||||
V(JSSet) \
|
||||
@ -8559,6 +8563,38 @@ class JSArrayBuffer: public JSObject {
|
||||
};
|
||||
|
||||
|
||||
class JSTypedArray: public JSObject {
|
||||
public:
|
||||
// [buffer]: ArrayBuffer that this typed array views.
|
||||
DECL_ACCESSORS(buffer, Object)
|
||||
|
||||
// [byte_length]: offset of typed array in bytes.
|
||||
DECL_ACCESSORS(byte_offset, Object)
|
||||
|
||||
// [byte_length]: length of typed array in bytes.
|
||||
DECL_ACCESSORS(byte_length, Object)
|
||||
|
||||
// [length]: length of typed array in elements.
|
||||
DECL_ACCESSORS(length, Object)
|
||||
|
||||
// Casting.
|
||||
static inline JSTypedArray* cast(Object* obj);
|
||||
|
||||
// Dispatched behavior.
|
||||
DECLARE_PRINTER(JSTypedArray)
|
||||
DECLARE_VERIFIER(JSTypedArray)
|
||||
|
||||
static const int kBufferOffset = JSObject::kHeaderSize;
|
||||
static const int kByteOffsetOffset = kBufferOffset + kPointerSize;
|
||||
static const int kByteLengthOffset = kByteOffsetOffset + kPointerSize;
|
||||
static const int kLengthOffset = kByteLengthOffset + kPointerSize;
|
||||
static const int kSize = kLengthOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray);
|
||||
};
|
||||
|
||||
|
||||
// Foreign describes objects pointing from JavaScript to C structures.
|
||||
// Since they cannot contain references to JS HeapObjects they can be
|
||||
// placed in old_data_space.
|
||||
|
130
src/runtime.cc
130
src/runtime.cc
@ -61,6 +61,7 @@
|
||||
#include "string-search.h"
|
||||
#include "stub-cache.h"
|
||||
#include "uri.h"
|
||||
#include "v8conversions.h"
|
||||
#include "v8threads.h"
|
||||
#include "vm-state-inl.h"
|
||||
|
||||
@ -638,19 +639,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
|
||||
}
|
||||
|
||||
|
||||
static size_t ArrayBufferAllocatedLength(Isolate* isolate,
|
||||
JSArrayBuffer* buffer) {
|
||||
NoHandleAllocation hc(isolate);
|
||||
Object* byte_length = buffer->byte_length();
|
||||
if (byte_length->IsSmi()) {
|
||||
return Smi::cast(byte_length)->value();
|
||||
} else {
|
||||
double value = HeapNumber::cast(byte_length)->value();
|
||||
return static_cast<size_t>(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
|
||||
Persistent<Value> object,
|
||||
void* data) {
|
||||
@ -658,8 +646,8 @@ static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
|
||||
HandleScope scope(isolate);
|
||||
Handle<Object> internal_object = Utils::OpenHandle(*object);
|
||||
|
||||
size_t allocated_length = ArrayBufferAllocatedLength(
|
||||
isolate, JSArrayBuffer::cast(*internal_object));
|
||||
size_t allocated_length = NumberToSize(
|
||||
isolate, JSArrayBuffer::cast(*internal_object)->byte_length());
|
||||
isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
|
||||
-static_cast<intptr_t>(allocated_length));
|
||||
if (data != NULL)
|
||||
@ -744,12 +732,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
|
||||
CONVERT_DOUBLE_ARG_CHECKED(first, 2);
|
||||
size_t start = static_cast<size_t>(first);
|
||||
size_t target_length = ArrayBufferAllocatedLength(isolate, *target);
|
||||
size_t target_length = NumberToSize(isolate, target->byte_length());
|
||||
|
||||
if (target_length == 0)
|
||||
return isolate->heap()->undefined_value();
|
||||
|
||||
ASSERT(ArrayBufferAllocatedLength(isolate, *source) - target_length >= start);
|
||||
ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start);
|
||||
uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
|
||||
uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
|
||||
CopyBytes(target_data, source_data + start, target_length);
|
||||
@ -757,6 +745,114 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
|
||||
}
|
||||
|
||||
|
||||
enum TypedArrayId {
|
||||
// arrayIds below should be synchromized with typedarray.js natives.
|
||||
ARRAY_ID_UINT8 = 1,
|
||||
ARRAY_ID_INT8 = 2,
|
||||
ARRAY_ID_UINT16 = 3,
|
||||
ARRAY_ID_INT16 = 4,
|
||||
ARRAY_ID_UINT32 = 5,
|
||||
ARRAY_ID_INT32 = 6,
|
||||
ARRAY_ID_FLOAT32 = 7,
|
||||
ARRAY_ID_FLOAT64 = 8
|
||||
};
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 5);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
|
||||
CONVERT_SMI_ARG_CHECKED(arrayId, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
|
||||
|
||||
ExternalArrayType arrayType;
|
||||
ElementsKind elementsKind;
|
||||
size_t elementSize;
|
||||
switch (arrayId) {
|
||||
case ARRAY_ID_UINT8:
|
||||
elementsKind = EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
|
||||
arrayType = kExternalUnsignedByteArray;
|
||||
elementSize = 1;
|
||||
break;
|
||||
case ARRAY_ID_INT8:
|
||||
elementsKind = EXTERNAL_BYTE_ELEMENTS;
|
||||
arrayType = kExternalByteArray;
|
||||
elementSize = 1;
|
||||
break;
|
||||
case ARRAY_ID_UINT16:
|
||||
elementsKind = EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
|
||||
arrayType = kExternalUnsignedShortArray;
|
||||
elementSize = 2;
|
||||
break;
|
||||
case ARRAY_ID_INT16:
|
||||
elementsKind = EXTERNAL_SHORT_ELEMENTS;
|
||||
arrayType = kExternalShortArray;
|
||||
elementSize = 2;
|
||||
break;
|
||||
case ARRAY_ID_UINT32:
|
||||
elementsKind = EXTERNAL_UNSIGNED_INT_ELEMENTS;
|
||||
arrayType = kExternalUnsignedIntArray;
|
||||
elementSize = 4;
|
||||
break;
|
||||
case ARRAY_ID_INT32:
|
||||
elementsKind = EXTERNAL_INT_ELEMENTS;
|
||||
arrayType = kExternalIntArray;
|
||||
elementSize = 4;
|
||||
break;
|
||||
case ARRAY_ID_FLOAT32:
|
||||
elementsKind = EXTERNAL_FLOAT_ELEMENTS;
|
||||
arrayType = kExternalFloatArray;
|
||||
elementSize = 4;
|
||||
break;
|
||||
case ARRAY_ID_FLOAT64:
|
||||
elementsKind = EXTERNAL_DOUBLE_ELEMENTS;
|
||||
arrayType = kExternalDoubleArray;
|
||||
elementSize = 8;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
holder->set_buffer(*buffer);
|
||||
holder->set_byte_offset(*byte_offset_object);
|
||||
holder->set_byte_length(*byte_length_object);
|
||||
|
||||
size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
|
||||
size_t byte_length = NumberToSize(isolate, *byte_length_object);
|
||||
ASSERT(byte_length % elementSize == 0);
|
||||
size_t length = byte_length / elementSize;
|
||||
|
||||
holder->set_length(
|
||||
*isolate->factory()->NewNumber(static_cast<double>(length)));
|
||||
Handle<ExternalArray> elements =
|
||||
isolate->factory()->NewExternalArray(
|
||||
length, arrayType,
|
||||
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
|
||||
Handle<Map> map =
|
||||
isolate->factory()->GetElementsTransitionMap(holder, elementsKind);
|
||||
holder->set_map(*map);
|
||||
holder->set_elements(*elements);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
#define TYPED_ARRAY_GETTER(getter, accessor) \
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
|
||||
HandleScope scope(isolate); \
|
||||
ASSERT(args.length() == 1); \
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); \
|
||||
return holder->accessor(); \
|
||||
}
|
||||
|
||||
TYPED_ARRAY_GETTER(Buffer, buffer)
|
||||
TYPED_ARRAY_GETTER(ByteLength, byte_length)
|
||||
TYPED_ARRAY_GETTER(ByteOffset, byte_offset)
|
||||
TYPED_ARRAY_GETTER(Length, length)
|
||||
|
||||
#undef TYPED_ARRAY_GETTER
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 1);
|
||||
|
@ -219,6 +219,7 @@ namespace internal {
|
||||
F(NumberToExponential, 2, 1) \
|
||||
F(NumberToPrecision, 2, 1)
|
||||
|
||||
|
||||
#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
|
||||
/* Reflection */ \
|
||||
F(FunctionSetInstanceClassName, 2, 1) \
|
||||
@ -350,6 +351,12 @@ namespace internal {
|
||||
F(ArrayBufferGetByteLength, 1, 1)\
|
||||
F(ArrayBufferSliceImpl, 3, 1) \
|
||||
\
|
||||
F(TypedArrayInitialize, 5, 1) \
|
||||
F(TypedArrayGetBuffer, 1, 1) \
|
||||
F(TypedArrayGetByteLength, 1, 1) \
|
||||
F(TypedArrayGetByteOffset, 1, 1) \
|
||||
F(TypedArrayGetLength, 1, 1) \
|
||||
\
|
||||
/* Statements */ \
|
||||
F(NewClosure, 3, 1) \
|
||||
F(NewObject, 1, 1) \
|
||||
|
@ -82,14 +82,74 @@ function ArrayBufferSlice(start, end) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------- Typed Arrays ---------------------
|
||||
|
||||
function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
|
||||
return function (buffer, byteOffset, length) {
|
||||
if (%_IsConstructCall()) {
|
||||
if (!IS_ARRAYBUFFER(buffer)) {
|
||||
throw MakeTypeError("Type error!");
|
||||
}
|
||||
var offset = IS_UNDEFINED(byteOffset)
|
||||
? 0 : offset = TO_POSITIVE_INTEGER(byteOffset);
|
||||
|
||||
if (offset % elementSize !== 0) {
|
||||
throw MakeRangeError("invalid_typed_array_alignment",
|
||||
"start offset", name, elementSize);
|
||||
}
|
||||
var bufferByteLength = %ArrayBufferGetByteLength(buffer);
|
||||
if (offset >= bufferByteLength) {
|
||||
throw MakeRangeError("invalid_typed_array_offset");
|
||||
}
|
||||
|
||||
var newByteLength;
|
||||
var newLength;
|
||||
if (IS_UNDEFINED(length)) {
|
||||
if (bufferByteLength % elementSize !== 0) {
|
||||
throw MakeRangeError("invalid_typed_array_alignment",
|
||||
"byte length", name, elementSize);
|
||||
}
|
||||
newByteLength = bufferByteLength - offset;
|
||||
newLength = newByteLength / elementSize;
|
||||
} else {
|
||||
var newLength = TO_POSITIVE_INTEGER(length);
|
||||
newByteLength = newLength * elementSize;
|
||||
}
|
||||
if (newByteLength > bufferByteLength) {
|
||||
throw MakeRangeError("invalid_typed_array_length");
|
||||
}
|
||||
%TypedArrayInitialize(this, arrayId, buffer, offset, newByteLength);
|
||||
} else {
|
||||
return new constructor(buffer, byteOffset, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function TypedArrayGetBuffer() {
|
||||
return %TypedArrayGetBuffer(this);
|
||||
}
|
||||
|
||||
function TypedArrayGetByteLength() {
|
||||
return %TypedArrayGetByteLength(this);
|
||||
}
|
||||
|
||||
function TypedArrayGetByteOffset() {
|
||||
return %TypedArrayGetByteOffset(this);
|
||||
}
|
||||
|
||||
function TypedArrayGetLength() {
|
||||
return %TypedArrayGetLength(this);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
function SetUpArrayBuffer() {
|
||||
%CheckIsBootstrapping();
|
||||
|
||||
// Set up the Uint16Array constructor function.
|
||||
// Set up the ArrayBuffer constructor function.
|
||||
%SetCode($ArrayBuffer, ArrayBufferConstructor);
|
||||
%FunctionSetPrototype($ArrayBuffer, new $Object());
|
||||
|
||||
// Set up the constructor property on the ArrayBuffer prototype object.
|
||||
%SetProperty($ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM);
|
||||
@ -102,3 +162,31 @@ function SetUpArrayBuffer() {
|
||||
}
|
||||
|
||||
SetUpArrayBuffer();
|
||||
|
||||
function SetupTypedArray(arrayId, name, constructor, elementSize) {
|
||||
var f = CreateTypedArrayConstructor(name, elementSize,
|
||||
arrayId, constructor);
|
||||
%SetCode(constructor, f);
|
||||
%FunctionSetPrototype(constructor, new $Object());
|
||||
|
||||
%SetProperty(constructor.prototype,
|
||||
"constructor", constructor, DONT_ENUM);
|
||||
%SetProperty(constructor.prototype,
|
||||
"BYTES_PER_ELEMENT", elementSize,
|
||||
READ_ONLY | DONT_ENUM | DONT_DELETE);
|
||||
InstallGetter(constructor.prototype, "buffer", TypedArrayGetBuffer);
|
||||
InstallGetter(constructor.prototype, "byteOffset", TypedArrayGetByteOffset);
|
||||
InstallGetter(constructor.prototype, "byteLength", TypedArrayGetByteLength);
|
||||
InstallGetter(constructor.prototype, "length", TypedArrayGetLength);
|
||||
}
|
||||
|
||||
// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
|
||||
SetupTypedArray(1, "Uint8Array", global.__Uint8Array, 1);
|
||||
SetupTypedArray(2, "Int8Array", global.__Int8Array, 1);
|
||||
SetupTypedArray(3, "Uint16Array", global.__Uint16Array, 2);
|
||||
SetupTypedArray(4, "Int16Array", global.__Int16Array, 2);
|
||||
SetupTypedArray(5, "Uint32Array", global.__Uint32Array, 4);
|
||||
SetupTypedArray(6, "Int32Array", global.__Int32Array, 4);
|
||||
SetupTypedArray(7, "Float32Array", global.__Float32Array, 4);
|
||||
SetupTypedArray(8, "Float64Array", global.__Float64Array, 8);
|
||||
|
||||
|
@ -55,6 +55,19 @@ double StringToDouble(UnicodeCache* unicode_cache,
|
||||
// Converts a string into an integer.
|
||||
double StringToInt(UnicodeCache* unicode_cache, String* str, int radix);
|
||||
|
||||
// Converts a number into size_t.
|
||||
inline size_t NumberToSize(Isolate* isolate,
|
||||
Object* number) {
|
||||
NoHandleAllocation hc(isolate);
|
||||
if (number->IsSmi()) {
|
||||
return Smi::cast(number)->value();
|
||||
} else {
|
||||
ASSERT(number->IsHeapNumber());
|
||||
double value = HeapNumber::cast(number)->value();
|
||||
return static_cast<size_t>(value);
|
||||
}
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_V8CONVERSIONS_H_
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
// Flags: --harmony-typed-arrays
|
||||
|
||||
// ArrayBuffer
|
||||
|
||||
function TestByteLength(param, expectedByteLength) {
|
||||
var ab = new __ArrayBuffer(param);
|
||||
assertSame(expectedByteLength, ab.byteLength);
|
||||
@ -104,8 +106,98 @@ function TestArrayBufferSlice() {
|
||||
|
||||
TestArrayBufferSlice();
|
||||
|
||||
// Typed arrays
|
||||
|
||||
function TestTypedArray(proto, elementSize, typicalElement) {
|
||||
var ab = new __ArrayBuffer(256*elementSize);
|
||||
|
||||
var a1 = new proto(ab, 128*elementSize, 128);
|
||||
assertSame(ab, a1.buffer);
|
||||
assertSame(elementSize, a1.BYTES_PER_ELEMENT);
|
||||
assertSame(128, a1.length);
|
||||
assertSame(128*elementSize, a1.byteLength);
|
||||
assertSame(128*elementSize, a1.byteOffset);
|
||||
|
||||
|
||||
var a2 = new proto(ab, 64*elementSize, 128);
|
||||
assertSame(ab, a2.buffer);
|
||||
assertSame(elementSize, a2.BYTES_PER_ELEMENT);
|
||||
assertSame(128, a2.length);
|
||||
assertSame(128*elementSize, a2.byteLength);
|
||||
assertSame(64*elementSize, a2.byteOffset);
|
||||
|
||||
var a3 = new proto(ab, 192*elementSize);
|
||||
assertSame(ab, a3.buffer);
|
||||
assertSame(64, a3.length);
|
||||
assertSame(64*elementSize, a3.byteLength);
|
||||
assertSame(192*elementSize, a3.byteOffset);
|
||||
|
||||
var a4 = new proto(ab);
|
||||
assertSame(ab, a4.buffer);
|
||||
assertSame(256, a4.length);
|
||||
assertSame(256*elementSize, a4.byteLength);
|
||||
assertSame(0, a4.byteOffset);
|
||||
|
||||
|
||||
var i;
|
||||
for (i = 0; i < 128; i++) {
|
||||
a1[i] = typicalElement;
|
||||
}
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
assertSame(typicalElement, a1[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
assertSame(0, a2[i]);
|
||||
}
|
||||
|
||||
for (i = 64; i < 128; i++) {
|
||||
assertSame(typicalElement, a2[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
assertSame(typicalElement, a3[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
assertSame(0, a4[i]);
|
||||
}
|
||||
|
||||
for (i = 128; i < 256; i++) {
|
||||
assertSame(typicalElement, a4[i]);
|
||||
}
|
||||
|
||||
assertThrows(function () { new proto(ab, 256*elementSize); }, RangeError);
|
||||
|
||||
if (elementSize !== 1) {
|
||||
assertThrows(function() { new proto(ab, 128*elementSize - 1, 10); },
|
||||
RangeError);
|
||||
var unalignedArrayBuffer = new __ArrayBuffer(10*elementSize + 1);
|
||||
var goodArray = new proto(unalignedArrayBuffer, 0, 10);
|
||||
assertSame(10, goodArray.length);
|
||||
assertSame(10*elementSize, goodArray.byteLength);
|
||||
assertThrows(function() { new proto(unalignedArrayBuffer)}, RangeError);
|
||||
assertThrows(function() { new proto(unalignedArrayBuffer, 5*elementSize)},
|
||||
RangeError);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TestTypedArray(__Uint8Array, 1, 0xFF);
|
||||
TestTypedArray(__Int8Array, 1, -0x7F);
|
||||
TestTypedArray(__Uint16Array, 2, 0xFFFF);
|
||||
TestTypedArray(__Int16Array, 2, -0x7FFF);
|
||||
TestTypedArray(__Uint32Array, 4, 0xFFFFFFFF);
|
||||
TestTypedArray(__Int32Array, 4, -0x7FFFFFFF);
|
||||
TestTypedArray(__Float32Array, 4, 0.5);
|
||||
TestTypedArray(__Float64Array, 8, 0.5);
|
||||
|
||||
|
||||
// General tests for properties
|
||||
|
||||
// Test property attribute [[Enumerable]]
|
||||
function TestEnumerable(func) {
|
||||
function TestEnumerable(func, obj) {
|
||||
function props(x) {
|
||||
var array = [];
|
||||
for (var p in x) array.push(p);
|
||||
@ -113,9 +205,11 @@ function TestEnumerable(func) {
|
||||
}
|
||||
assertArrayEquals([], props(func));
|
||||
assertArrayEquals([], props(func.prototype));
|
||||
assertArrayEquals([], props(new func()));
|
||||
if (obj)
|
||||
assertArrayEquals([], props(obj));
|
||||
}
|
||||
TestEnumerable(__ArrayBuffer);
|
||||
TestEnumerable(__ArrayBuffer, new __ArrayBuffer());
|
||||
TestEnumerable(__Uint8Array);
|
||||
|
||||
|
||||
// Test arbitrary properties on ArrayBuffer
|
||||
@ -131,6 +225,5 @@ function TestArbitrary(m) {
|
||||
}
|
||||
TestArbitrary(new __ArrayBuffer(256));
|
||||
|
||||
|
||||
// Test direct constructor call
|
||||
assertTrue(__ArrayBuffer() instanceof __ArrayBuffer);
|
||||
|
Loading…
Reference in New Issue
Block a user