This implements allocating small typed arrays in heap.
R=mvstanton@chromium.org, verwaest@chromium.org Review URL: https://codereview.chromium.org/150813004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20279 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
6130206c2f
commit
76b8f25edb
@ -5571,7 +5571,7 @@ class Internals {
|
||||
static const int kNullValueRootIndex = 7;
|
||||
static const int kTrueValueRootIndex = 8;
|
||||
static const int kFalseValueRootIndex = 9;
|
||||
static const int kEmptyStringRootIndex = 145;
|
||||
static const int kEmptyStringRootIndex = 154;
|
||||
|
||||
static const int kNodeClassIdOffset = 1 * kApiPointerSize;
|
||||
static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
|
||||
|
@ -119,9 +119,7 @@ bool Accessors::IsJSObjectFieldAccessor(typename T::TypeHandle type,
|
||||
CheckForName(name, isolate->heap()->byte_length_string(),
|
||||
JSTypedArray::kByteLengthOffset, object_offset) ||
|
||||
CheckForName(name, isolate->heap()->byte_offset_string(),
|
||||
JSTypedArray::kByteOffsetOffset, object_offset) ||
|
||||
CheckForName(name, isolate->heap()->buffer_string(),
|
||||
JSTypedArray::kBufferOffset, object_offset);
|
||||
JSTypedArray::kByteOffsetOffset, object_offset);
|
||||
case JS_ARRAY_BUFFER_TYPE:
|
||||
return
|
||||
CheckForName(name, isolate->heap()->byte_length_string(),
|
||||
@ -131,9 +129,7 @@ bool Accessors::IsJSObjectFieldAccessor(typename T::TypeHandle type,
|
||||
CheckForName(name, isolate->heap()->byte_length_string(),
|
||||
JSDataView::kByteLengthOffset, object_offset) ||
|
||||
CheckForName(name, isolate->heap()->byte_offset_string(),
|
||||
JSDataView::kByteOffsetOffset, object_offset) ||
|
||||
CheckForName(name, isolate->heap()->buffer_string(),
|
||||
JSDataView::kBufferOffset, object_offset);
|
||||
JSDataView::kByteOffsetOffset, object_offset);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
15
src/api.cc
15
src/api.cc
@ -6018,8 +6018,15 @@ Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, void* data,
|
||||
|
||||
Local<ArrayBuffer> v8::ArrayBufferView::Buffer() {
|
||||
i::Handle<i::JSArrayBufferView> obj = Utils::OpenHandle(this);
|
||||
ASSERT(obj->buffer()->IsJSArrayBuffer());
|
||||
i::Handle<i::JSArrayBuffer> buffer(i::JSArrayBuffer::cast(obj->buffer()));
|
||||
i::Handle<i::JSArrayBuffer> buffer;
|
||||
if (obj->IsJSDataView()) {
|
||||
i::Handle<i::JSDataView> data_view(i::JSDataView::cast(*obj));
|
||||
ASSERT(data_view->buffer()->IsJSArrayBuffer());
|
||||
buffer = i::handle(i::JSArrayBuffer::cast(data_view->buffer()));
|
||||
} else {
|
||||
ASSERT(obj->IsJSTypedArray());
|
||||
buffer = i::JSTypedArray::cast(*obj)->GetBuffer();
|
||||
}
|
||||
return Utils::ToLocal(buffer);
|
||||
}
|
||||
|
||||
@ -6090,7 +6097,9 @@ i::Handle<i::JSTypedArray> NewTypedArray(
|
||||
isolate->factory()->NewExternalArray(
|
||||
static_cast<int>(length), array_type,
|
||||
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
|
||||
obj->set_elements(*elements);
|
||||
i::Handle<i::Map> map =
|
||||
i::JSObject::GetElementsTransitionMap(obj, elements_kind);
|
||||
obj->set_map_and_elements(*map, *elements);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -1099,7 +1099,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
#define INSTALL_TYPED_ARRAY(Type, type, TYPE, ctype, size) \
|
||||
{ \
|
||||
Handle<JSFunction> fun = InstallTypedArray(#Type "Array", \
|
||||
EXTERNAL_##TYPE##_ELEMENTS); \
|
||||
TYPE##_ELEMENTS); \
|
||||
native_context()->set_##type##_array_fun(*fun); \
|
||||
}
|
||||
TYPED_ARRAYS(INSTALL_TYPED_ARRAY)
|
||||
|
@ -142,14 +142,27 @@ int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind) {
|
||||
}
|
||||
|
||||
|
||||
ElementsKind GetNextTransitionElementsKind(ElementsKind kind) {
|
||||
switch (kind) {
|
||||
#define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
||||
case TYPE##_ELEMENTS: return EXTERNAL_##TYPE##_ELEMENTS;
|
||||
|
||||
TYPED_ARRAYS(FIXED_TYPED_ARRAY_CASE)
|
||||
#undef FIXED_TYPED_ARRAY_CASE
|
||||
default: {
|
||||
int index = GetSequenceIndexFromFastElementsKind(kind);
|
||||
return GetFastElementsKindFromSequenceIndex(index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ElementsKind GetNextMoreGeneralFastElementsKind(ElementsKind elements_kind,
|
||||
bool allow_only_packed) {
|
||||
ASSERT(IsFastElementsKind(elements_kind));
|
||||
ASSERT(elements_kind != TERMINAL_FAST_ELEMENTS_KIND);
|
||||
while (true) {
|
||||
int index =
|
||||
GetSequenceIndexFromFastElementsKind(elements_kind) + 1;
|
||||
elements_kind = GetFastElementsKindFromSequenceIndex(index);
|
||||
elements_kind = GetNextTransitionElementsKind(elements_kind);
|
||||
if (!IsFastHoleyElementsKind(elements_kind) || !allow_only_packed) {
|
||||
return elements_kind;
|
||||
}
|
||||
|
@ -100,10 +100,10 @@ void PrintElementsKind(FILE* out, ElementsKind kind);
|
||||
|
||||
ElementsKind GetInitialFastElementsKind();
|
||||
|
||||
ElementsKind GetFastElementsKindFromSequenceIndex(int sequence_index);
|
||||
|
||||
ElementsKind GetFastElementsKindFromSequenceIndex(int sequence_number);
|
||||
int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind);
|
||||
|
||||
ElementsKind GetNextTransitionElementsKind(ElementsKind elements_kind);
|
||||
|
||||
inline bool IsDictionaryElementsKind(ElementsKind kind) {
|
||||
return kind == DICTIONARY_ELEMENTS;
|
||||
@ -116,6 +116,12 @@ inline bool IsExternalArrayElementsKind(ElementsKind kind) {
|
||||
}
|
||||
|
||||
|
||||
inline bool IsTerminalElementsKind(ElementsKind kind) {
|
||||
return kind == TERMINAL_FAST_ELEMENTS_KIND ||
|
||||
IsExternalArrayElementsKind(kind);
|
||||
}
|
||||
|
||||
|
||||
inline bool IsFixedTypedArrayElementsKind(ElementsKind kind) {
|
||||
return kind >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND &&
|
||||
kind <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND;
|
||||
@ -128,6 +134,11 @@ inline bool IsFastElementsKind(ElementsKind kind) {
|
||||
}
|
||||
|
||||
|
||||
inline bool IsTransitionElementsKind(ElementsKind kind) {
|
||||
return IsFastElementsKind(kind) || IsFixedTypedArrayElementsKind(kind);
|
||||
}
|
||||
|
||||
|
||||
inline bool IsFastDoubleElementsKind(ElementsKind kind) {
|
||||
return kind == FAST_DOUBLE_ELEMENTS ||
|
||||
kind == FAST_HOLEY_DOUBLE_ELEMENTS;
|
||||
|
@ -357,6 +357,9 @@ DEFINE_bool(omit_map_checks_for_leaf_maps, true,
|
||||
"do not emit check maps for constant values that have a leaf map, "
|
||||
"deoptimize the optimized code if the layout of the maps changes.")
|
||||
|
||||
DEFINE_int(typed_array_max_size_in_heap, 64,
|
||||
"threshold for in-heap typed array")
|
||||
|
||||
// Profiler flags.
|
||||
DEFINE_int(frame_count, 1, "number of stack frames inspected by the profiler")
|
||||
// 0x1800 fits in the immediate field of an ARM instruction.
|
||||
|
41
src/heap.cc
41
src/heap.cc
@ -2934,6 +2934,16 @@ bool Heap::CreateInitialMaps() {
|
||||
|
||||
TYPED_ARRAYS(ALLOCATE_EMPTY_EXTERNAL_ARRAY)
|
||||
#undef ALLOCATE_EMPTY_EXTERNAL_ARRAY
|
||||
|
||||
#define ALLOCATE_EMPTY_FIXED_TYPED_ARRAY(Type, type, TYPE, ctype, size) \
|
||||
{ FixedTypedArrayBase* obj; \
|
||||
if (!AllocateEmptyFixedTypedArray(kExternal##Type##Array)->To(&obj)) \
|
||||
return false; \
|
||||
set_empty_fixed_##type##_array(obj); \
|
||||
}
|
||||
|
||||
TYPED_ARRAYS(ALLOCATE_EMPTY_FIXED_TYPED_ARRAY)
|
||||
#undef ALLOCATE_EMPTY_FIXED_TYPED_ARRAY
|
||||
}
|
||||
ASSERT(!InNewSpace(empty_fixed_array()));
|
||||
return true;
|
||||
@ -3762,12 +3772,34 @@ Heap::RootListIndex Heap::RootIndexForEmptyExternalArray(
|
||||
}
|
||||
|
||||
|
||||
Heap::RootListIndex Heap::RootIndexForEmptyFixedTypedArray(
|
||||
ElementsKind elementsKind) {
|
||||
switch (elementsKind) {
|
||||
#define ELEMENT_KIND_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \
|
||||
case TYPE##_ELEMENTS: \
|
||||
return kEmptyFixed##Type##ArrayRootIndex;
|
||||
|
||||
TYPED_ARRAYS(ELEMENT_KIND_TO_ROOT_INDEX)
|
||||
#undef ELEMENT_KIND_TO_ROOT_INDEX
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return kUndefinedValueRootIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ExternalArray* Heap::EmptyExternalArrayForMap(Map* map) {
|
||||
return ExternalArray::cast(
|
||||
roots_[RootIndexForEmptyExternalArray(map->elements_kind())]);
|
||||
}
|
||||
|
||||
|
||||
FixedTypedArrayBase* Heap::EmptyFixedTypedArrayForMap(Map* map) {
|
||||
return FixedTypedArrayBase::cast(
|
||||
roots_[RootIndexForEmptyFixedTypedArray(map->elements_kind())]);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
|
||||
// We need to distinguish the minus zero value and this cannot be
|
||||
// done after conversion to int. Doing this by comparing bit
|
||||
@ -4063,6 +4095,7 @@ MaybeObject* Heap::AllocateFixedTypedArray(int length,
|
||||
reinterpret_cast<FixedTypedArrayBase*>(object);
|
||||
elements->set_map(MapForFixedTypedArray(array_type));
|
||||
elements->set_length(length);
|
||||
memset(elements->DataPtr(), 0, elements->DataSize());
|
||||
return elements;
|
||||
}
|
||||
|
||||
@ -4471,7 +4504,8 @@ MaybeObject* Heap::AllocateJSObjectFromMap(
|
||||
// Initialize the JSObject.
|
||||
InitializeJSObjectFromMap(JSObject::cast(obj), properties, map);
|
||||
ASSERT(JSObject::cast(obj)->HasFastElements() ||
|
||||
JSObject::cast(obj)->HasExternalArrayElements());
|
||||
JSObject::cast(obj)->HasExternalArrayElements() ||
|
||||
JSObject::cast(obj)->HasFixedTypedArrayElements());
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -5139,6 +5173,11 @@ MaybeObject* Heap::CopyAndTenureFixedCOWArray(FixedArray* src) {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Heap::AllocateEmptyFixedTypedArray(ExternalArrayType array_type) {
|
||||
return AllocateFixedTypedArray(0, array_type, TENURED);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) {
|
||||
int len = src->length();
|
||||
Object* obj;
|
||||
|
16
src/heap.h
16
src/heap.h
@ -164,6 +164,16 @@ namespace internal {
|
||||
V(Map, fixed_float32_array_map, FixedFloat32ArrayMap) \
|
||||
V(Map, fixed_float64_array_map, FixedFloat64ArrayMap) \
|
||||
V(Map, fixed_uint8_clamped_array_map, FixedUint8ClampedArrayMap) \
|
||||
V(FixedTypedArrayBase, empty_fixed_uint8_array, EmptyFixedUint8Array) \
|
||||
V(FixedTypedArrayBase, empty_fixed_int8_array, EmptyFixedInt8Array) \
|
||||
V(FixedTypedArrayBase, empty_fixed_uint16_array, EmptyFixedUint16Array) \
|
||||
V(FixedTypedArrayBase, empty_fixed_int16_array, EmptyFixedInt16Array) \
|
||||
V(FixedTypedArrayBase, empty_fixed_uint32_array, EmptyFixedUint32Array) \
|
||||
V(FixedTypedArrayBase, empty_fixed_int32_array, EmptyFixedInt32Array) \
|
||||
V(FixedTypedArrayBase, empty_fixed_float32_array, EmptyFixedFloat32Array) \
|
||||
V(FixedTypedArrayBase, empty_fixed_float64_array, EmptyFixedFloat64Array) \
|
||||
V(FixedTypedArrayBase, empty_fixed_uint8_clamped_array, \
|
||||
EmptyFixedUint8ClampedArray) \
|
||||
V(Map, sloppy_arguments_elements_map, SloppyArgumentsElementsMap) \
|
||||
V(Map, function_context_map, FunctionContextMap) \
|
||||
V(Map, catch_context_map, CatchContextMap) \
|
||||
@ -1655,7 +1665,9 @@ class Heap {
|
||||
ExternalArrayType array_type);
|
||||
|
||||
RootListIndex RootIndexForEmptyExternalArray(ElementsKind kind);
|
||||
RootListIndex RootIndexForEmptyFixedTypedArray(ElementsKind kind);
|
||||
ExternalArray* EmptyExternalArrayForMap(Map* map);
|
||||
FixedTypedArrayBase* EmptyFixedTypedArrayForMap(Map* map);
|
||||
|
||||
void RecordStats(HeapStats* stats, bool take_snapshot = false);
|
||||
|
||||
@ -2221,6 +2233,10 @@ class Heap {
|
||||
MUST_USE_RESULT MaybeObject* AllocateEmptyExternalArray(
|
||||
ExternalArrayType array_type);
|
||||
|
||||
// Allocate empty fixed typed array of given type.
|
||||
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedTypedArray(
|
||||
ExternalArrayType array_type);
|
||||
|
||||
// Allocate empty fixed double array.
|
||||
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedDoubleArray();
|
||||
|
||||
|
244
src/hydrogen.cc
244
src/hydrogen.cc
@ -1904,6 +1904,19 @@ void HGraphBuilder::BuildCopySeqStringChars(HValue* src,
|
||||
}
|
||||
|
||||
|
||||
HValue* HGraphBuilder::BuildObjectSizeAlignment(
|
||||
HValue* unaligned_size, int header_size) {
|
||||
ASSERT((header_size & kObjectAlignmentMask) == 0);
|
||||
HValue* size = AddUncasted<HAdd>(
|
||||
unaligned_size, Add<HConstant>(static_cast<int32_t>(
|
||||
header_size + kObjectAlignmentMask)));
|
||||
size->ClearFlag(HValue::kCanOverflow);
|
||||
return AddUncasted<HBitwise>(
|
||||
Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
|
||||
~kObjectAlignmentMask)));
|
||||
}
|
||||
|
||||
|
||||
HValue* HGraphBuilder::BuildUncheckedStringAdd(
|
||||
HValue* left,
|
||||
HValue* right,
|
||||
@ -2004,13 +2017,7 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd(
|
||||
// Calculate the number of bytes needed for the characters in the
|
||||
// string while observing object alignment.
|
||||
STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
|
||||
HValue* size = Pop();
|
||||
size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>(
|
||||
SeqString::kHeaderSize + kObjectAlignmentMask)));
|
||||
size->ClearFlag(HValue::kCanOverflow);
|
||||
size = AddUncasted<HBitwise>(
|
||||
Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
|
||||
~kObjectAlignmentMask)));
|
||||
HValue* size = BuildObjectSizeAlignment(Pop(), SeqString::kHeaderSize);
|
||||
|
||||
// Allocate the string object. HAllocate does not care whether we pass
|
||||
// STRING_TYPE or ASCII_STRING_TYPE here, so we just use STRING_TYPE here.
|
||||
@ -6470,7 +6477,8 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
||||
access = AddInstruction(BuildKeyedGeneric(access_type, object, key, val));
|
||||
} else {
|
||||
ASSERT(IsFastElementsKind(elements_kind) ||
|
||||
IsExternalArrayElementsKind(elements_kind));
|
||||
IsExternalArrayElementsKind(elements_kind) ||
|
||||
IsFixedTypedArrayElementsKind(elements_kind));
|
||||
LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
|
||||
// Happily, mapcompare is a checked object.
|
||||
access = BuildUncheckedMonomorphicElementAccess(
|
||||
@ -8421,9 +8429,6 @@ void HGraphBuilder::BuildArrayBufferViewInitialization(
|
||||
graph()->GetConstant0());
|
||||
}
|
||||
|
||||
Add<HStoreNamedField>(
|
||||
obj,
|
||||
HObjectAccess::ForJSArrayBufferViewBuffer(), buffer);
|
||||
Add<HStoreNamedField>(
|
||||
obj,
|
||||
HObjectAccess::ForJSArrayBufferViewByteOffset(),
|
||||
@ -8433,14 +8438,27 @@ void HGraphBuilder::BuildArrayBufferViewInitialization(
|
||||
HObjectAccess::ForJSArrayBufferViewByteLength(),
|
||||
byte_length);
|
||||
|
||||
HObjectAccess weak_first_view_access =
|
||||
HObjectAccess::ForJSArrayBufferWeakFirstView();
|
||||
Add<HStoreNamedField>(obj,
|
||||
HObjectAccess::ForJSArrayBufferViewWeakNext(),
|
||||
Add<HLoadNamedField>(buffer, static_cast<HValue*>(NULL),
|
||||
weak_first_view_access));
|
||||
Add<HStoreNamedField>(
|
||||
buffer, weak_first_view_access, obj);
|
||||
if (buffer != NULL) {
|
||||
Add<HStoreNamedField>(
|
||||
obj,
|
||||
HObjectAccess::ForJSArrayBufferViewBuffer(), buffer);
|
||||
HObjectAccess weak_first_view_access =
|
||||
HObjectAccess::ForJSArrayBufferWeakFirstView();
|
||||
Add<HStoreNamedField>(obj,
|
||||
HObjectAccess::ForJSArrayBufferViewWeakNext(),
|
||||
Add<HLoadNamedField>(buffer,
|
||||
static_cast<HValue*>(NULL),
|
||||
weak_first_view_access));
|
||||
Add<HStoreNamedField>(buffer, weak_first_view_access, obj);
|
||||
} else {
|
||||
Add<HStoreNamedField>(
|
||||
obj,
|
||||
HObjectAccess::ForJSArrayBufferViewBuffer(),
|
||||
Add<HConstant>(static_cast<int32_t>(0)));
|
||||
Add<HStoreNamedField>(obj,
|
||||
HObjectAccess::ForJSArrayBufferViewWeakNext(),
|
||||
graph()->GetConstantUndefined());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8467,6 +8485,115 @@ void HOptimizedGraphBuilder::GenerateDataViewInitialize(
|
||||
}
|
||||
|
||||
|
||||
static Handle<Map> TypedArrayMap(Isolate* isolate,
|
||||
ExternalArrayType array_type,
|
||||
ElementsKind target_kind) {
|
||||
Handle<Context> native_context = isolate->native_context();
|
||||
Handle<JSFunction> fun;
|
||||
switch (array_type) {
|
||||
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
||||
case kExternal##Type##Array: \
|
||||
fun = Handle<JSFunction>(native_context->type##_array_fun()); \
|
||||
break;
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
||||
#undef TYPED_ARRAY_CASE
|
||||
}
|
||||
Handle<Map> map(fun->initial_map());
|
||||
return Map::AsElementsKind(map, target_kind);
|
||||
}
|
||||
|
||||
|
||||
HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements(
|
||||
ExternalArrayType array_type,
|
||||
bool is_zero_byte_offset,
|
||||
HValue* buffer, HValue* byte_offset, HValue* length) {
|
||||
Handle<Map> external_array_map(
|
||||
isolate()->heap()->MapForExternalArrayType(array_type));
|
||||
HValue* elements =
|
||||
Add<HAllocate>(
|
||||
Add<HConstant>(ExternalArray::kAlignedSize),
|
||||
HType::Tagged(),
|
||||
NOT_TENURED,
|
||||
external_array_map->instance_type());
|
||||
|
||||
AddStoreMapConstant(elements, external_array_map);
|
||||
|
||||
HValue* backing_store = Add<HLoadNamedField>(
|
||||
buffer, static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForJSArrayBufferBackingStore());
|
||||
|
||||
HValue* typed_array_start;
|
||||
if (is_zero_byte_offset) {
|
||||
typed_array_start = backing_store;
|
||||
} else {
|
||||
HInstruction* external_pointer =
|
||||
AddUncasted<HAdd>(backing_store, byte_offset);
|
||||
// Arguments are checked prior to call to TypedArrayInitialize,
|
||||
// including byte_offset.
|
||||
external_pointer->ClearFlag(HValue::kCanOverflow);
|
||||
typed_array_start = external_pointer;
|
||||
}
|
||||
|
||||
|
||||
Add<HStoreNamedField>(elements,
|
||||
HObjectAccess::ForExternalArrayExternalPointer(),
|
||||
typed_array_start);
|
||||
|
||||
Add<HStoreNamedField>(elements,
|
||||
HObjectAccess::ForFixedArrayLength(), length);
|
||||
return elements;
|
||||
}
|
||||
|
||||
|
||||
HValue* HOptimizedGraphBuilder::BuildAllocateFixedTypedArray(
|
||||
ExternalArrayType array_type, size_t element_size,
|
||||
ElementsKind fixed_elements_kind,
|
||||
HValue* byte_length, HValue* length) {
|
||||
STATIC_ASSERT(
|
||||
(FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask) == 0);
|
||||
HValue* total_size;
|
||||
|
||||
// if fixed array's elements are not aligned to object's alignment,
|
||||
// we need to align the whole array to object alignment.
|
||||
if (element_size % kObjectAlignment != 0) {
|
||||
total_size = BuildObjectSizeAlignment(
|
||||
byte_length, FixedTypedArrayBase::kHeaderSize);
|
||||
} else {
|
||||
total_size = AddUncasted<HAdd>(byte_length,
|
||||
Add<HConstant>(FixedTypedArrayBase::kHeaderSize));
|
||||
total_size->ClearFlag(HValue::kCanOverflow);
|
||||
}
|
||||
|
||||
Handle<Map> fixed_typed_array_map(
|
||||
isolate()->heap()->MapForFixedTypedArray(array_type));
|
||||
HValue* elements =
|
||||
Add<HAllocate>(total_size, HType::Tagged(),
|
||||
NOT_TENURED,
|
||||
fixed_typed_array_map->instance_type());
|
||||
AddStoreMapConstant(elements, fixed_typed_array_map);
|
||||
|
||||
Add<HStoreNamedField>(elements,
|
||||
HObjectAccess::ForFixedArrayLength(),
|
||||
length);
|
||||
HValue* filler = Add<HConstant>(static_cast<int32_t>(0));
|
||||
|
||||
{
|
||||
LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
|
||||
|
||||
HValue* key = builder.BeginBody(
|
||||
Add<HConstant>(static_cast<int32_t>(0)),
|
||||
length, Token::LT);
|
||||
Add<HStoreKeyed>(elements, key, filler, fixed_elements_kind);
|
||||
|
||||
builder.EndBody();
|
||||
}
|
||||
Add<HStoreNamedField>(
|
||||
elements, HObjectAccess::ForFixedArrayLength(), length);
|
||||
return elements;
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateTypedArrayInitialize(
|
||||
CallRuntime* expr) {
|
||||
ZoneList<Expression*>* arguments = expr->arguments();
|
||||
@ -8490,8 +8617,13 @@ void HOptimizedGraphBuilder::GenerateTypedArrayInitialize(
|
||||
ASSERT(value->IsSmi());
|
||||
int array_id = Smi::cast(*value)->value();
|
||||
|
||||
CHECK_ALIVE(VisitForValue(arguments->at(kBufferArg)));
|
||||
HValue* buffer = Pop();
|
||||
HValue* buffer;
|
||||
if (!arguments->at(kBufferArg)->IsNullLiteral()) {
|
||||
CHECK_ALIVE(VisitForValue(arguments->at(kBufferArg)));
|
||||
buffer = Pop();
|
||||
} else {
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
HValue* byte_offset;
|
||||
bool is_zero_byte_offset;
|
||||
@ -8505,6 +8637,7 @@ void HOptimizedGraphBuilder::GenerateTypedArrayInitialize(
|
||||
CHECK_ALIVE(VisitForValue(arguments->at(kByteOffsetArg)));
|
||||
byte_offset = Pop();
|
||||
is_zero_byte_offset = false;
|
||||
ASSERT(buffer != NULL);
|
||||
}
|
||||
|
||||
CHECK_ALIVE(VisitForValue(arguments->at(kByteLengthArg)));
|
||||
@ -8517,13 +8650,24 @@ void HOptimizedGraphBuilder::GenerateTypedArrayInitialize(
|
||||
byte_offset_smi.Then();
|
||||
}
|
||||
|
||||
ExternalArrayType array_type =
|
||||
kExternalInt8Array; // Bogus initialization.
|
||||
size_t element_size = 1; // Bogus initialization.
|
||||
ElementsKind external_elements_kind = // Bogus initialization.
|
||||
EXTERNAL_INT8_ELEMENTS;
|
||||
ElementsKind fixed_elements_kind = // Bogus initialization.
|
||||
INT8_ELEMENTS;
|
||||
Runtime::ArrayIdToTypeAndSize(array_id,
|
||||
&array_type,
|
||||
&external_elements_kind,
|
||||
&fixed_elements_kind,
|
||||
&element_size);
|
||||
|
||||
|
||||
{ // byte_offset is Smi.
|
||||
BuildArrayBufferViewInitialization<JSTypedArray>(
|
||||
obj, buffer, byte_offset, byte_length);
|
||||
|
||||
ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
|
||||
size_t element_size = 1; // Bogus initialization.
|
||||
Runtime::ArrayIdToTypeAndSize(array_id, &array_type, &element_size);
|
||||
|
||||
HInstruction* length = AddUncasted<HDiv>(byte_length,
|
||||
Add<HConstant>(static_cast<int32_t>(element_size)));
|
||||
@ -8532,40 +8676,19 @@ void HOptimizedGraphBuilder::GenerateTypedArrayInitialize(
|
||||
HObjectAccess::ForJSTypedArrayLength(),
|
||||
length);
|
||||
|
||||
Handle<Map> external_array_map(
|
||||
isolate()->heap()->MapForExternalArrayType(array_type));
|
||||
|
||||
HValue* elements =
|
||||
Add<HAllocate>(
|
||||
Add<HConstant>(ExternalArray::kAlignedSize),
|
||||
HType::Tagged(),
|
||||
NOT_TENURED,
|
||||
external_array_map->instance_type());
|
||||
|
||||
AddStoreMapConstant(elements, external_array_map);
|
||||
|
||||
HValue* backing_store = Add<HLoadNamedField>(
|
||||
buffer, static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForJSArrayBufferBackingStore());
|
||||
|
||||
HValue* typed_array_start;
|
||||
if (is_zero_byte_offset) {
|
||||
typed_array_start = backing_store;
|
||||
HValue* elements;
|
||||
if (buffer != NULL) {
|
||||
elements = BuildAllocateExternalElements(
|
||||
array_type, is_zero_byte_offset, buffer, byte_offset, length);
|
||||
Handle<Map> obj_map = TypedArrayMap(
|
||||
isolate(), array_type, external_elements_kind);
|
||||
AddStoreMapConstant(obj, obj_map);
|
||||
} else {
|
||||
HInstruction* external_pointer =
|
||||
AddUncasted<HAdd>(backing_store, byte_offset);
|
||||
// Arguments are checked prior to call to TypedArrayInitialize,
|
||||
// including byte_offset.
|
||||
external_pointer->ClearFlag(HValue::kCanOverflow);
|
||||
typed_array_start = external_pointer;
|
||||
ASSERT(is_zero_byte_offset);
|
||||
elements = BuildAllocateFixedTypedArray(
|
||||
array_type, element_size, fixed_elements_kind,
|
||||
byte_length, length);
|
||||
}
|
||||
|
||||
Add<HStoreNamedField>(elements,
|
||||
HObjectAccess::ForExternalArrayExternalPointer(),
|
||||
typed_array_start);
|
||||
Add<HStoreNamedField>(elements,
|
||||
HObjectAccess::ForFixedArrayLength(),
|
||||
length);
|
||||
Add<HStoreNamedField>(
|
||||
obj, HObjectAccess::ForElementsPointer(), elements);
|
||||
}
|
||||
@ -8593,6 +8716,15 @@ void HOptimizedGraphBuilder::GenerateMaxSmi(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateTypedArrayMaxSizeInHeap(
|
||||
CallRuntime* expr) {
|
||||
ASSERT(expr->arguments()->length() == 0);
|
||||
HConstant* result = New<HConstant>(static_cast<int32_t>(
|
||||
FLAG_typed_array_max_size_in_heap));
|
||||
return ast_context()->ReturnInstruction(result, expr->id());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
|
||||
ASSERT(!HasStackOverflow());
|
||||
ASSERT(current_block() != NULL);
|
||||
|
@ -1372,6 +1372,10 @@ class HGraphBuilder {
|
||||
HValue* dst_offset,
|
||||
String::Encoding dst_encoding,
|
||||
HValue* length);
|
||||
|
||||
// Align an object size to object alignment boundary
|
||||
HValue* BuildObjectSizeAlignment(HValue* unaligned_size, int header_size);
|
||||
|
||||
// Both operands are non-empty strings.
|
||||
HValue* BuildUncheckedStringAdd(HValue* left,
|
||||
HValue* right,
|
||||
@ -2322,6 +2326,15 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
SmallMapList* types,
|
||||
Handle<String> name);
|
||||
|
||||
HValue* BuildAllocateExternalElements(
|
||||
ExternalArrayType array_type,
|
||||
bool is_zero_byte_offset,
|
||||
HValue* buffer, HValue* byte_offset, HValue* length);
|
||||
HValue* BuildAllocateFixedTypedArray(
|
||||
ExternalArrayType array_type, size_t element_size,
|
||||
ElementsKind fixed_elements_kind,
|
||||
HValue* byte_length, HValue* length);
|
||||
|
||||
bool IsCallNewArrayInlineable(CallNew* expr);
|
||||
void BuildInlinedCallNewArray(CallNew* expr);
|
||||
|
||||
|
@ -774,7 +774,8 @@ void JSArrayBufferView::JSArrayBufferViewVerify() {
|
||||
CHECK(IsJSArrayBufferView());
|
||||
JSObjectVerify();
|
||||
VerifyPointer(buffer());
|
||||
CHECK(buffer()->IsJSArrayBuffer() || buffer()->IsUndefined());
|
||||
CHECK(buffer()->IsJSArrayBuffer() || buffer()->IsUndefined()
|
||||
|| buffer() == Smi::FromInt(0));
|
||||
|
||||
VerifyPointer(byte_offset());
|
||||
CHECK(byte_offset()->IsSmi() || byte_offset()->IsHeapNumber()
|
||||
|
@ -1736,6 +1736,11 @@ void JSObject::initialize_elements() {
|
||||
ExternalArray* empty_array = GetHeap()->EmptyExternalArrayForMap(map());
|
||||
ASSERT(!GetHeap()->InNewSpace(empty_array));
|
||||
WRITE_FIELD(this, kElementsOffset, empty_array);
|
||||
} else if (map()->has_fixed_typed_array_elements()) {
|
||||
FixedTypedArrayBase* empty_array =
|
||||
GetHeap()->EmptyFixedTypedArrayForMap(map());
|
||||
ASSERT(!GetHeap()->InNewSpace(empty_array));
|
||||
WRITE_FIELD(this, kElementsOffset, empty_array);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -3676,35 +3681,64 @@ void ExternalFloat64Array::set(int index, double value) {
|
||||
}
|
||||
|
||||
|
||||
int FixedTypedArrayBase::size() {
|
||||
void* FixedTypedArrayBase::DataPtr() {
|
||||
return FIELD_ADDR(this, kDataOffset);
|
||||
}
|
||||
|
||||
|
||||
int FixedTypedArrayBase::DataSize() {
|
||||
InstanceType instance_type = map()->instance_type();
|
||||
int element_size;
|
||||
switch (instance_type) {
|
||||
case FIXED_UINT8_ARRAY_TYPE:
|
||||
case FIXED_INT8_ARRAY_TYPE:
|
||||
case FIXED_UINT8_CLAMPED_ARRAY_TYPE:
|
||||
element_size = 1;
|
||||
break;
|
||||
case FIXED_UINT16_ARRAY_TYPE:
|
||||
case FIXED_INT16_ARRAY_TYPE:
|
||||
element_size = 2;
|
||||
break;
|
||||
case FIXED_UINT32_ARRAY_TYPE:
|
||||
case FIXED_INT32_ARRAY_TYPE:
|
||||
case FIXED_FLOAT32_ARRAY_TYPE:
|
||||
element_size = 4;
|
||||
break;
|
||||
case FIXED_FLOAT64_ARRAY_TYPE:
|
||||
element_size = 8;
|
||||
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
||||
case FIXED_##TYPE##_ARRAY_TYPE: \
|
||||
element_size = size; \
|
||||
break;
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
||||
#undef TYPED_ARRAY_CASE
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
return OBJECT_POINTER_ALIGN(kDataOffset + length() * element_size);
|
||||
return length() * element_size;
|
||||
}
|
||||
|
||||
|
||||
int FixedTypedArrayBase::size() {
|
||||
return OBJECT_POINTER_ALIGN(kDataOffset + DataSize());
|
||||
}
|
||||
|
||||
|
||||
uint8_t Uint8ArrayTraits::defaultValue() { return 0; }
|
||||
|
||||
|
||||
uint8_t Uint8ClampedArrayTraits::defaultValue() { return 0; }
|
||||
|
||||
|
||||
int8_t Int8ArrayTraits::defaultValue() { return 0; }
|
||||
|
||||
|
||||
uint16_t Uint16ArrayTraits::defaultValue() { return 0; }
|
||||
|
||||
|
||||
int16_t Int16ArrayTraits::defaultValue() { return 0; }
|
||||
|
||||
|
||||
uint32_t Uint32ArrayTraits::defaultValue() { return 0; }
|
||||
|
||||
|
||||
int32_t Int32ArrayTraits::defaultValue() { return 0; }
|
||||
|
||||
|
||||
float Float32ArrayTraits::defaultValue() {
|
||||
return static_cast<float>(OS::nan_value());
|
||||
}
|
||||
|
||||
|
||||
double Float64ArrayTraits::defaultValue() { return OS::nan_value(); }
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename Traits::ElementType FixedTypedArray<Traits>::get_scalar(int index) {
|
||||
ASSERT((index >= 0) && (index < this->length()));
|
||||
@ -3739,6 +3773,47 @@ void FixedTypedArray<Float64ArrayTraits>::set(
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename Traits::ElementType FixedTypedArray<Traits>::from_int(int value) {
|
||||
return static_cast<ElementType>(value);
|
||||
}
|
||||
|
||||
|
||||
template <> inline
|
||||
uint8_t FixedTypedArray<Uint8ClampedArrayTraits>::from_int(int value) {
|
||||
if (value < 0) return 0;
|
||||
if (value > 0xFF) return 0xFF;
|
||||
return static_cast<uint8_t>(value);
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename Traits::ElementType FixedTypedArray<Traits>::from_double(
|
||||
double value) {
|
||||
return static_cast<ElementType>(DoubleToInt32(value));
|
||||
}
|
||||
|
||||
|
||||
template<> inline
|
||||
uint8_t FixedTypedArray<Uint8ClampedArrayTraits>::from_double(double value) {
|
||||
if (value < 0) return 0;
|
||||
if (value > 0xFF) return 0xFF;
|
||||
return static_cast<uint8_t>(lrint(value));
|
||||
}
|
||||
|
||||
|
||||
template<> inline
|
||||
float FixedTypedArray<Float32ArrayTraits>::from_double(double value) {
|
||||
return static_cast<float>(value);
|
||||
}
|
||||
|
||||
|
||||
template<> inline
|
||||
double FixedTypedArray<Float64ArrayTraits>::from_double(double value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
MaybeObject* FixedTypedArray<Traits>::get(int index) {
|
||||
return Traits::ToObject(GetHeap(), get_scalar(index));
|
||||
@ -3750,10 +3825,10 @@ MaybeObject* FixedTypedArray<Traits>::SetValue(uint32_t index, Object* value) {
|
||||
if (index < static_cast<uint32_t>(length())) {
|
||||
if (value->IsSmi()) {
|
||||
int int_value = Smi::cast(value)->value();
|
||||
cast_value = static_cast<ElementType>(int_value);
|
||||
cast_value = from_int(int_value);
|
||||
} else if (value->IsHeapNumber()) {
|
||||
double double_value = HeapNumber::cast(value)->value();
|
||||
cast_value = static_cast<ElementType>(DoubleToInt32(double_value));
|
||||
cast_value = from_double(double_value);
|
||||
} else {
|
||||
// Clamp undefined to the default value. All other types have been
|
||||
// converted to a number type further up in the call chain.
|
||||
@ -6021,6 +6096,20 @@ bool JSObject::HasFixedTypedArrayElements() {
|
||||
}
|
||||
|
||||
|
||||
#define FIXED_TYPED_ELEMENTS_CHECK(Type, type, TYPE, ctype, size) \
|
||||
bool JSObject::HasFixed##Type##Elements() { \
|
||||
HeapObject* array = elements(); \
|
||||
ASSERT(array != NULL); \
|
||||
if (!array->IsHeapObject()) \
|
||||
return false; \
|
||||
return array->map()->instance_type() == FIXED_##TYPE##_ARRAY_TYPE; \
|
||||
}
|
||||
|
||||
TYPED_ARRAYS(FIXED_TYPED_ELEMENTS_CHECK)
|
||||
|
||||
#undef FIXED_TYPED_ELEMENTS_CHECK
|
||||
|
||||
|
||||
bool JSObject::HasNamedInterceptor() {
|
||||
return map()->has_named_interceptor();
|
||||
}
|
||||
|
127
src/objects.cc
127
src/objects.cc
@ -3233,24 +3233,31 @@ Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
|
||||
|
||||
static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
|
||||
Map* current_map = map;
|
||||
int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
|
||||
int to_index = IsFastElementsKind(to_kind)
|
||||
? GetSequenceIndexFromFastElementsKind(to_kind)
|
||||
: GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
|
||||
int target_kind =
|
||||
IsFastElementsKind(to_kind) || IsExternalArrayElementsKind(to_kind)
|
||||
? to_kind
|
||||
: TERMINAL_FAST_ELEMENTS_KIND;
|
||||
|
||||
ASSERT(index <= to_index);
|
||||
// Support for legacy API.
|
||||
if (IsExternalArrayElementsKind(to_kind) &&
|
||||
!IsFixedTypedArrayElementsKind(map->elements_kind())) {
|
||||
return map;
|
||||
}
|
||||
|
||||
for (; index < to_index; ++index) {
|
||||
ElementsKind kind = map->elements_kind();
|
||||
while (kind != target_kind) {
|
||||
kind = GetNextTransitionElementsKind(kind);
|
||||
if (!current_map->HasElementsTransition()) return current_map;
|
||||
current_map = current_map->elements_transition_map();
|
||||
}
|
||||
if (!IsFastElementsKind(to_kind) && current_map->HasElementsTransition()) {
|
||||
|
||||
if (to_kind != kind && current_map->HasElementsTransition()) {
|
||||
ASSERT(to_kind == DICTIONARY_ELEMENTS);
|
||||
Map* next_map = current_map->elements_transition_map();
|
||||
if (next_map->elements_kind() == to_kind) return next_map;
|
||||
}
|
||||
ASSERT(IsFastElementsKind(to_kind)
|
||||
? current_map->elements_kind() == to_kind
|
||||
: current_map->elements_kind() == TERMINAL_FAST_ELEMENTS_KIND);
|
||||
|
||||
ASSERT(current_map->elements_kind() == target_kind);
|
||||
return current_map;
|
||||
}
|
||||
|
||||
@ -3278,26 +3285,21 @@ bool Map::IsMapInArrayPrototypeChain() {
|
||||
|
||||
static MaybeObject* AddMissingElementsTransitions(Map* map,
|
||||
ElementsKind to_kind) {
|
||||
ASSERT(IsFastElementsKind(map->elements_kind()));
|
||||
int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
|
||||
int to_index = IsFastElementsKind(to_kind)
|
||||
? GetSequenceIndexFromFastElementsKind(to_kind)
|
||||
: GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
|
||||
|
||||
ASSERT(index <= to_index);
|
||||
ASSERT(IsTransitionElementsKind(map->elements_kind()));
|
||||
|
||||
Map* current_map = map;
|
||||
|
||||
for (; index < to_index; ++index) {
|
||||
ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1);
|
||||
ElementsKind kind = map->elements_kind();
|
||||
while (kind != to_kind && !IsTerminalElementsKind(kind)) {
|
||||
kind = GetNextTransitionElementsKind(kind);
|
||||
MaybeObject* maybe_next_map =
|
||||
current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
|
||||
current_map->CopyAsElementsKind(kind, INSERT_TRANSITION);
|
||||
if (!maybe_next_map->To(¤t_map)) return maybe_next_map;
|
||||
}
|
||||
|
||||
// In case we are exiting the fast elements kind system, just add the map in
|
||||
// the end.
|
||||
if (!IsFastElementsKind(to_kind)) {
|
||||
if (kind != to_kind) {
|
||||
MaybeObject* maybe_next_map =
|
||||
current_map->CopyAsElementsKind(to_kind, INSERT_TRANSITION);
|
||||
if (!maybe_next_map->To(¤t_map)) return maybe_next_map;
|
||||
@ -3329,7 +3331,7 @@ MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
|
||||
// Only remember the map transition if there is not an already existing
|
||||
// non-matching element transition.
|
||||
!start_map->IsUndefined() && !start_map->is_shared() &&
|
||||
IsFastElementsKind(from_kind);
|
||||
IsTransitionElementsKind(from_kind);
|
||||
|
||||
// Only store fast element maps in ascending generality.
|
||||
if (IsFastElementsKind(to_kind)) {
|
||||
@ -4701,7 +4703,8 @@ static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
|
||||
|
||||
Handle<SeededNumberDictionary> JSObject::NormalizeElements(
|
||||
Handle<JSObject> object) {
|
||||
ASSERT(!object->HasExternalArrayElements());
|
||||
ASSERT(!object->HasExternalArrayElements() &&
|
||||
!object->HasFixedTypedArrayElements());
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
@ -5436,7 +5439,8 @@ Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
|
||||
}
|
||||
|
||||
// It's not possible to seal objects with external array elements
|
||||
if (object->HasExternalArrayElements()) {
|
||||
if (object->HasExternalArrayElements() ||
|
||||
object->HasFixedTypedArrayElements()) {
|
||||
Handle<Object> error =
|
||||
isolate->factory()->NewTypeError(
|
||||
"cant_prevent_ext_external_array_elements",
|
||||
@ -5516,7 +5520,8 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
|
||||
}
|
||||
|
||||
// It's not possible to freeze objects with external array elements
|
||||
if (object->HasExternalArrayElements()) {
|
||||
if (object->HasExternalArrayElements() ||
|
||||
object->HasFixedTypedArrayElements()) {
|
||||
Handle<Object> error =
|
||||
isolate->factory()->NewTypeError(
|
||||
"cant_prevent_ext_external_array_elements",
|
||||
@ -12435,7 +12440,9 @@ Handle<Object> JSObject::SetElement(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
// Don't allow element properties to be redefined for external arrays.
|
||||
if (object->HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
|
||||
if ((object->HasExternalArrayElements() ||
|
||||
object->HasFixedTypedArrayElements()) &&
|
||||
set_mode == DEFINE_PROPERTY) {
|
||||
Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
|
||||
Handle<Object> args[] = { object, number };
|
||||
Handle<Object> error = isolate->factory()->NewTypeError(
|
||||
@ -14354,10 +14361,11 @@ Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
|
||||
object->ValidateElements();
|
||||
|
||||
object->set_map_and_elements(*new_map, *fast_elements);
|
||||
} else if (object->HasExternalArrayElements()) {
|
||||
// External arrays cannot have holes or undefined elements.
|
||||
} else if (object->HasExternalArrayElements() ||
|
||||
object->HasFixedTypedArrayElements()) {
|
||||
// Typed arrays cannot have holes or undefined elements.
|
||||
return handle(Smi::FromInt(
|
||||
ExternalArray::cast(object->elements())->length()), isolate);
|
||||
FixedArrayBase::cast(object->elements())->length()), isolate);
|
||||
} else if (!object->HasFastDoubleElements()) {
|
||||
EnsureWritableFastElements(object);
|
||||
}
|
||||
@ -14458,12 +14466,14 @@ ExternalArrayType JSTypedArray::type() {
|
||||
switch (elements()->map()->instance_type()) {
|
||||
#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
|
||||
case EXTERNAL_##TYPE##_ARRAY_TYPE: \
|
||||
case FIXED_##TYPE##_ARRAY_TYPE: \
|
||||
return kExternal##Type##Array;
|
||||
|
||||
TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
|
||||
#undef INSTANCE_TYPE_TO_ARRAY_TYPE
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return static_cast<ExternalArrayType>(-1);
|
||||
}
|
||||
}
|
||||
@ -16302,6 +16312,65 @@ void JSTypedArray::Neuter() {
|
||||
}
|
||||
|
||||
|
||||
static ElementsKind FixedToExternalElementsKind(ElementsKind elements_kind) {
|
||||
switch (elements_kind) {
|
||||
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
||||
case TYPE##_ELEMENTS: return EXTERNAL_##TYPE##_ELEMENTS;
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
||||
#undef TYPED_ARRAY_CASE
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
|
||||
Handle<JSTypedArray> typed_array) {
|
||||
|
||||
Handle<Map> map(typed_array->map());
|
||||
Isolate* isolate = typed_array->GetIsolate();
|
||||
|
||||
ASSERT(IsFixedTypedArrayElementsKind(map->elements_kind()));
|
||||
|
||||
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
||||
Handle<FixedTypedArrayBase> fixed_typed_array(
|
||||
FixedTypedArrayBase::cast(typed_array->elements()));
|
||||
Runtime::SetupArrayBufferAllocatingData(isolate, buffer,
|
||||
fixed_typed_array->DataSize(), false);
|
||||
memcpy(buffer->backing_store(),
|
||||
fixed_typed_array->DataPtr(),
|
||||
fixed_typed_array->DataSize());
|
||||
Handle<ExternalArray> new_elements =
|
||||
isolate->factory()->NewExternalArray(
|
||||
fixed_typed_array->length(), typed_array->type(),
|
||||
static_cast<uint8_t*>(buffer->backing_store()));
|
||||
Handle<Map> new_map = JSObject::GetElementsTransitionMap(
|
||||
typed_array,
|
||||
FixedToExternalElementsKind(map->elements_kind()));
|
||||
|
||||
buffer->set_weak_first_view(*typed_array);
|
||||
ASSERT(typed_array->weak_next() == isolate->heap()->undefined_value());
|
||||
typed_array->set_buffer(*buffer);
|
||||
typed_array->set_map_and_elements(*new_map, *new_elements);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
|
||||
Handle<Object> result(buffer(), GetIsolate());
|
||||
if (*result != Smi::FromInt(0)) {
|
||||
ASSERT(IsExternalArrayElementsKind(map()->elements_kind()));
|
||||
return Handle<JSArrayBuffer>::cast(result);
|
||||
}
|
||||
Handle<JSTypedArray> self(this);
|
||||
return MaterializeArrayBuffer(self);
|
||||
}
|
||||
|
||||
|
||||
HeapType* PropertyCell::type() {
|
||||
return static_cast<HeapType*>(type_raw());
|
||||
}
|
||||
|
@ -2217,6 +2217,17 @@ class JSObject: public JSReceiver {
|
||||
|
||||
inline bool HasFixedTypedArrayElements();
|
||||
|
||||
inline bool HasFixedUint8ClampedElements();
|
||||
inline bool HasFixedArrayElements();
|
||||
inline bool HasFixedInt8Elements();
|
||||
inline bool HasFixedUint8Elements();
|
||||
inline bool HasFixedInt16Elements();
|
||||
inline bool HasFixedUint16Elements();
|
||||
inline bool HasFixedInt32Elements();
|
||||
inline bool HasFixedUint32Elements();
|
||||
inline bool HasFixedFloat32Elements();
|
||||
inline bool HasFixedFloat64Elements();
|
||||
|
||||
bool HasFastArgumentsElements();
|
||||
bool HasDictionaryArgumentsElements();
|
||||
inline SeededNumberDictionary* element_dictionary(); // Gets slow elements.
|
||||
@ -4956,6 +4967,11 @@ class FixedTypedArrayBase: public FixedArrayBase {
|
||||
|
||||
inline int size();
|
||||
|
||||
// Use with care: returns raw pointer into heap.
|
||||
inline void* DataPtr();
|
||||
|
||||
inline int DataSize();
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(FixedTypedArrayBase);
|
||||
};
|
||||
@ -4982,6 +4998,9 @@ class FixedTypedArray: public FixedTypedArrayBase {
|
||||
MUST_USE_RESULT inline MaybeObject* get(int index);
|
||||
inline void set(int index, ElementType value);
|
||||
|
||||
static inline ElementType from_int(int value);
|
||||
static inline ElementType from_double(double value);
|
||||
|
||||
// This accessor applies the correct conversion from Smi, HeapNumber
|
||||
// and undefined.
|
||||
MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value);
|
||||
@ -5004,7 +5023,7 @@ class FixedTypedArray: public FixedTypedArrayBase {
|
||||
static const InstanceType kInstanceType = FIXED_##TYPE##_ARRAY_TYPE; \
|
||||
static const char* Designator() { return #type " array"; } \
|
||||
static inline MaybeObject* ToObject(Heap* heap, elementType scalar); \
|
||||
static elementType defaultValue() { return 0; } \
|
||||
static inline elementType defaultValue(); \
|
||||
}; \
|
||||
\
|
||||
typedef FixedTypedArray<Type##ArrayTraits> Fixed##Type##Array;
|
||||
@ -6224,9 +6243,11 @@ class Map: public HeapObject {
|
||||
Descriptor* descriptor,
|
||||
int index,
|
||||
TransitionFlag flag);
|
||||
static Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind kind);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* AsElementsKind(ElementsKind kind);
|
||||
|
||||
static Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind kind);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* CopyAsElementsKind(ElementsKind kind,
|
||||
TransitionFlag flag);
|
||||
|
||||
@ -9916,6 +9937,8 @@ class JSTypedArray: public JSArrayBufferView {
|
||||
ExternalArrayType type();
|
||||
size_t element_size();
|
||||
|
||||
Handle<JSArrayBuffer> GetBuffer();
|
||||
|
||||
// Dispatched behavior.
|
||||
DECLARE_PRINTER(JSTypedArray)
|
||||
DECLARE_VERIFIER(JSTypedArray)
|
||||
@ -9927,6 +9950,9 @@ class JSTypedArray: public JSArrayBufferView {
|
||||
kSize + v8::ArrayBufferView::kInternalFieldCount * kPointerSize;
|
||||
|
||||
private:
|
||||
static Handle<JSArrayBuffer> MaterializeArrayBuffer(
|
||||
Handle<JSTypedArray> typed_array);
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray);
|
||||
};
|
||||
|
||||
|
109
src/runtime.cc
109
src/runtime.cc
@ -926,11 +926,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferNeuter) {
|
||||
|
||||
|
||||
void Runtime::ArrayIdToTypeAndSize(
|
||||
int arrayId, ExternalArrayType* array_type, size_t* element_size) {
|
||||
int arrayId,
|
||||
ExternalArrayType* array_type,
|
||||
ElementsKind* external_elements_kind,
|
||||
ElementsKind* fixed_elements_kind,
|
||||
size_t* element_size) {
|
||||
switch (arrayId) {
|
||||
#define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \
|
||||
case ARRAY_ID_##TYPE: \
|
||||
*array_type = kExternal##Type##Array; \
|
||||
*external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \
|
||||
*fixed_elements_kind = TYPE##_ELEMENTS; \
|
||||
*element_size = size; \
|
||||
break;
|
||||
|
||||
@ -948,7 +954,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
|
||||
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, maybe_buffer, 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
|
||||
|
||||
@ -960,18 +966,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
|
||||
|
||||
ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
|
||||
size_t element_size = 1; // Bogus initialization.
|
||||
Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
|
||||
ElementsKind external_elements_kind = EXTERNAL_INT8_ELEMENTS;
|
||||
ElementsKind fixed_elements_kind = INT8_ELEMENTS;
|
||||
Runtime::ArrayIdToTypeAndSize(arrayId,
|
||||
&array_type,
|
||||
&external_elements_kind,
|
||||
&fixed_elements_kind,
|
||||
&element_size);
|
||||
|
||||
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);
|
||||
size_t array_buffer_byte_length =
|
||||
NumberToSize(isolate, buffer->byte_length());
|
||||
CHECK(byte_offset <= array_buffer_byte_length);
|
||||
CHECK(array_buffer_byte_length - byte_offset >= byte_length);
|
||||
|
||||
CHECK_EQ(0, static_cast<int>(byte_length % element_size));
|
||||
size_t length = byte_length / element_size;
|
||||
@ -984,14 +991,34 @@ 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_view());
|
||||
buffer->set_weak_first_view(*holder);
|
||||
if (!maybe_buffer->IsNull()) {
|
||||
Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(*maybe_buffer));
|
||||
|
||||
Handle<ExternalArray> elements =
|
||||
isolate->factory()->NewExternalArray(
|
||||
static_cast<int>(length), array_type,
|
||||
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
|
||||
holder->set_elements(*elements);
|
||||
size_t array_buffer_byte_length =
|
||||
NumberToSize(isolate, buffer->byte_length());
|
||||
CHECK(byte_offset <= array_buffer_byte_length);
|
||||
CHECK(array_buffer_byte_length - byte_offset >= byte_length);
|
||||
|
||||
holder->set_buffer(*buffer);
|
||||
holder->set_weak_next(buffer->weak_first_view());
|
||||
buffer->set_weak_first_view(*holder);
|
||||
|
||||
Handle<ExternalArray> elements =
|
||||
isolate->factory()->NewExternalArray(
|
||||
static_cast<int>(length), array_type,
|
||||
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
|
||||
Handle<Map> map =
|
||||
JSObject::GetElementsTransitionMap(holder, external_elements_kind);
|
||||
holder->set_map_and_elements(*map, *elements);
|
||||
ASSERT(IsExternalArrayElementsKind(holder->map()->elements_kind()));
|
||||
} else {
|
||||
holder->set_buffer(Smi::FromInt(0));
|
||||
holder->set_weak_next(isolate->heap()->undefined_value());
|
||||
Handle<FixedTypedArrayBase> elements =
|
||||
isolate->factory()->NewFixedTypedArray(
|
||||
static_cast<int>(length), array_type);
|
||||
holder->set_elements(*elements);
|
||||
}
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
@ -1017,7 +1044,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
|
||||
|
||||
ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
|
||||
size_t element_size = 1; // Bogus initialization.
|
||||
Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
|
||||
ElementsKind external_elements_kind;
|
||||
ElementsKind fixed_elements_kind;
|
||||
Runtime::ArrayIdToTypeAndSize(arrayId,
|
||||
&array_type,
|
||||
&external_elements_kind,
|
||||
&fixed_elements_kind,
|
||||
&element_size);
|
||||
|
||||
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
||||
if (source->IsJSTypedArray() &&
|
||||
@ -1070,7 +1103,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
|
||||
isolate->factory()->NewExternalArray(
|
||||
static_cast<int>(length), array_type,
|
||||
static_cast<uint8_t*>(buffer->backing_store()));
|
||||
holder->set_elements(*elements);
|
||||
Handle<Map> map = JSObject::GetElementsTransitionMap(
|
||||
holder, external_elements_kind);
|
||||
holder->set_map_and_elements(*map, *elements);
|
||||
|
||||
if (source->IsJSTypedArray()) {
|
||||
Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
|
||||
@ -1078,7 +1113,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
|
||||
if (typed_array->type() == holder->type()) {
|
||||
uint8_t* backing_store =
|
||||
static_cast<uint8_t*>(
|
||||
JSArrayBuffer::cast(typed_array->buffer())->backing_store());
|
||||
typed_array->GetBuffer()->backing_store());
|
||||
size_t source_byte_offset =
|
||||
NumberToSize(isolate, typed_array->byte_offset());
|
||||
memcpy(
|
||||
@ -1107,13 +1142,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
|
||||
return typed_array->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_TypedArrayGetBuffer) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0);
|
||||
if (!holder->IsJSTypedArray())
|
||||
return isolate->Throw(*isolate->factory()->NewTypeError(
|
||||
"not_typed_array", HandleVector<Object>(NULL, 0)));
|
||||
Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder));
|
||||
return *typed_array->GetBuffer();
|
||||
}
|
||||
|
||||
|
||||
// Return codes for Runtime_TypedArraySetFastCases.
|
||||
// Should be synchronized with typedarray.js natives.
|
||||
enum TypedArraySetResultCodes {
|
||||
@ -1159,10 +1205,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) {
|
||||
size_t source_offset = NumberToSize(isolate, source->byte_offset());
|
||||
uint8_t* target_base =
|
||||
static_cast<uint8_t*>(
|
||||
JSArrayBuffer::cast(target->buffer())->backing_store()) + target_offset;
|
||||
target->GetBuffer()->backing_store()) + target_offset;
|
||||
uint8_t* source_base =
|
||||
static_cast<uint8_t*>(
|
||||
JSArrayBuffer::cast(source->buffer())->backing_store()) + source_offset;
|
||||
source->GetBuffer()->backing_store()) + source_offset;
|
||||
|
||||
// Typed arrays of the same type: use memmove.
|
||||
if (target->type() == source->type()) {
|
||||
@ -1178,8 +1224,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) {
|
||||
target_base + target_byte_length > source_base)) {
|
||||
// We do not support overlapping ArrayBuffers
|
||||
ASSERT(
|
||||
JSArrayBuffer::cast(target->buffer())->backing_store() ==
|
||||
JSArrayBuffer::cast(source->buffer())->backing_store());
|
||||
target->GetBuffer()->backing_store() ==
|
||||
source->GetBuffer()->backing_store());
|
||||
return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
|
||||
} else { // Non-overlapping typed arrays
|
||||
return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
|
||||
@ -1187,6 +1233,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayMaxSizeInHeap) {
|
||||
ASSERT_OBJECT_SIZE(FLAG_typed_array_max_size_in_heap);
|
||||
return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 4);
|
||||
@ -14739,6 +14791,17 @@ TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
|
||||
#undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
|
||||
|
||||
|
||||
#define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_HasFixed##Type##Elements) { \
|
||||
CONVERT_ARG_CHECKED(JSObject, obj, 0); \
|
||||
return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \
|
||||
}
|
||||
|
||||
TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
|
||||
|
||||
#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
|
||||
SealHandleScope shs(isolate);
|
||||
ASSERT(args.length() == 2);
|
||||
|
@ -468,6 +468,15 @@ namespace internal {
|
||||
F(HasExternalUint32Elements, 1, 1) \
|
||||
F(HasExternalFloat32Elements, 1, 1) \
|
||||
F(HasExternalFloat64Elements, 1, 1) \
|
||||
F(HasFixedUint8ClampedElements, 1, 1) \
|
||||
F(HasFixedInt8Elements, 1, 1) \
|
||||
F(HasFixedUint8Elements, 1, 1) \
|
||||
F(HasFixedInt16Elements, 1, 1) \
|
||||
F(HasFixedUint16Elements, 1, 1) \
|
||||
F(HasFixedInt32Elements, 1, 1) \
|
||||
F(HasFixedUint32Elements, 1, 1) \
|
||||
F(HasFixedFloat32Elements, 1, 1) \
|
||||
F(HasFixedFloat64Elements, 1, 1) \
|
||||
F(HasFastProperties, 1, 1) \
|
||||
F(TransitionElementsKind, 2, 1) \
|
||||
F(HaveSameMap, 2, 1) \
|
||||
@ -676,7 +685,8 @@ namespace internal {
|
||||
F(ConstructDouble, 2, 1) \
|
||||
F(TypedArrayInitialize, 5, 1) \
|
||||
F(DataViewInitialize, 4, 1) \
|
||||
F(MaxSmi, 0, 1)
|
||||
F(MaxSmi, 0, 1) \
|
||||
F(TypedArrayMaxSizeInHeap, 0, 1)
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -868,7 +878,10 @@ class Runtime : public AllStatic {
|
||||
};
|
||||
|
||||
static void ArrayIdToTypeAndSize(int array_id,
|
||||
ExternalArrayType *type, size_t *element_size);
|
||||
ExternalArrayType *type,
|
||||
ElementsKind* external_elements_kind,
|
||||
ElementsKind* fixed_elements_kind,
|
||||
size_t *element_size);
|
||||
|
||||
// Helper functions used stubs.
|
||||
static void PerformGC(Object* result, Isolate* isolate);
|
||||
|
@ -100,8 +100,12 @@ macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
|
||||
throw MakeRangeError("invalid_typed_array_length");
|
||||
}
|
||||
var byteLength = l * ELEMENT_SIZE;
|
||||
var buffer = new $ArrayBuffer(byteLength);
|
||||
%_TypedArrayInitialize(obj, ARRAY_ID, buffer, 0, byteLength);
|
||||
if (byteLength > %_TypedArrayMaxSizeInHeap()) {
|
||||
var buffer = new $ArrayBuffer(byteLength);
|
||||
%_TypedArrayInitialize(obj, ARRAY_ID, buffer, 0, byteLength);
|
||||
} else {
|
||||
%_TypedArrayInitialize(obj, ARRAY_ID, null, 0, byteLength);
|
||||
}
|
||||
}
|
||||
|
||||
function NAMEConstructByArrayLike(obj, arrayLike) {
|
||||
|
@ -25,7 +25,7 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc --nostress-opt
|
||||
// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc --nostress-opt --typed-array-max_size_in-heap=2048
|
||||
|
||||
// Test element kind of objects.
|
||||
// Since --smi-only-arrays affects builtins, its default setting at compile
|
||||
@ -43,19 +43,28 @@ if (support_smi_only_arrays) {
|
||||
}
|
||||
|
||||
var elements_kind = {
|
||||
fast_smi_only : 'fast smi only elements',
|
||||
fast : 'fast elements',
|
||||
fast_double : 'fast double elements',
|
||||
dictionary : 'dictionary elements',
|
||||
external_byte : 'external byte elements',
|
||||
external_unsigned_byte : 'external unsigned byte elements',
|
||||
external_short : 'external short elements',
|
||||
external_unsigned_short : 'external unsigned short elements',
|
||||
external_int : 'external int elements',
|
||||
external_unsigned_int : 'external unsigned int elements',
|
||||
external_float : 'external float elements',
|
||||
external_double : 'external double elements',
|
||||
external_pixel : 'external pixel elements'
|
||||
fast_smi_only : 'fast smi only elements',
|
||||
fast : 'fast elements',
|
||||
fast_double : 'fast double elements',
|
||||
dictionary : 'dictionary elements',
|
||||
external_int32 : 'external int8 elements',
|
||||
external_uint8 : 'external uint8 elements',
|
||||
external_int16 : 'external int16 elements',
|
||||
external_uint16 : 'external uint16 elements',
|
||||
external_int32 : 'external int32 elements',
|
||||
external_uint32 : 'external uint32 elements',
|
||||
external_float32 : 'external float32 elements',
|
||||
external_float64 : 'external float64 elements',
|
||||
external_uint8_clamped : 'external uint8_clamped elements',
|
||||
fixed_int32 : 'fixed int8 elements',
|
||||
fixed_uint8 : 'fixed uint8 elements',
|
||||
fixed_int16 : 'fixed int16 elements',
|
||||
fixed_uint16 : 'fixed uint16 elements',
|
||||
fixed_int32 : 'fixed int32 elements',
|
||||
fixed_uint32 : 'fixed uint32 elements',
|
||||
fixed_float32 : 'fixed float32 elements',
|
||||
fixed_float64 : 'fixed float64 elements',
|
||||
fixed_uint8_clamped : 'fixed uint8_clamped elements'
|
||||
}
|
||||
|
||||
function getKind(obj) {
|
||||
@ -63,34 +72,61 @@ function getKind(obj) {
|
||||
if (%HasFastObjectElements(obj)) return elements_kind.fast;
|
||||
if (%HasFastDoubleElements(obj)) return elements_kind.fast_double;
|
||||
if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
|
||||
|
||||
// Every external kind is also an external array.
|
||||
assertTrue(%HasExternalArrayElements(obj));
|
||||
if (%HasExternalInt8Elements(obj)) {
|
||||
return elements_kind.external_byte;
|
||||
return elements_kind.external_int8;
|
||||
}
|
||||
if (%HasExternalUint8Elements(obj)) {
|
||||
return elements_kind.external_unsigned_byte;
|
||||
return elements_kind.external_uint8;
|
||||
}
|
||||
if (%HasExternalInt16Elements(obj)) {
|
||||
return elements_kind.external_short;
|
||||
return elements_kind.external_int16;
|
||||
}
|
||||
if (%HasExternalUint16Elements(obj)) {
|
||||
return elements_kind.external_unsigned_short;
|
||||
return elements_kind.external_uint16;
|
||||
}
|
||||
if (%HasExternalInt32Elements(obj)) {
|
||||
return elements_kind.external_int;
|
||||
return elements_kind.external_int32;
|
||||
}
|
||||
if (%HasExternalUint32Elements(obj)) {
|
||||
return elements_kind.external_unsigned_int;
|
||||
return elements_kind.external_uint32;
|
||||
}
|
||||
if (%HasExternalFloat32Elements(obj)) {
|
||||
return elements_kind.external_float;
|
||||
return elements_kind.external_float32;
|
||||
}
|
||||
if (%HasExternalFloat64Elements(obj)) {
|
||||
return elements_kind.external_double;
|
||||
return elements_kind.external_float64;
|
||||
}
|
||||
if (%HasExternalUint8ClampedElements(obj)) {
|
||||
return elements_kind.external_pixel;
|
||||
return elements_kind.external_uint8_clamped;
|
||||
}
|
||||
if (%HasFixedInt8Elements(obj)) {
|
||||
return elements_kind.fixed_int8;
|
||||
}
|
||||
if (%HasFixedUint8Elements(obj)) {
|
||||
return elements_kind.fixed_uint8;
|
||||
}
|
||||
if (%HasFixedInt16Elements(obj)) {
|
||||
return elements_kind.fixed_int16;
|
||||
}
|
||||
if (%HasFixedUint16Elements(obj)) {
|
||||
return elements_kind.fixed_uint16;
|
||||
}
|
||||
if (%HasFixedInt32Elements(obj)) {
|
||||
return elements_kind.fixed_int32;
|
||||
}
|
||||
if (%HasFixedUint32Elements(obj)) {
|
||||
return elements_kind.fixed_uint32;
|
||||
}
|
||||
if (%HasFixedFloat32Elements(obj)) {
|
||||
return elements_kind.fixed_float32;
|
||||
}
|
||||
if (%HasFixedFloat64Elements(obj)) {
|
||||
return elements_kind.fixed_float64;
|
||||
}
|
||||
if (%HasFixedUint8ClampedElements(obj)) {
|
||||
return elements_kind.fixed_uint8_clamped;
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,15 +172,26 @@ function test_wrapper() {
|
||||
for (var i = 0; i < 0xDECAF; i++) fast_double_array[i] = i / 2;
|
||||
assertKind(elements_kind.fast_double, fast_double_array);
|
||||
|
||||
assertKind(elements_kind.external_byte, new Int8Array(9001));
|
||||
assertKind(elements_kind.external_unsigned_byte, new Uint8Array(007));
|
||||
assertKind(elements_kind.external_short, new Int16Array(666));
|
||||
assertKind(elements_kind.external_unsigned_short, new Uint16Array(42));
|
||||
assertKind(elements_kind.external_int, new Int32Array(0xF));
|
||||
assertKind(elements_kind.external_unsigned_int, new Uint32Array(23));
|
||||
assertKind(elements_kind.external_float, new Float32Array(7));
|
||||
assertKind(elements_kind.external_double, new Float64Array(0));
|
||||
assertKind(elements_kind.external_pixel, new Uint8ClampedArray(512));
|
||||
assertKind(elements_kind.fixed_int8, new Int8Array(007));
|
||||
assertKind(elements_kind.fixed_uint8, new Uint8Array(007));
|
||||
assertKind(elements_kind.fixed_int16, new Int16Array(666));
|
||||
assertKind(elements_kind.fixed_uint16, new Uint16Array(42));
|
||||
assertKind(elements_kind.fixed_int32, new Int32Array(0xF));
|
||||
assertKind(elements_kind.fixed_uint32, new Uint32Array(23));
|
||||
assertKind(elements_kind.fixed_float32, new Float32Array(7));
|
||||
assertKind(elements_kind.fixed_float64, new Float64Array(0));
|
||||
assertKind(elements_kind.fixed_uint8_clamped, new Uint8ClampedArray(512));
|
||||
|
||||
var ab = new ArrayBuffer(128);
|
||||
assertKind(elements_kind.external_int8, new Int8Array(ab));
|
||||
assertKind(elements_kind.external_uint8, new Uint8Array(ab));
|
||||
assertKind(elements_kind.external_int16, new Int16Array(ab));
|
||||
assertKind(elements_kind.external_uint16, new Uint16Array(ab));
|
||||
assertKind(elements_kind.external_int32, new Int32Array(ab));
|
||||
assertKind(elements_kind.external_uint32, new Uint32Array(ab));
|
||||
assertKind(elements_kind.external_float32, new Float32Array(ab));
|
||||
assertKind(elements_kind.external_float64, new Float64Array(ab));
|
||||
assertKind(elements_kind.external_uint8_clamped, new Uint8ClampedArray(ab));
|
||||
|
||||
// Crankshaft support for smi-only array elements.
|
||||
function monomorphic(array) {
|
||||
|
@ -530,6 +530,7 @@ assertThrows(function() { ArrayBuffer.apply(null, [1000]); }, TypeError);
|
||||
assertThrows(function() { Float32Array.apply(null, [b, 128, 1]); }, TypeError);
|
||||
|
||||
// Test array.set in different combinations.
|
||||
var b = new ArrayBuffer(4)
|
||||
|
||||
function assertArrayPrefix(expected, array) {
|
||||
for (var i = 0; i < expected.length; ++i) {
|
||||
|
Loading…
Reference in New Issue
Block a user