Commit c1a19275 authored by dslomov@chromium.org's avatar dslomov@chromium.org

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
parent 266d2e63
...@@ -199,6 +199,8 @@ class Genesis BASE_EMBEDDED { ...@@ -199,6 +199,8 @@ class Genesis BASE_EMBEDDED {
const char* name, const char* name,
ElementsKind elements_kind); ElementsKind elements_kind);
bool InstallNatives(); bool InstallNatives();
void InstallTypedArray(const char* name);
bool InstallExperimentalNatives(); bool InstallExperimentalNatives();
void InstallBuiltinFunctionIds(); void InstallBuiltinFunctionIds();
void InstallJSFunctionResultCaches(); void InstallJSFunctionResultCaches();
...@@ -1258,6 +1260,14 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, ...@@ -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() { void Genesis::InitializeExperimentalGlobal() {
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object()); Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
...@@ -1298,6 +1308,17 @@ void Genesis::InitializeExperimentalGlobal() { ...@@ -1298,6 +1308,17 @@ void Genesis::InitializeExperimentalGlobal() {
isolate()->initial_object_prototype(), isolate()->initial_object_prototype(),
Builtins::kIllegal, true); 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) { if (FLAG_harmony_generators) {
......
...@@ -102,6 +102,9 @@ var kMessages = { ...@@ -102,6 +102,9 @@ var kMessages = {
// RangeError // RangeError
invalid_array_length: ["Invalid array length"], invalid_array_length: ["Invalid array length"],
invalid_array_buffer_length: ["Invalid array buffer 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"], stack_overflow: ["Maximum call stack size exceeded"],
invalid_time_value: ["Invalid time value"], invalid_time_value: ["Invalid time value"],
// SyntaxError // SyntaxError
......
...@@ -201,6 +201,9 @@ void HeapObject::HeapObjectVerify() { ...@@ -201,6 +201,9 @@ void HeapObject::HeapObjectVerify() {
case JS_ARRAY_BUFFER_TYPE: case JS_ARRAY_BUFFER_TYPE:
JSArrayBuffer::cast(this)->JSArrayBufferVerify(); JSArrayBuffer::cast(this)->JSArrayBufferVerify();
break; break;
case JS_TYPED_ARRAY_TYPE:
JSTypedArray::cast(this)->JSTypedArrayVerify();
break;
#define MAKE_STRUCT_CASE(NAME, Name, name) \ #define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \ case NAME##_TYPE: \
...@@ -738,6 +741,28 @@ void JSArrayBuffer::JSArrayBufferVerify() { ...@@ -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() { void Foreign::ForeignVerify() {
CHECK(IsForeign()); CHECK(IsForeign());
} }
......
...@@ -676,6 +676,7 @@ bool Object::IsBoolean() { ...@@ -676,6 +676,7 @@ bool Object::IsBoolean() {
TYPE_CHECKER(JSArray, JS_ARRAY_TYPE) TYPE_CHECKER(JSArray, JS_ARRAY_TYPE)
TYPE_CHECKER(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE) TYPE_CHECKER(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE)
TYPE_CHECKER(JSTypedArray, JS_TYPED_ARRAY_TYPE)
TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE) TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE)
...@@ -1605,6 +1606,8 @@ int JSObject::GetHeaderSize() { ...@@ -1605,6 +1606,8 @@ int JSObject::GetHeaderSize() {
return JSArray::kSize; return JSArray::kSize;
case JS_ARRAY_BUFFER_TYPE: case JS_ARRAY_BUFFER_TYPE:
return JSArrayBuffer::kSize; return JSArrayBuffer::kSize;
case JS_TYPED_ARRAY_TYPE:
return JSTypedArray::kSize;
case JS_SET_TYPE: case JS_SET_TYPE:
return JSSet::kSize; return JSSet::kSize;
case JS_MAP_TYPE: case JS_MAP_TYPE:
...@@ -2492,6 +2495,7 @@ CAST_ACCESSOR(JSBuiltinsObject) ...@@ -2492,6 +2495,7 @@ CAST_ACCESSOR(JSBuiltinsObject)
CAST_ACCESSOR(Code) CAST_ACCESSOR(Code)
CAST_ACCESSOR(JSArray) CAST_ACCESSOR(JSArray)
CAST_ACCESSOR(JSArrayBuffer) CAST_ACCESSOR(JSArrayBuffer)
CAST_ACCESSOR(JSTypedArray)
CAST_ACCESSOR(JSRegExp) CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(JSProxy) CAST_ACCESSOR(JSProxy)
CAST_ACCESSOR(JSFunctionProxy) CAST_ACCESSOR(JSFunctionProxy)
...@@ -5207,6 +5211,12 @@ void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) { ...@@ -5207,6 +5211,12 @@ void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) {
ACCESSORS(JSArrayBuffer, byte_length, Object, kByteLengthOffset) 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) ACCESSORS(JSRegExp, data, Object, kDataOffset)
......
...@@ -187,6 +187,8 @@ void HeapObject::HeapObjectPrint(FILE* out) { ...@@ -187,6 +187,8 @@ void HeapObject::HeapObjectPrint(FILE* out) {
break; break;
case JS_ARRAY_BUFFER_TYPE: case JS_ARRAY_BUFFER_TYPE:
JSArrayBuffer::cast(this)->JSArrayBufferPrint(out); JSArrayBuffer::cast(this)->JSArrayBufferPrint(out);
case JS_TYPED_ARRAY_TYPE:
JSTypedArray::cast(this)->JSTypedArrayPrint(out);
#define MAKE_STRUCT_CASE(NAME, Name, name) \ #define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \ case NAME##_TYPE: \
Name::cast(this)->Name##Print(out); \ Name::cast(this)->Name##Print(out); \
...@@ -809,6 +811,22 @@ void JSArrayBuffer::JSArrayBufferPrint(FILE* 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) { void JSFunction::JSFunctionPrint(FILE* out) {
HeapObject::PrintHeader(out, "Function"); HeapObject::PrintHeader(out, "Function");
PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map())); PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
......
...@@ -146,6 +146,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( ...@@ -146,6 +146,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case JS_BUILTINS_OBJECT_TYPE: case JS_BUILTINS_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE: case JS_MESSAGE_OBJECT_TYPE:
case JS_ARRAY_BUFFER_TYPE: case JS_ARRAY_BUFFER_TYPE:
case JS_TYPED_ARRAY_TYPE:
return GetVisitorIdForSize(kVisitJSObject, return GetVisitorIdForSize(kVisitJSObject,
kVisitJSObjectGeneric, kVisitJSObjectGeneric,
instance_size); instance_size);
......
...@@ -1556,6 +1556,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size, ...@@ -1556,6 +1556,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case JS_DATE_TYPE: case JS_DATE_TYPE:
case JS_ARRAY_TYPE: case JS_ARRAY_TYPE:
case JS_ARRAY_BUFFER_TYPE: case JS_ARRAY_BUFFER_TYPE:
case JS_TYPED_ARRAY_TYPE:
case JS_SET_TYPE: case JS_SET_TYPE:
case JS_MAP_TYPE: case JS_MAP_TYPE:
case JS_WEAK_MAP_TYPE: case JS_WEAK_MAP_TYPE:
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
// - JSObject // - JSObject
// - JSArray // - JSArray
// - JSArrayBuffer // - JSArrayBuffer
// - JSTypedArray
// - JSSet // - JSSet
// - JSMap // - JSMap
// - JSWeakMap // - JSWeakMap
...@@ -403,6 +404,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; ...@@ -403,6 +404,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
V(JS_GLOBAL_PROXY_TYPE) \ V(JS_GLOBAL_PROXY_TYPE) \
V(JS_ARRAY_TYPE) \ V(JS_ARRAY_TYPE) \
V(JS_ARRAY_BUFFER_TYPE) \ V(JS_ARRAY_BUFFER_TYPE) \
V(JS_TYPED_ARRAY_TYPE) \
V(JS_PROXY_TYPE) \ V(JS_PROXY_TYPE) \
V(JS_WEAK_MAP_TYPE) \ V(JS_WEAK_MAP_TYPE) \
V(JS_REGEXP_TYPE) \ V(JS_REGEXP_TYPE) \
...@@ -735,6 +737,7 @@ enum InstanceType { ...@@ -735,6 +737,7 @@ enum InstanceType {
JS_GLOBAL_PROXY_TYPE, JS_GLOBAL_PROXY_TYPE,
JS_ARRAY_TYPE, JS_ARRAY_TYPE,
JS_ARRAY_BUFFER_TYPE, JS_ARRAY_BUFFER_TYPE,
JS_TYPED_ARRAY_TYPE,
JS_SET_TYPE, JS_SET_TYPE,
JS_MAP_TYPE, JS_MAP_TYPE,
JS_WEAK_MAP_TYPE, JS_WEAK_MAP_TYPE,
...@@ -982,6 +985,7 @@ class MaybeObject BASE_EMBEDDED { ...@@ -982,6 +985,7 @@ class MaybeObject BASE_EMBEDDED {
V(Boolean) \ V(Boolean) \
V(JSArray) \ V(JSArray) \
V(JSArrayBuffer) \ V(JSArrayBuffer) \
V(JSTypedArray) \
V(JSProxy) \ V(JSProxy) \
V(JSFunctionProxy) \ V(JSFunctionProxy) \
V(JSSet) \ V(JSSet) \
...@@ -8559,6 +8563,38 @@ class JSArrayBuffer: public JSObject { ...@@ -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. // Foreign describes objects pointing from JavaScript to C structures.
// Since they cannot contain references to JS HeapObjects they can be // Since they cannot contain references to JS HeapObjects they can be
// placed in old_data_space. // placed in old_data_space.
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#include "string-search.h" #include "string-search.h"
#include "stub-cache.h" #include "stub-cache.h"
#include "uri.h" #include "uri.h"
#include "v8conversions.h"
#include "v8threads.h" #include "v8threads.h"
#include "vm-state-inl.h" #include "vm-state-inl.h"
...@@ -638,19 +639,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) { ...@@ -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, static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
Persistent<Value> object, Persistent<Value> object,
void* data) { void* data) {
...@@ -658,8 +646,8 @@ static void ArrayBufferWeakCallback(v8::Isolate* external_isolate, ...@@ -658,8 +646,8 @@ static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<Object> internal_object = Utils::OpenHandle(*object); Handle<Object> internal_object = Utils::OpenHandle(*object);
size_t allocated_length = ArrayBufferAllocatedLength( size_t allocated_length = NumberToSize(
isolate, JSArrayBuffer::cast(*internal_object)); isolate, JSArrayBuffer::cast(*internal_object)->byte_length());
isolate->heap()->AdjustAmountOfExternalAllocatedMemory( isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
-static_cast<intptr_t>(allocated_length)); -static_cast<intptr_t>(allocated_length));
if (data != NULL) if (data != NULL)
...@@ -744,12 +732,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) { ...@@ -744,12 +732,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
CONVERT_DOUBLE_ARG_CHECKED(first, 2); CONVERT_DOUBLE_ARG_CHECKED(first, 2);
size_t start = static_cast<size_t>(first); 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) if (target_length == 0)
return isolate->heap()->undefined_value(); 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* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store()); uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
CopyBytes(target_data, source_data + start, target_length); CopyBytes(target_data, source_data + start, target_length);
...@@ -757,6 +745,114 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) { ...@@ -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) { RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
......
...@@ -219,6 +219,7 @@ namespace internal { ...@@ -219,6 +219,7 @@ namespace internal {
F(NumberToExponential, 2, 1) \ F(NumberToExponential, 2, 1) \
F(NumberToPrecision, 2, 1) F(NumberToPrecision, 2, 1)
#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \ #define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
/* Reflection */ \ /* Reflection */ \
F(FunctionSetInstanceClassName, 2, 1) \ F(FunctionSetInstanceClassName, 2, 1) \
...@@ -350,6 +351,12 @@ namespace internal { ...@@ -350,6 +351,12 @@ namespace internal {
F(ArrayBufferGetByteLength, 1, 1)\ F(ArrayBufferGetByteLength, 1, 1)\
F(ArrayBufferSliceImpl, 3, 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 */ \ /* Statements */ \
F(NewClosure, 3, 1) \ F(NewClosure, 3, 1) \
F(NewObject, 1, 1) \ F(NewObject, 1, 1) \
......
...@@ -82,14 +82,74 @@ function ArrayBufferSlice(start, end) { ...@@ -82,14 +82,74 @@ function ArrayBufferSlice(start, end) {
return result; 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() { function SetUpArrayBuffer() {
%CheckIsBootstrapping(); %CheckIsBootstrapping();
// Set up the Uint16Array constructor function. // Set up the ArrayBuffer constructor function.
%SetCode($ArrayBuffer, ArrayBufferConstructor); %SetCode($ArrayBuffer, ArrayBufferConstructor);
%FunctionSetPrototype($ArrayBuffer, new $Object());
// Set up the constructor property on the ArrayBuffer prototype object. // Set up the constructor property on the ArrayBuffer prototype object.
%SetProperty($ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM); %SetProperty($ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM);
...@@ -102,3 +162,31 @@ function SetUpArrayBuffer() { ...@@ -102,3 +162,31 @@ function SetUpArrayBuffer() {
} }
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, ...@@ -55,6 +55,19 @@ double StringToDouble(UnicodeCache* unicode_cache,
// Converts a string into an integer. // Converts a string into an integer.
double StringToInt(UnicodeCache* unicode_cache, String* str, int radix); 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 } } // namespace v8::internal
#endif // V8_V8CONVERSIONS_H_ #endif // V8_V8CONVERSIONS_H_
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
// Flags: --harmony-typed-arrays // Flags: --harmony-typed-arrays
// ArrayBuffer
function TestByteLength(param, expectedByteLength) { function TestByteLength(param, expectedByteLength) {
var ab = new __ArrayBuffer(param); var ab = new __ArrayBuffer(param);
assertSame(expectedByteLength, ab.byteLength); assertSame(expectedByteLength, ab.byteLength);
...@@ -104,8 +106,98 @@ function TestArrayBufferSlice() { ...@@ -104,8 +106,98 @@ function TestArrayBufferSlice() {
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]] // Test property attribute [[Enumerable]]
function TestEnumerable(func) { function TestEnumerable(func, obj) {
function props(x) { function props(x) {
var array = []; var array = [];
for (var p in x) array.push(p); for (var p in x) array.push(p);
...@@ -113,9 +205,11 @@ function TestEnumerable(func) { ...@@ -113,9 +205,11 @@ function TestEnumerable(func) {
} }
assertArrayEquals([], props(func)); assertArrayEquals([], props(func));
assertArrayEquals([], props(func.prototype)); 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 // Test arbitrary properties on ArrayBuffer
...@@ -131,6 +225,5 @@ function TestArbitrary(m) { ...@@ -131,6 +225,5 @@ function TestArbitrary(m) {
} }
TestArbitrary(new __ArrayBuffer(256)); TestArbitrary(new __ArrayBuffer(256));
// Test direct constructor call // Test direct constructor call
assertTrue(__ArrayBuffer() instanceof __ArrayBuffer); assertTrue(__ArrayBuffer() instanceof __ArrayBuffer);
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