static const int kNodeIsIndependentShift = 3;
static const int kNodeIsPartiallyDependentShift = 4;
- static const int kJSObjectType = 0xb6;
+ static const int kJSObjectType = 0xbf;
static const int kFirstNonstringType = 0x80;
static const int kOddballType = 0x83;
static const int kForeignType = 0x87;
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LInstruction* result = NULL;
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
LOperand* obj = NULL;
if (instr->representation().IsDouble()) {
obj = UseRegister(instr->elements());
}
bool needs_environment;
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_external() || instr->is_fixed_typed_array()) {
// see LCodeGen::DoLoadKeyedExternalArray
- needs_environment = elements_kind == UINT32_ELEMENTS &&
+ needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) &&
!instr->CheckFlag(HInstruction::kUint32);
} else {
// see LCodeGen::DoLoadKeyedFixedDoubleArray and
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
DCHECK(instr->elements()->representation().IsTagged());
bool needs_write_barrier = instr->NeedsWriteBarrier();
LOperand* object = NULL;
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ bool is_external() const {
+ return hydrogen()->is_external();
+ }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
inputs_[2] = value;
}
+ bool is_external() const { return hydrogen()->is_external(); }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
? (element_size_shift - kSmiTagSize) : element_size_shift;
int base_offset = instr->base_offset();
- if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
DwVfpRegister result = ToDoubleRegister(instr->result());
Operand operand = key_is_constant
? Operand(constant_key << element_size_shift)
: Operand(key, LSL, shift_size);
__ add(scratch0(), external_pointer, operand);
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
__ vldr(double_scratch0().low(), scratch0(), base_offset);
__ vcvt_f64_f32(result, double_scratch0().low());
} else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
key, external_pointer, key_is_constant, constant_key,
element_size_shift, shift_size, base_offset);
switch (elements_kind) {
+ case EXTERNAL_INT8_ELEMENTS:
case INT8_ELEMENTS:
__ ldrsb(result, mem_operand);
break;
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
__ ldrb(result, mem_operand);
break;
+ case EXTERNAL_INT16_ELEMENTS:
case INT16_ELEMENTS:
__ ldrsh(result, mem_operand);
break;
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
__ ldrh(result, mem_operand);
break;
+ case EXTERNAL_INT32_ELEMENTS:
case INT32_ELEMENTS:
__ ldr(result, mem_operand);
break;
+ case EXTERNAL_UINT32_ELEMENTS:
case UINT32_ELEMENTS:
__ ldr(result, mem_operand);
if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
break;
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoLoadKeyedExternalArray(instr);
} else if (instr->hydrogen()->representation().IsDouble()) {
DoLoadKeyedFixedDoubleArray(instr);
? (element_size_shift - kSmiTagSize) : element_size_shift;
int base_offset = instr->base_offset();
- if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
Register address = scratch0();
DwVfpRegister value(ToDoubleRegister(instr->value()));
if (key_is_constant) {
} else {
__ add(address, external_pointer, Operand(key, LSL, shift_size));
}
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
__ vcvt_f32_f64(double_scratch0().low(), value);
__ vstr(double_scratch0().low(), address, base_offset);
} else { // Storing doubles, not floats.
element_size_shift, shift_size,
base_offset);
switch (elements_kind) {
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_INT8_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
case INT8_ELEMENTS:
__ strb(value, mem_operand);
break;
+ case EXTERNAL_INT16_ELEMENTS:
+ case EXTERNAL_UINT16_ELEMENTS:
case INT16_ELEMENTS:
case UINT16_ELEMENTS:
__ strh(value, mem_operand);
break;
+ case EXTERNAL_INT32_ELEMENTS:
+ case EXTERNAL_UINT32_ELEMENTS:
case INT32_ELEMENTS:
case UINT32_ELEMENTS:
__ str(value, mem_operand);
break;
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
// By cases: external, fast double
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoStoreKeyedExternalArray(instr);
} else if (instr->hydrogen()->value()->representation().IsDouble()) {
DoStoreKeyedFixedDoubleArray(instr);
LOperand* elements = UseRegister(instr->elements());
LOperand* key = UseRegisterOrConstant(instr->key());
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
if (instr->representation().IsDouble()) {
LOperand* temp = (!instr->key()->IsConstant() ||
instr->RequiresHoleCheck())
LOperand* temp = instr->key()->IsConstant() ? NULL : TempRegister();
LInstruction* result = DefineAsRegister(
new(zone()) LLoadKeyedExternal(elements, key, temp));
- if (elements_kind == UINT32_ELEMENTS &&
+ if ((elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) &&
!instr->CheckFlag(HInstruction::kUint32)) {
result = AssignEnvironment(result);
}
LOperand* elements = NULL;
LOperand* val = NULL;
- if (!instr->is_fixed_typed_array() &&
+ if (!instr->is_typed_elements() &&
instr->value()->representation().IsTagged() &&
instr->NeedsWriteBarrier()) {
// RecordWrite() will clobber all registers.
temp = instr->key()->IsConstant() ? NULL : TempRegister();
}
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DCHECK((instr->value()->representation().IsInteger32() &&
!IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
(instr->value()->representation().IsDouble() &&
elements_kind,
instr->base_offset());
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if ((elements_kind == EXTERNAL_FLOAT32_ELEMENTS) ||
+ (elements_kind == FLOAT32_ELEMENTS)) {
DoubleRegister result = ToDoubleRegister(instr->result());
__ Ldr(result.S(), mem_op);
__ Fcvt(result, result.S());
- } else if (elements_kind == FLOAT64_ELEMENTS) {
+ } else if ((elements_kind == EXTERNAL_FLOAT64_ELEMENTS) ||
+ (elements_kind == FLOAT64_ELEMENTS)) {
DoubleRegister result = ToDoubleRegister(instr->result());
__ Ldr(result, mem_op);
} else {
Register result = ToRegister(instr->result());
switch (elements_kind) {
+ case EXTERNAL_INT8_ELEMENTS:
case INT8_ELEMENTS:
__ Ldrsb(result, mem_op);
break;
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
__ Ldrb(result, mem_op);
break;
+ case EXTERNAL_INT16_ELEMENTS:
case INT16_ELEMENTS:
__ Ldrsh(result, mem_op);
break;
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
__ Ldrh(result, mem_op);
break;
+ case EXTERNAL_INT32_ELEMENTS:
case INT32_ELEMENTS:
__ Ldrsw(result, mem_op);
break;
+ case EXTERNAL_UINT32_ELEMENTS:
case UINT32_ELEMENTS:
__ Ldr(result.W(), mem_op);
if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
break;
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
elements_kind,
instr->base_offset());
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if ((elements_kind == EXTERNAL_FLOAT32_ELEMENTS) ||
+ (elements_kind == FLOAT32_ELEMENTS)) {
DoubleRegister value = ToDoubleRegister(instr->value());
DoubleRegister dbl_scratch = double_scratch();
__ Fcvt(dbl_scratch.S(), value);
__ Str(dbl_scratch.S(), dst);
- } else if (elements_kind == FLOAT64_ELEMENTS) {
+ } else if ((elements_kind == EXTERNAL_FLOAT64_ELEMENTS) ||
+ (elements_kind == FLOAT64_ELEMENTS)) {
DoubleRegister value = ToDoubleRegister(instr->value());
__ Str(value, dst);
} else {
Register value = ToRegister(instr->value());
switch (elements_kind) {
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_INT8_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
case INT8_ELEMENTS:
__ Strb(value, dst);
break;
+ case EXTERNAL_INT16_ELEMENTS:
+ case EXTERNAL_UINT16_ELEMENTS:
case INT16_ELEMENTS:
case UINT16_ELEMENTS:
__ Strh(value, dst);
break;
+ case EXTERNAL_INT32_ELEMENTS:
+ case EXTERNAL_UINT32_ELEMENTS:
case INT32_ELEMENTS:
case UINT32_ELEMENTS:
__ Str(value.W(), dst);
break;
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
ElementsKind elements_kind);
bool InstallNatives(ContextType context_type);
- void InstallTypedArray(const char* name, ElementsKind elements_kind,
- Handle<JSFunction>* fun);
+ void InstallTypedArray(
+ const char* name,
+ ElementsKind elements_kind,
+ Handle<JSFunction>* fun,
+ Handle<Map>* external_map);
bool InstallExperimentalNatives();
bool InstallExtraNatives();
void InstallBuiltinFunctionIds();
}
{ // -- T y p e d A r r a y s
-#define INSTALL_TYPED_ARRAY(Type, type, TYPE, ctype, size) \
- { \
- Handle<JSFunction> fun; \
- InstallTypedArray(#Type "Array", TYPE##_ELEMENTS, &fun); \
- native_context()->set_##type##_array_fun(*fun); \
- }
+#define INSTALL_TYPED_ARRAY(Type, type, TYPE, ctype, size) \
+ { \
+ Handle<JSFunction> fun; \
+ Handle<Map> external_map; \
+ InstallTypedArray(#Type "Array", \
+ TYPE##_ELEMENTS, \
+ &fun, \
+ &external_map); \
+ native_context()->set_##type##_array_fun(*fun); \
+ native_context()->set_##type##_array_external_map(*external_map); \
+ }
TYPED_ARRAYS(INSTALL_TYPED_ARRAY)
#undef INSTALL_TYPED_ARRAY
}
-void Genesis::InstallTypedArray(const char* name, ElementsKind elements_kind,
- Handle<JSFunction>* fun) {
+void Genesis::InstallTypedArray(
+ const char* name,
+ ElementsKind elements_kind,
+ Handle<JSFunction>* fun,
+ Handle<Map>* external_map) {
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
Handle<JSFunction> result = InstallFunction(
global, name, JS_TYPED_ARRAY_TYPE, JSTypedArray::kSize,
JSFunction::SetInitialMap(result, initial_map,
handle(initial_map->prototype(), isolate()));
*fun = result;
+
+ ElementsKind external_kind = GetNextTransitionElementsKind(elements_kind);
+ *external_map = Map::AsElementsKind(initial_map, external_kind);
}
HValue* bit_field2,
ElementsKind kind);
+ void BuildExternalElementLoad(HGraphBuilder::IfBuilder* if_builder,
+ HValue* receiver,
+ HValue* key,
+ HValue* instance_type,
+ HValue* bit_field2,
+ ElementsKind kind);
+
KeyedLoadGenericStub* casted_stub() {
return static_cast<KeyedLoadGenericStub*>(stub());
}
void CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildFastElementLoad(
HGraphBuilder::IfBuilder* if_builder, HValue* receiver, HValue* key,
HValue* instance_type, HValue* bit_field2, ElementsKind kind) {
+ DCHECK(!IsExternalArrayElementsKind(kind));
+
BuildElementsKindLimitCheck(if_builder, bit_field2, kind);
IfBuilder js_array_check(this);
}
+void CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildExternalElementLoad(
+ HGraphBuilder::IfBuilder* if_builder, HValue* receiver, HValue* key,
+ HValue* instance_type, HValue* bit_field2, ElementsKind kind) {
+ DCHECK(IsExternalArrayElementsKind(kind));
+
+ BuildElementsKindLimitCheck(if_builder, bit_field2, kind);
+
+ Push(BuildUncheckedMonomorphicElementAccess(receiver, key, NULL,
+ false, kind,
+ LOAD, NEVER_RETURN_HOLE,
+ STANDARD_STORE));
+}
+
+
HValue* CodeStubGraphBuilder<KeyedLoadGenericStub>::BuildCodeStub() {
HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex);
HValue* key = GetParameter(LoadDescriptor::kNameIndex);
Deoptimizer::EAGER);
Push(graph()->GetConstant0());
+ kind_if.Else();
+ BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2,
+ EXTERNAL_INT8_ELEMENTS);
+
+ kind_if.Else();
+ BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2,
+ EXTERNAL_UINT8_ELEMENTS);
+
+ kind_if.Else();
+ BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2,
+ EXTERNAL_INT16_ELEMENTS);
+
+ kind_if.Else();
+ BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2,
+ EXTERNAL_UINT16_ELEMENTS);
+
+ kind_if.Else();
+ BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2,
+ EXTERNAL_INT32_ELEMENTS);
+
+ kind_if.Else();
+ BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2,
+ EXTERNAL_UINT32_ELEMENTS);
+
+ kind_if.Else();
+ BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2,
+ EXTERNAL_FLOAT32_ELEMENTS);
+
+ kind_if.Else();
+ BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2,
+ EXTERNAL_FLOAT64_ELEMENTS);
+
+ kind_if.Else();
+ BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2,
+ EXTERNAL_UINT8_CLAMPED_ELEMENTS);
+
kind_if.ElseDeopt(
Deoptimizer::kElementsKindUnhandledInKeyedLoadGenericStub);
index->ClearFlag(HValue::kCanOverflow);
HValue* property_index =
Add<HLoadKeyed>(cache_field_offsets, index, nullptr,
- INT32_ELEMENTS, NEVER_RETURN_HOLE, 0);
+ EXTERNAL_INT32_ELEMENTS, NEVER_RETURN_HOLE, 0);
Push(property_index);
}
lookup_if->Else();
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS:
TYPED_ARRAYS(TYPED_ARRAY_CASE)
}
+// static
+FieldAccess AccessBuilder::ForExternalArrayPointer() {
+ FieldAccess access = {kTaggedBase, ExternalArray::kExternalPointerOffset,
+ MaybeHandle<Name>(), Type::UntaggedPointer(), kMachPtr};
+ return access;
+}
+
+
// static
FieldAccess AccessBuilder::ForDescriptorArrayEnumCache() {
FieldAccess access = {kTaggedBase, DescriptorArray::kEnumCacheOffset,
// Provides access to FixedArray::length() field.
static FieldAccess ForFixedArrayLength();
+ // Provides access to ExternalArray::external_pointer() field.
+ static FieldAccess ForExternalArrayPointer();
+
// Provides access to DescriptorArray::enum_cache() field.
static FieldAccess ForDescriptorArrayEnumCache();
size_t const k = ElementSizeLog2Of(access.machine_type());
double const byte_length = array->byte_length()->Number();
CHECK_LT(k, arraysize(shifted_int32_ranges_));
- if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
+ if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
+ key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
// JSLoadProperty(typed-array, int32)
- Handle<FixedTypedArrayBase> elements =
- Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
+ Handle<ExternalArray> elements =
+ Handle<ExternalArray>::cast(handle(array->elements()));
Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
Node* length = jsgraph()->Constant(byte_length);
Node* effect = NodeProperties::GetEffectInput(node);
size_t const k = ElementSizeLog2Of(access.machine_type());
double const byte_length = array->byte_length()->Number();
CHECK_LT(k, arraysize(shifted_int32_ranges_));
- if (access.external_array_type() != kExternalUint8ClampedArray &&
+ if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
+ access.external_array_type() != kExternalUint8ClampedArray &&
key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
// JSLoadProperty(typed-array, int32)
- Handle<FixedTypedArrayBase> elements =
- Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
+ Handle<ExternalArray> elements =
+ Handle<ExternalArray>::cast(handle(array->elements()));
Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
Node* length = jsgraph()->Constant(byte_length);
Node* context = NodeProperties::GetContextInput(node);
V(FLOAT32_ARRAY_FUN_INDEX, JSFunction, float32_array_fun) \
V(FLOAT64_ARRAY_FUN_INDEX, JSFunction, float64_array_fun) \
V(UINT8_CLAMPED_ARRAY_FUN_INDEX, JSFunction, uint8_clamped_array_fun) \
+ V(INT8_ARRAY_EXTERNAL_MAP_INDEX, Map, int8_array_external_map) \
+ V(UINT8_ARRAY_EXTERNAL_MAP_INDEX, Map, uint8_array_external_map) \
+ V(INT16_ARRAY_EXTERNAL_MAP_INDEX, Map, int16_array_external_map) \
+ V(UINT16_ARRAY_EXTERNAL_MAP_INDEX, Map, uint16_array_external_map) \
+ V(INT32_ARRAY_EXTERNAL_MAP_INDEX, Map, int32_array_external_map) \
+ V(UINT32_ARRAY_EXTERNAL_MAP_INDEX, Map, uint32_array_external_map) \
+ V(FLOAT32_ARRAY_EXTERNAL_MAP_INDEX, Map, float32_array_external_map) \
+ V(FLOAT64_ARRAY_EXTERNAL_MAP_INDEX, Map, float64_array_external_map) \
+ V(UINT8_CLAMPED_ARRAY_EXTERNAL_MAP_INDEX, Map, \
+ uint8_clamped_array_external_map) \
V(DATA_VIEW_FUN_INDEX, JSFunction, data_view_fun) \
V(SLOPPY_FUNCTION_MAP_INDEX, Map, sloppy_function_map) \
V(SLOPPY_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX, Map, \
int ElementsKindToShiftSize(ElementsKind elements_kind) {
switch (elements_kind) {
+ case EXTERNAL_INT8_ELEMENTS:
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case INT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
return 0;
+ case EXTERNAL_INT16_ELEMENTS:
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
case INT16_ELEMENTS:
return 1;
+ case EXTERNAL_INT32_ELEMENTS:
+ case EXTERNAL_UINT32_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
case UINT32_ELEMENTS:
case INT32_ELEMENTS:
case FLOAT32_ELEMENTS:
return 2;
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case FLOAT64_ELEMENTS:
}
+static bool IsTypedArrayElementsKind(ElementsKind elements_kind) {
+ return IsFixedTypedArrayElementsKind(elements_kind) ||
+ IsExternalArrayElementsKind(elements_kind);
+}
+
+
int GetDefaultHeaderSizeForElementsKind(ElementsKind elements_kind) {
STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
- if (IsFixedTypedArrayElementsKind(elements_kind)) {
+ if (IsTypedArrayElementsKind(elements_kind)) {
return 0;
} else {
return FixedArray::kHeaderSize - kHeapObjectTag;
ElementsKind GetNextTransitionElementsKind(ElementsKind kind) {
- int index = GetSequenceIndexFromFastElementsKind(kind);
- return GetFastElementsKindFromSequenceIndex(index + 1);
+ 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);
+ }
+ }
}
bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
ElementsKind to_kind) {
- if (IsFixedTypedArrayElementsKind(from_kind) ||
- IsFixedTypedArrayElementsKind(to_kind)) {
- return false;
+ if (IsTypedArrayElementsKind(from_kind) ||
+ IsTypedArrayElementsKind(to_kind)) {
+ switch (from_kind) {
+#define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case TYPE##_ELEMENTS: \
+ return to_kind == EXTERNAL_##TYPE##_ELEMENTS;
+
+ TYPED_ARRAYS(FIXED_TYPED_ARRAY_CASE);
+#undef FIXED_TYPED_ARRAY_CASE
+ default:
+ return false;
+ }
}
if (IsFastElementsKind(from_kind) && IsFastTransitionTarget(to_kind)) {
switch (from_kind) {
FAST_SLOPPY_ARGUMENTS_ELEMENTS,
SLOW_SLOPPY_ARGUMENTS_ELEMENTS,
+ // The "fast" kind for external arrays
+ EXTERNAL_INT8_ELEMENTS,
+ EXTERNAL_UINT8_ELEMENTS,
+ EXTERNAL_INT16_ELEMENTS,
+ EXTERNAL_UINT16_ELEMENTS,
+ EXTERNAL_INT32_ELEMENTS,
+ EXTERNAL_UINT32_ELEMENTS,
+ EXTERNAL_FLOAT32_ELEMENTS,
+ EXTERNAL_FLOAT64_ELEMENTS,
+ EXTERNAL_UINT8_CLAMPED_ELEMENTS,
+
// Fixed typed arrays
UINT8_ELEMENTS,
INT8_ELEMENTS,
LAST_ELEMENTS_KIND = UINT8_CLAMPED_ELEMENTS,
FIRST_FAST_ELEMENTS_KIND = FAST_SMI_ELEMENTS,
LAST_FAST_ELEMENTS_KIND = FAST_HOLEY_DOUBLE_ELEMENTS,
+ FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_INT8_ELEMENTS,
+ LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_UINT8_CLAMPED_ELEMENTS,
FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = UINT8_ELEMENTS,
LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = UINT8_CLAMPED_ELEMENTS,
TERMINAL_FAST_ELEMENTS_KIND = FAST_HOLEY_ELEMENTS
}
-inline bool IsFixedTypedArrayElementsKind(ElementsKind kind) {
- return kind >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND &&
- kind <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND;
+inline bool IsExternalArrayElementsKind(ElementsKind kind) {
+ return kind >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
+ kind <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND;
}
inline bool IsTerminalElementsKind(ElementsKind kind) {
return kind == TERMINAL_FAST_ELEMENTS_KIND ||
- IsFixedTypedArrayElementsKind(kind);
+ IsExternalArrayElementsKind(kind);
+}
+
+
+inline bool IsFixedTypedArrayElementsKind(ElementsKind kind) {
+ return kind >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND &&
+ kind <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND;
}
}
+inline bool IsExternalFloatOrDoubleElementsKind(ElementsKind kind) {
+ return kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ kind == EXTERNAL_FLOAT32_ELEMENTS;
+}
+
+
inline bool IsFixedFloatElementsKind(ElementsKind kind) {
return kind == FLOAT32_ELEMENTS || kind == FLOAT64_ELEMENTS;
}
inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) {
- return IsFastDoubleElementsKind(kind) || IsFixedFloatElementsKind(kind);
+ return IsFastDoubleElementsKind(kind) ||
+ IsExternalFloatOrDoubleElementsKind(kind) ||
+ IsFixedFloatElementsKind(kind);
}
// - FastPackedDoubleElementsAccessor
// - FastHoleyDoubleElementsAccessor
// - TypedElementsAccessor: template, with instantiations:
+// - ExternalInt8ElementsAccessor
+// - ExternalUint8ElementsAccessor
+// - ExternalInt16ElementsAccessor
+// - ExternalUint16ElementsAccessor
+// - ExternalInt32ElementsAccessor
+// - ExternalUint32ElementsAccessor
+// - ExternalFloat32ElementsAccessor
+// - ExternalFloat64ElementsAccessor
+// - ExternalUint8ClampedElementsAccessor
// - FixedUint8ElementsAccessor
// - FixedInt8ElementsAccessor
// - FixedUint16ElementsAccessor
FixedArray) \
V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS, \
FixedArray) \
+ V(ExternalInt8ElementsAccessor, EXTERNAL_INT8_ELEMENTS, ExternalInt8Array) \
+ V(ExternalUint8ElementsAccessor, EXTERNAL_UINT8_ELEMENTS, \
+ ExternalUint8Array) \
+ V(ExternalInt16ElementsAccessor, EXTERNAL_INT16_ELEMENTS, \
+ ExternalInt16Array) \
+ V(ExternalUint16ElementsAccessor, EXTERNAL_UINT16_ELEMENTS, \
+ ExternalUint16Array) \
+ V(ExternalInt32ElementsAccessor, EXTERNAL_INT32_ELEMENTS, \
+ ExternalInt32Array) \
+ V(ExternalUint32ElementsAccessor, EXTERNAL_UINT32_ELEMENTS, \
+ ExternalUint32Array) \
+ V(ExternalFloat32ElementsAccessor, EXTERNAL_FLOAT32_ELEMENTS, \
+ ExternalFloat32Array) \
+ V(ExternalFloat64ElementsAccessor, EXTERNAL_FLOAT64_ELEMENTS, \
+ ExternalFloat64Array) \
+ V(ExternalUint8ClampedElementsAccessor, EXTERNAL_UINT8_CLAMPED_ELEMENTS, \
+ ExternalUint8ClampedArray) \
V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array) \
V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array) \
V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array) \
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
UNREACHABLE();
TYPED_ARRAYS(TYPED_ARRAY_CASE)
UNREACHABLE();
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
UNREACHABLE();
TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#define EXTERNAL_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
+ typedef TypedElementsAccessor<EXTERNAL_##TYPE##_ELEMENTS> \
+ External##Type##ElementsAccessor;
+
+TYPED_ARRAYS(EXTERNAL_ELEMENTS_ACCESSOR)
+#undef EXTERNAL_ELEMENTS_ACCESSOR
+
#define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
typedef TypedElementsAccessor<TYPE##_ELEMENTS > \
Fixed##Type##ElementsAccessor;
}
-Handle<FixedTypedArrayBase> Factory::NewFixedTypedArrayWithExternalPointer(
- int length, ExternalArrayType array_type, void* external_pointer,
- PretenureFlag pretenure) {
+Handle<ExternalArray> Factory::NewExternalArray(int length,
+ ExternalArrayType array_type,
+ void* external_pointer,
+ PretenureFlag pretenure) {
DCHECK(0 <= length && length <= Smi::kMaxValue);
CALL_HEAP_FUNCTION(
- isolate(), isolate()->heap()->AllocateFixedTypedArrayWithExternalPointer(
- length, array_type, external_pointer, pretenure),
- FixedTypedArrayBase);
+ isolate(),
+ isolate()->heap()->AllocateExternalArray(length,
+ array_type,
+ external_pointer,
+ pretenure),
+ ExternalArray);
}
switch (type) {
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case kExternal##Type##Array: \
- return TYPE##_ELEMENTS;
+ return EXTERNAL_##TYPE##_ELEMENTS;
TYPED_ARRAYS(TYPED_ARRAY_CASE)
}
UNREACHABLE();
- return FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND;
+ return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND;
#undef TYPED_ARRAY_CASE
}
Handle<Object> length_object = NewNumberFromSize(length);
obj->set_length(*length_object);
- Handle<FixedTypedArrayBase> elements = NewFixedTypedArrayWithExternalPointer(
+ Handle<ExternalArray> elements = NewExternalArray(
static_cast<int>(length), type,
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
Handle<Map> map = JSObject::GetElementsTransitionMap(obj, elements_kind);
Handle<BytecodeArray> NewBytecodeArray(int length, const byte* raw_bytecodes,
int frame_size);
- Handle<FixedTypedArrayBase> NewFixedTypedArrayWithExternalPointer(
- int length, ExternalArrayType array_type, void* external_pointer,
+ Handle<ExternalArray> NewExternalArray(
+ int length,
+ ExternalArrayType array_type,
+ void* external_pointer,
PretenureFlag pretenure = NOT_TENURED);
Handle<FixedTypedArrayBase> NewFixedTypedArray(
return AddEntry(object, HeapEntry::kHidden, "system / NativeContext");
} else if (object->IsContext()) {
return AddEntry(object, HeapEntry::kObject, "system / Context");
- } else if (object->IsFixedArray() || object->IsFixedDoubleArray() ||
- object->IsByteArray()) {
+ } else if (object->IsFixedArray() ||
+ object->IsFixedDoubleArray() ||
+ object->IsByteArray() ||
+ object->IsExternalArray()) {
return AddEntry(object, HeapEntry::kArray, "");
} else if (object->IsHeapNumber()) {
return AddEntry(object, HeapEntry::kHeapNumber, "number");
DCHECK(map_word.IsForwardingAddress());
FixedTypedArrayBase* target =
reinterpret_cast<FixedTypedArrayBase*>(map_word.ToForwardingAddress());
- if (target->base_pointer() != Smi::FromInt(0))
- target->set_base_pointer(target, SKIP_WRITE_BARRIER);
+ target->set_base_pointer(target, SKIP_WRITE_BARRIER);
}
DCHECK(map_word.IsForwardingAddress());
FixedTypedArrayBase* target =
reinterpret_cast<FixedTypedArrayBase*>(map_word.ToForwardingAddress());
- if (target->base_pointer() != Smi::FromInt(0))
- target->set_base_pointer(target, SKIP_WRITE_BARRIER);
+ target->set_base_pointer(target, SKIP_WRITE_BARRIER);
}
ALLOCATE_VARSIZE_MAP(BYTECODE_ARRAY_TYPE, bytecode_array)
ALLOCATE_VARSIZE_MAP(FREE_SPACE_TYPE, free_space)
+#define ALLOCATE_EXTERNAL_ARRAY_MAP(Type, type, TYPE, ctype, size) \
+ ALLOCATE_MAP(EXTERNAL_##TYPE##_ARRAY_TYPE, ExternalArray::kSize, \
+ external_##type##_array)
+
+ TYPED_ARRAYS(ALLOCATE_EXTERNAL_ARRAY_MAP)
+#undef ALLOCATE_EXTERNAL_ARRAY_MAP
+
#define ALLOCATE_FIXED_TYPED_ARRAY_MAP(Type, type, TYPE, ctype, size) \
ALLOCATE_VARSIZE_MAP(FIXED_##TYPE##_ARRAY_TYPE, fixed_##type##_array)
set_empty_bytecode_array(bytecode_array);
}
+#define ALLOCATE_EMPTY_EXTERNAL_ARRAY(Type, type, TYPE, ctype, size) \
+ { \
+ ExternalArray* obj; \
+ if (!AllocateEmptyExternalArray(kExternal##Type##Array).To(&obj)) \
+ return false; \
+ set_empty_external_##type##_array(obj); \
+ }
+
+ TYPED_ARRAYS(ALLOCATE_EMPTY_EXTERNAL_ARRAY)
+#undef ALLOCATE_EMPTY_EXTERNAL_ARRAY
+
#define ALLOCATE_EMPTY_FIXED_TYPED_ARRAY(Type, type, TYPE, ctype, size) \
{ \
FixedTypedArrayBase* obj; \
}
+Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
+ return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]);
+}
+
+
+Heap::RootListIndex Heap::RootIndexForExternalArrayType(
+ ExternalArrayType array_type) {
+ switch (array_type) {
+#define ARRAY_TYPE_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return kExternal##Type##ArrayMapRootIndex;
+
+ TYPED_ARRAYS(ARRAY_TYPE_TO_ROOT_INDEX)
+#undef ARRAY_TYPE_TO_ROOT_INDEX
+
+ default:
+ UNREACHABLE();
+ return kUndefinedValueRootIndex;
+ }
+}
+
Map* Heap::MapForFixedTypedArray(ExternalArrayType array_type) {
return Map::cast(roots_[RootIndexForFixedTypedArray(array_type)]);
}
+Heap::RootListIndex Heap::RootIndexForEmptyExternalArray(
+ ElementsKind elementsKind) {
+ switch (elementsKind) {
+#define ELEMENT_KIND_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ELEMENTS: \
+ return kEmptyExternal##Type##ArrayRootIndex;
+
+ TYPED_ARRAYS(ELEMENT_KIND_TO_ROOT_INDEX)
+#undef ELEMENT_KIND_TO_ROOT_INDEX
+
+ default:
+ UNREACHABLE();
+ return kUndefinedValueRootIndex;
+ }
+}
+
+
Heap::RootListIndex Heap::RootIndexForEmptyFixedTypedArray(
ElementsKind elementsKind) {
switch (elementsKind) {
}
+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())]);
}
-AllocationResult Heap::AllocateFixedTypedArrayWithExternalPointer(
- int length, ExternalArrayType array_type, void* external_pointer,
- PretenureFlag pretenure) {
- int size = FixedTypedArrayBase::kHeaderSize;
+AllocationResult Heap::AllocateExternalArray(int length,
+ ExternalArrayType array_type,
+ void* external_pointer,
+ PretenureFlag pretenure) {
+ int size = ExternalArray::kSize;
AllocationSpace space = SelectSpace(size, pretenure);
HeapObject* result;
{
if (!allocation.To(&result)) return allocation;
}
- result->set_map_no_write_barrier(MapForFixedTypedArray(array_type));
- FixedTypedArrayBase* elements = FixedTypedArrayBase::cast(result);
- elements->set_base_pointer(Smi::FromInt(0), SKIP_WRITE_BARRIER);
- elements->set_external_pointer(external_pointer, SKIP_WRITE_BARRIER);
- elements->set_length(length);
- return elements;
+ result->set_map_no_write_barrier(MapForExternalArrayType(array_type));
+ ExternalArray::cast(result)->set_length(length);
+ ExternalArray::cast(result)->set_external_pointer(external_pointer);
+ return result;
}
static void ForFixedTypedArray(ExternalArrayType array_type, int* element_size,
array_type == kExternalFloat64Array ? kDoubleAligned : kWordAligned);
if (!allocation.To(&object)) return allocation;
- object->set_map_no_write_barrier(MapForFixedTypedArray(array_type));
+ object->set_map(MapForFixedTypedArray(array_type));
FixedTypedArrayBase* elements = FixedTypedArrayBase::cast(object);
elements->set_base_pointer(elements, SKIP_WRITE_BARRIER);
elements->set_external_pointer(
// Initialize the JSObject.
InitializeJSObjectFromMap(js_obj, properties, map);
- DCHECK(js_obj->HasFastElements() || js_obj->HasFixedTypedArrayElements());
+ DCHECK(js_obj->HasFastElements() || js_obj->HasExternalArrayElements() ||
+ js_obj->HasFixedTypedArrayElements());
return js_obj;
}
}
+AllocationResult Heap::AllocateEmptyExternalArray(
+ ExternalArrayType array_type) {
+ return AllocateExternalArray(0, array_type, NULL, TENURED);
+}
+
+
AllocationResult Heap::CopyAndTenureFixedCOWArray(FixedArray* src) {
if (!InNewSpace(src)) {
return src;
V(Map, short_external_one_byte_internalized_string_map, \
ShortExternalOneByteInternalizedStringMap) \
V(Map, short_external_one_byte_string_map, ShortExternalOneByteStringMap) \
+ V(Map, external_int8_array_map, ExternalInt8ArrayMap) \
+ V(Map, external_uint8_array_map, ExternalUint8ArrayMap) \
+ V(Map, external_int16_array_map, ExternalInt16ArrayMap) \
+ V(Map, external_uint16_array_map, ExternalUint16ArrayMap) \
+ V(Map, external_int32_array_map, ExternalInt32ArrayMap) \
+ V(Map, external_uint32_array_map, ExternalUint32ArrayMap) \
+ V(Map, external_float32_array_map, ExternalFloat32ArrayMap) \
+ V(Map, external_float64_array_map, ExternalFloat64ArrayMap) \
+ V(Map, external_uint8_clamped_array_map, ExternalUint8ClampedArrayMap) \
+ V(ExternalArray, empty_external_int8_array, EmptyExternalInt8Array) \
+ V(ExternalArray, empty_external_uint8_array, EmptyExternalUint8Array) \
+ V(ExternalArray, empty_external_int16_array, EmptyExternalInt16Array) \
+ V(ExternalArray, empty_external_uint16_array, EmptyExternalUint16Array) \
+ V(ExternalArray, empty_external_int32_array, EmptyExternalInt32Array) \
+ V(ExternalArray, empty_external_uint32_array, EmptyExternalUint32Array) \
+ V(ExternalArray, empty_external_float32_array, EmptyExternalFloat32Array) \
+ V(ExternalArray, empty_external_float64_array, EmptyExternalFloat64Array) \
+ V(ExternalArray, empty_external_uint8_clamped_array, \
+ EmptyExternalUint8ClampedArray) \
V(Map, fixed_uint8_array_map, FixedUint8ArrayMap) \
V(Map, fixed_int8_array_map, FixedInt8ArrayMap) \
V(Map, fixed_uint16_array_map, FixedUint16ArrayMap) \
Map* MapForFixedTypedArray(ExternalArrayType array_type);
RootListIndex RootIndexForFixedTypedArray(ExternalArrayType array_type);
+ Map* MapForExternalArrayType(ExternalArrayType array_type);
+ RootListIndex RootIndexForExternalArrayType(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);
MUST_USE_RESULT AllocationResult AllocateSymbol();
// Allocates an external array of the specified length and type.
- MUST_USE_RESULT AllocationResult AllocateFixedTypedArrayWithExternalPointer(
- int length, ExternalArrayType array_type, void* external_pointer,
- PretenureFlag pretenure);
+ MUST_USE_RESULT AllocationResult
+ AllocateExternalArray(int length, ExternalArrayType array_type,
+ void* external_pointer, PretenureFlag pretenure);
// Allocates a fixed typed array of the specified length and type.
MUST_USE_RESULT AllocationResult
// Allocate empty fixed array.
MUST_USE_RESULT AllocationResult AllocateEmptyFixedArray();
+ // Allocate empty external array of given type.
+ MUST_USE_RESULT AllocationResult
+ AllocateEmptyExternalArray(ExternalArrayType array_type);
+
// Allocate empty fixed typed array of given type.
MUST_USE_RESULT AllocationResult
AllocateEmptyFixedTypedArray(ExternalArrayType array_type);
case HEAP_NUMBER_TYPE:
case MUTABLE_HEAP_NUMBER_TYPE:
case FLOAT32X4_TYPE:
+#define EXTERNAL_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ARRAY_TYPE:
+
+ TYPED_ARRAYS(EXTERNAL_ARRAY_CASE)
return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric,
instance_size, has_unboxed_fields);
+#undef EXTERNAL_ARRAY_CASE
case FIXED_UINT8_ARRAY_TYPE:
case FIXED_INT8_ARRAY_TYPE:
Range* HLoadKeyed::InferRange(Zone* zone) {
switch (elements_kind()) {
+ case EXTERNAL_INT8_ELEMENTS:
case INT8_ELEMENTS:
return new(zone) Range(kMinInt8, kMaxInt8);
+ case EXTERNAL_UINT8_ELEMENTS:
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
return new(zone) Range(kMinUInt8, kMaxUInt8);
+ case EXTERNAL_INT16_ELEMENTS:
case INT16_ELEMENTS:
return new(zone) Range(kMinInt16, kMaxInt16);
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
return new(zone) Range(kMinUInt16, kMaxUInt16);
default:
std::ostream& HLoadKeyed::PrintDataTo(std::ostream& os) const { // NOLINT
- if (!is_fixed_typed_array()) {
+ if (!is_external()) {
os << NameOf(elements());
} else {
- DCHECK(elements_kind() >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND &&
- elements_kind() <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
+ DCHECK(elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
+ elements_kind() <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
os << NameOf(elements()) << "." << ElementsKindToString(elements_kind());
}
return false;
}
- if (IsFixedTypedArrayElementsKind(elements_kind())) {
+ if (IsExternalArrayElementsKind(elements_kind())) {
return false;
}
return false;
}
- if (IsFixedTypedArrayElementsKind(elements_kind())) {
+ if (IsExternalArrayElementsKind(elements_kind())) {
return false;
}
std::ostream& HStoreKeyed::PrintDataTo(std::ostream& os) const { // NOLINT
- if (!is_fixed_typed_array()) {
+ if (!is_external()) {
os << NameOf(elements());
} else {
- DCHECK(elements_kind() >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND &&
- elements_kind() <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
+ DCHECK(elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
+ elements_kind() <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
os << NameOf(elements()) << "." << ElementsKindToString(elements_kind());
}
switch (value()->opcode()) {
case kLoadKeyed: {
ElementsKind load_kind = HLoadKeyed::cast(value())->elements_kind();
- return IsFixedFloatElementsKind(load_kind);
+ return IsExternalFloatOrDoubleElementsKind(load_kind) ||
+ IsFixedFloatElementsKind(load_kind);
}
case kChange: {
Representation from = HChange::cast(value())->from();
JSArrayBuffer::kBitFieldSlot, Representation::Smi());
}
+ static HObjectAccess ForExternalArrayExternalPointer() {
+ return HObjectAccess::ForObservableJSObjectOffset(
+ ExternalArray::kExternalPointerOffset, Representation::External());
+ }
+
static HObjectAccess ForJSArrayBufferViewBuffer() {
return HObjectAccess::ForObservableJSObjectOffset(
JSArrayBufferView::kBufferOffset);
DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
ElementsKind, LoadKeyedHoleMode, int);
+ bool is_external() const {
+ return IsExternalArrayElementsKind(elements_kind());
+ }
bool is_fixed_typed_array() const {
return IsFixedTypedArrayElementsKind(elements_kind());
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
HValue* elements() const { return OperandAt(0); }
HValue* key() const { return OperandAt(1); }
HValue* dependency() const {
// kind_fixed_typed_array: external[int32] (none)
// kind_external: external[int32] (none)
if (index == 0) {
- return is_fixed_typed_array() ? Representation::External()
- : Representation::Tagged();
+ return is_typed_elements() ? Representation::External()
+ : Representation::Tagged();
}
if (index == 1) {
return ArrayInstructionInterface::KeyedAccessIndexRequirement(
SetOperandAt(1, key);
SetOperandAt(2, dependency != NULL ? dependency : obj);
- if (!is_fixed_typed_array()) {
+ if (!is_typed_elements()) {
// I can detect the case between storing double (holey and fast) and
// smi/object by looking at elements_kind_.
DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
SetDependsOnFlag(kDoubleArrayElements);
}
} else {
- if (elements_kind == FLOAT32_ELEMENTS ||
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS ||
elements_kind == FLOAT64_ELEMENTS) {
set_representation(Representation::Double());
} else {
set_representation(Representation::Integer32());
}
- if (is_fixed_typed_array()) {
+ if (is_external()) {
SetDependsOnFlag(kExternalMemory);
+ } else if (is_fixed_typed_array()) {
SetDependsOnFlag(kTypedArrayElements);
} else {
UNREACHABLE();
// kind_fixed_typed_array: tagged[int32] = (double | int32)
// kind_external: external[int32] = (double | int32)
if (index == 0) {
- return is_fixed_typed_array() ? Representation::External()
- : Representation::Tagged();
+ return is_typed_elements() ? Representation::External()
+ : Representation::Tagged();
} else if (index == 1) {
return ArrayInstructionInterface::KeyedAccessIndexRequirement(
OperandAt(1)->representation());
return Representation::Smi();
}
- if (IsFixedTypedArrayElementsKind(kind)) {
- return Representation::Integer32();
- }
- return Representation::Tagged();
+ return IsExternalArrayElementsKind(kind) ||
+ IsFixedTypedArrayElementsKind(kind)
+ ? Representation::Integer32()
+ : Representation::Tagged();
+ }
+
+ bool is_external() const {
+ return IsExternalArrayElementsKind(elements_kind());
}
bool is_fixed_typed_array() const {
return IsFixedTypedArrayElementsKind(elements_kind());
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
+
Representation observed_input_representation(int index) override {
if (index < 2) return RequiredInputRepresentation(index);
if (IsUninitialized()) {
SetFlag(kTrackSideEffectDominators);
SetDependsOnFlag(kNewSpacePromotion);
}
- if (IsFastDoubleElementsKind(elements_kind)) {
+ if (is_external()) {
+ SetChangesFlag(kExternalMemory);
+ SetFlag(kAllowUndefinedAsNaN);
+ } else if (IsFastDoubleElementsKind(elements_kind)) {
SetChangesFlag(kDoubleArrayElements);
} else if (IsFastSmiElementsKind(elements_kind)) {
SetChangesFlag(kArrayElements);
} else if (is_fixed_typed_array()) {
SetChangesFlag(kTypedArrayElements);
- SetChangesFlag(kExternalMemory);
SetFlag(kAllowUndefinedAsNaN);
} else {
SetChangesFlag(kArrayElements);
}
- // {UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
- if (elements_kind >= UINT8_ELEMENTS && elements_kind <= INT32_ELEMENTS) {
+ // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
+ if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
+ elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
+ (elements_kind >= UINT8_ELEMENTS &&
+ elements_kind <= INT32_ELEMENTS)) {
SetFlag(kTruncatingToInt32);
}
}
static bool IsUnsignedLoad(HLoadKeyed* instr) {
switch (instr->elements_kind()) {
+ case EXTERNAL_UINT8_ELEMENTS:
+ case EXTERNAL_UINT16_ELEMENTS:
+ case EXTERNAL_UINT32_ELEMENTS:
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
case UINT8_ELEMENTS:
case UINT16_ELEMENTS:
case UINT32_ELEMENTS:
return true;
} else if (use->IsStoreKeyed()) {
HStoreKeyed* store = HStoreKeyed::cast(use);
- if (store->is_fixed_typed_array()) {
+ if (store->is_external()) {
// Storing a value into an external integer array is a bit level
// operation.
if (store->value() == val) {
// Clamping or a conversion to double should have beed inserted.
- DCHECK(store->elements_kind() != UINT8_CLAMPED_ELEMENTS);
- DCHECK(store->elements_kind() != FLOAT32_ELEMENTS);
- DCHECK(store->elements_kind() != FLOAT64_ELEMENTS);
+ DCHECK(store->elements_kind() != EXTERNAL_UINT8_CLAMPED_ELEMENTS);
+ DCHECK(store->elements_kind() != EXTERNAL_FLOAT32_ELEMENTS);
+ DCHECK(store->elements_kind() != EXTERNAL_FLOAT64_ELEMENTS);
return true;
}
}
KeyedAccessStoreMode store_mode) {
DCHECK(top_info()->IsStub() || checked_object->IsCompareMap() ||
checked_object->IsCheckMaps());
- DCHECK(!IsFixedTypedArrayElementsKind(elements_kind) || !is_js_array);
+ DCHECK((!IsExternalArrayElementsKind(elements_kind) &&
+ !IsFixedTypedArrayElementsKind(elements_kind)) ||
+ !is_js_array);
// No GVNFlag is necessary for ElementsKind if there is an explicit dependency
// on a HElementsTransition instruction. The flag can also be removed if the
// map to check has FAST_HOLEY_ELEMENTS, since there can be no further
}
length->set_type(HType::Smi());
HValue* checked_key = NULL;
- if (IsFixedTypedArrayElementsKind(elements_kind)) {
+ if (IsExternalArrayElementsKind(elements_kind) ||
+ IsFixedTypedArrayElementsKind(elements_kind)) {
checked_object = Add<HCheckArrayBufferNotNeutered>(checked_object);
- HValue* external_pointer = Add<HLoadNamedField>(
- elements, nullptr,
- HObjectAccess::ForFixedTypedArrayBaseExternalPointer());
- HValue* base_pointer = Add<HLoadNamedField>(
- elements, nullptr, HObjectAccess::ForFixedTypedArrayBaseBasePointer());
- HValue* backing_store = AddUncasted<HAdd>(
- external_pointer, base_pointer, Strength::WEAK, AddOfExternalAndTagged);
-
+ HValue* backing_store;
+ if (IsExternalArrayElementsKind(elements_kind)) {
+ backing_store = Add<HLoadNamedField>(
+ elements, nullptr, HObjectAccess::ForExternalArrayExternalPointer());
+ } else {
+ HValue* external_pointer = Add<HLoadNamedField>(
+ elements, nullptr,
+ HObjectAccess::ForFixedTypedArrayBaseExternalPointer());
+ HValue* base_pointer = Add<HLoadNamedField>(
+ elements, nullptr,
+ HObjectAccess::ForFixedTypedArrayBaseBasePointer());
+ backing_store = AddUncasted<HAdd>(external_pointer, base_pointer,
+ Strength::WEAK, AddOfExternalAndTagged);
+ }
if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
NoObservableSideEffectsScope no_effects(this);
IfBuilder length_checker(this);
LoadKeyedHoleMode load_mode) {
if (access_type == STORE) {
DCHECK(val != NULL);
- if (elements_kind == UINT8_CLAMPED_ELEMENTS) {
+ if (elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS ||
+ elements_kind == UINT8_CLAMPED_ELEMENTS) {
val = Add<HClampToUint8>(val);
}
return Add<HStoreKeyed>(elements, checked_key, val, elements_kind,
DCHECK(val == NULL);
HLoadKeyed* load = Add<HLoadKeyed>(
elements, checked_key, dependency, elements_kind, load_mode);
- if (elements_kind == UINT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) {
graph()->RecordUint32Instruction(load);
}
return load;
val));
} else {
DCHECK(IsFastElementsKind(elements_kind) ||
+ IsExternalArrayElementsKind(elements_kind) ||
IsFixedTypedArrayElementsKind(elements_kind));
LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
// Happily, mapcompare is a checked object.
bool is_zero_byte_offset,
HValue* buffer, HValue* byte_offset, HValue* length) {
Handle<Map> external_array_map(
- isolate()->heap()->MapForFixedTypedArray(array_type));
+ isolate()->heap()->MapForExternalArrayType(array_type));
// The HForceRepresentation is to prevent possible deopt on int-smi
// conversion after allocation but before the new object fields are set.
length = AddUncasted<HForceRepresentation>(length, Representation::Smi());
- HValue* elements = Add<HAllocate>(
- Add<HConstant>(FixedTypedArrayBase::kHeaderSize), HType::HeapObject(),
- NOT_TENURED, external_array_map->instance_type());
+ HValue* elements =
+ Add<HAllocate>(Add<HConstant>(ExternalArray::kSize), HType::HeapObject(),
+ NOT_TENURED, external_array_map->instance_type());
AddStoreMapConstant(elements, external_array_map);
Add<HStoreNamedField>(elements,
}
Add<HStoreNamedField>(elements,
- HObjectAccess::ForFixedTypedArrayBaseBasePointer(),
- graph()->GetConstant0());
- Add<HStoreNamedField>(elements,
- HObjectAccess::ForFixedTypedArrayBaseExternalPointer(),
- typed_array_start);
+ HObjectAccess::ForExternalArrayExternalPointer(),
+ typed_array_start);
return elements;
}
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);
if (buffer != NULL) {
elements = BuildAllocateExternalElements(
array_type, is_zero_byte_offset, buffer, byte_offset, length);
- Handle<Map> obj_map =
- TypedArrayMap(isolate(), array_type, fixed_elements_kind);
+ Handle<Map> obj_map = TypedArrayMap(
+ isolate(), array_type, external_elements_kind);
AddStoreMapConstant(obj, obj_map);
} else {
DCHECK(is_zero_byte_offset);
instr->hydrogen()->key()->representation(),
elements_kind,
instr->base_offset()));
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
__ cvtss2sd(result, result);
- } else if (elements_kind == FLOAT64_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
__ movsd(ToDoubleRegister(instr->result()), operand);
} else {
Register result(ToRegister(instr->result()));
switch (elements_kind) {
+ case EXTERNAL_INT8_ELEMENTS:
case INT8_ELEMENTS:
__ movsx_b(result, operand);
break;
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
__ movzx_b(result, operand);
break;
+ case EXTERNAL_INT16_ELEMENTS:
case INT16_ELEMENTS:
__ movsx_w(result, operand);
break;
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
__ movzx_w(result, operand);
break;
+ case EXTERNAL_INT32_ELEMENTS:
case INT32_ELEMENTS:
__ mov(result, operand);
break;
+ case EXTERNAL_UINT32_ELEMENTS:
case UINT32_ELEMENTS:
__ mov(result, operand);
if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
DeoptimizeIf(negative, instr, Deoptimizer::kNegativeValue);
}
break;
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
case FAST_SMI_ELEMENTS:
void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoLoadKeyedExternalArray(instr);
} else if (instr->hydrogen()->representation().IsDouble()) {
DoLoadKeyedFixedDoubleArray(instr);
instr->hydrogen()->key()->representation(),
elements_kind,
instr->base_offset()));
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
XMMRegister xmm_scratch = double_scratch0();
__ cvtsd2ss(xmm_scratch, ToDoubleRegister(instr->value()));
__ movss(operand, xmm_scratch);
- } else if (elements_kind == FLOAT64_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
__ movsd(operand, ToDoubleRegister(instr->value()));
} else {
Register value = ToRegister(instr->value());
switch (elements_kind) {
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
+ case EXTERNAL_INT8_ELEMENTS:
case UINT8_ELEMENTS:
case INT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
__ mov_b(operand, value);
break;
+ case EXTERNAL_INT16_ELEMENTS:
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
case INT16_ELEMENTS:
__ mov_w(operand, value);
break;
+ case EXTERNAL_INT32_ELEMENTS:
+ case EXTERNAL_UINT32_ELEMENTS:
case UINT32_ELEMENTS:
case INT32_ELEMENTS:
__ mov(operand, value);
break;
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
case FAST_SMI_ELEMENTS:
void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
// By cases...external, fast-double, fast
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoStoreKeyedExternalArray(instr);
} else if (instr->hydrogen()->value()->representation().IsDouble()) {
DoStoreKeyedFixedDoubleArray(instr);
: UseRegisterOrConstantAtStart(instr->key());
LInstruction* result = NULL;
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
LOperand* obj = UseRegisterAtStart(instr->elements());
result = DefineAsRegister(new(zone()) LLoadKeyed(obj, key));
} else {
}
bool needs_environment;
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_external() || instr->is_fixed_typed_array()) {
// see LCodeGen::DoLoadKeyedExternalArray
- needs_environment = elements_kind == UINT32_ELEMENTS &&
+ needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) &&
!instr->CheckFlag(HInstruction::kUint32);
} else {
// see LCodeGen::DoLoadKeyedFixedDoubleArray and
// Determine if we need a byte register in this case for the value.
bool val_is_fixed_register =
+ elements_kind == EXTERNAL_INT8_ELEMENTS ||
+ elements_kind == EXTERNAL_UINT8_ELEMENTS ||
+ elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS ||
elements_kind == UINT8_ELEMENTS ||
elements_kind == INT8_ELEMENTS ||
elements_kind == UINT8_CLAMPED_ELEMENTS;
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
DCHECK(instr->elements()->representation().IsTagged());
DCHECK(instr->key()->representation().IsInteger32() ||
instr->key()->representation().IsSmi());
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ bool is_external() const {
+ return hydrogen()->is_external();
+ }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
// an index cannot fold the scale operation into a load and need an extra
// temp register to do the work.
return key_representation.IsSmi() &&
- (elements_kind == UINT8_ELEMENTS || elements_kind == INT8_ELEMENTS ||
- elements_kind == UINT8_CLAMPED_ELEMENTS);
+ (elements_kind == EXTERNAL_INT8_ELEMENTS ||
+ elements_kind == EXTERNAL_UINT8_ELEMENTS ||
+ elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS ||
+ elements_kind == UINT8_ELEMENTS ||
+ elements_kind == INT8_ELEMENTS ||
+ elements_kind == UINT8_CLAMPED_ELEMENTS);
}
inputs_[2] = val;
}
+ bool is_external() const { return hydrogen()->is_external(); }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
} else if (IsSloppyArgumentsElements(elements_kind)) {
cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
} else if (IsFastElementsKind(elements_kind) ||
+ IsExternalArrayElementsKind(elements_kind) ||
IsFixedTypedArrayElementsKind(elements_kind)) {
cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind,
convert_hole_to_undefined).GetCode();
} else if (receiver_map->has_sloppy_arguments_elements()) {
stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
} else if (receiver_map->has_fast_elements() ||
+ receiver_map->has_external_array_elements() ||
receiver_map->has_fixed_typed_array_elements()) {
stub = LoadFastElementStub(isolate, is_js_array, elements_kind,
convert_hole_to_undefined).GetCode();
if (IsSloppyArgumentsElements(elements_kind)) {
cached_stub = KeyedStoreSloppyArgumentsStub(isolate()).GetCode();
} else if (receiver_map->has_fast_elements() ||
+ receiver_map->has_external_array_elements() ||
receiver_map->has_fixed_typed_array_elements()) {
cached_stub = StoreFastElementStub(isolate(), is_js_array,
elements_kind, store_mode).GetCode();
if (receiver_map->has_sloppy_arguments_elements()) {
stub = KeyedStoreSloppyArgumentsStub(isolate()).GetCode();
} else if (receiver_map->has_fast_elements() ||
+ receiver_map->has_external_array_elements() ||
receiver_map->has_fixed_typed_array_elements()) {
stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
store_mode).GetCode();
if (store_mode != STANDARD_STORE) {
int external_arrays = 0;
for (int i = 0; i < target_receiver_maps.length(); ++i) {
- if (target_receiver_maps[i]->has_fixed_typed_array_elements()) {
+ if (target_receiver_maps[i]->has_external_array_elements() ||
+ target_receiver_maps[i]->has_fixed_typed_array_elements()) {
external_arrays++;
}
}
case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
return Map::TransitionElementsTo(map, FAST_HOLEY_DOUBLE_ELEMENTS);
case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
- DCHECK(map->has_fixed_typed_array_elements());
+ DCHECK(map->has_external_array_elements());
// Fall through
case STORE_NO_TRANSITION_HANDLE_COW:
case STANDARD_STORE:
}
}
if (!FLAG_trace_external_array_abuse &&
- receiver->map()->has_fixed_typed_array_elements() && oob_access) {
+ receiver->map()->has_external_array_elements() && oob_access) {
return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
}
Heap* heap = receiver->GetHeap();
void LookupIterator::ReloadHolderMap() {
DCHECK_EQ(DATA, state_);
DCHECK(IsElement());
- DCHECK(JSObject::cast(*holder_)->HasFixedTypedArrayElements());
+ DCHECK(JSObject::cast(*holder_)->HasExternalArrayElements() ||
+ JSObject::cast(*holder_)->HasFixedTypedArrayElements());
if (*holder_map_ != holder_->map()) {
holder_map_ = handle(holder_->map(), isolate_);
}
DCHECK(HolderIsReceiverOrHiddenPrototype());
Handle<JSObject> holder = GetHolder<JSObject>();
if (IsElement()) {
+ DCHECK(!holder->HasExternalArrayElements());
DCHECK(!holder->HasFixedTypedArrayElements());
DCHECK(attributes != NONE || !holder->HasFastElements());
Handle<FixedArrayBase> elements(holder->elements());
? (element_size_shift - kSmiTagSize) : element_size_shift;
int base_offset = instr->base_offset();
- if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
FPURegister result = ToDoubleRegister(instr->result());
if (key_is_constant) {
__ Addu(scratch0(), external_pointer, constant_key << element_size_shift);
__ sll(scratch0(), key, shift_size);
__ Addu(scratch0(), scratch0(), external_pointer);
}
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
__ lwc1(result, MemOperand(scratch0(), base_offset));
__ cvt_d_s(result, result);
} else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
key, external_pointer, key_is_constant, constant_key,
element_size_shift, shift_size, base_offset);
switch (elements_kind) {
+ case EXTERNAL_INT8_ELEMENTS:
case INT8_ELEMENTS:
__ lb(result, mem_operand);
break;
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
__ lbu(result, mem_operand);
break;
+ case EXTERNAL_INT16_ELEMENTS:
case INT16_ELEMENTS:
__ lh(result, mem_operand);
break;
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
__ lhu(result, mem_operand);
break;
+ case EXTERNAL_INT32_ELEMENTS:
case INT32_ELEMENTS:
__ lw(result, mem_operand);
break;
+ case EXTERNAL_UINT32_ELEMENTS:
case UINT32_ELEMENTS:
__ lw(result, mem_operand);
if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
break;
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoLoadKeyedExternalArray(instr);
} else if (instr->hydrogen()->representation().IsDouble()) {
DoLoadKeyedFixedDoubleArray(instr);
? (element_size_shift - kSmiTagSize) : element_size_shift;
int base_offset = instr->base_offset();
- if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
Register address = scratch0();
FPURegister value(ToDoubleRegister(instr->value()));
if (key_is_constant) {
__ Addu(address, external_pointer, address);
}
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
__ cvt_s_d(double_scratch0(), value);
__ swc1(double_scratch0(), MemOperand(address, base_offset));
} else { // Storing doubles, not floats.
element_size_shift, shift_size,
base_offset);
switch (elements_kind) {
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_INT8_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
case INT8_ELEMENTS:
__ sb(value, mem_operand);
break;
+ case EXTERNAL_INT16_ELEMENTS:
+ case EXTERNAL_UINT16_ELEMENTS:
case INT16_ELEMENTS:
case UINT16_ELEMENTS:
__ sh(value, mem_operand);
break;
+ case EXTERNAL_INT32_ELEMENTS:
+ case EXTERNAL_UINT32_ELEMENTS:
case INT32_ELEMENTS:
case UINT32_ELEMENTS:
__ sw(value, mem_operand);
break;
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
// By cases: external, fast double
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoStoreKeyedExternalArray(instr);
} else if (instr->hydrogen()->value()->representation().IsDouble()) {
DoStoreKeyedFixedDoubleArray(instr);
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LInstruction* result = NULL;
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
LOperand* obj = NULL;
if (instr->representation().IsDouble()) {
obj = UseRegister(instr->elements());
}
bool needs_environment;
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_external() || instr->is_fixed_typed_array()) {
// see LCodeGen::DoLoadKeyedExternalArray
- needs_environment = elements_kind == UINT32_ELEMENTS &&
+ needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) &&
!instr->CheckFlag(HInstruction::kUint32);
} else {
// see LCodeGen::DoLoadKeyedFixedDoubleArray and
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
DCHECK(instr->elements()->representation().IsTagged());
bool needs_write_barrier = instr->NeedsWriteBarrier();
LOperand* object = NULL;
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ bool is_external() const {
+ return hydrogen()->is_external();
+ }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
inputs_[2] = value;
}
+ bool is_external() const { return hydrogen()->is_external(); }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
: element_size_shift;
int base_offset = instr->base_offset();
- if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
FPURegister result = ToDoubleRegister(instr->result());
if (key_is_constant) {
__ Daddu(scratch0(), external_pointer,
}
__ Daddu(scratch0(), scratch0(), external_pointer);
}
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
__ lwc1(result, MemOperand(scratch0(), base_offset));
__ cvt_d_s(result, result);
} else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
key, external_pointer, key_is_constant, constant_key,
element_size_shift, shift_size, base_offset);
switch (elements_kind) {
+ case EXTERNAL_INT8_ELEMENTS:
case INT8_ELEMENTS:
__ lb(result, mem_operand);
break;
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
__ lbu(result, mem_operand);
break;
+ case EXTERNAL_INT16_ELEMENTS:
case INT16_ELEMENTS:
__ lh(result, mem_operand);
break;
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
__ lhu(result, mem_operand);
break;
+ case EXTERNAL_INT32_ELEMENTS:
case INT32_ELEMENTS:
__ lw(result, mem_operand);
break;
+ case EXTERNAL_UINT32_ELEMENTS:
case UINT32_ELEMENTS:
__ lw(result, mem_operand);
if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
break;
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoLoadKeyedExternalArray(instr);
} else if (instr->hydrogen()->representation().IsDouble()) {
DoLoadKeyedFixedDoubleArray(instr);
: element_size_shift;
int base_offset = instr->base_offset();
- if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
Register address = scratch0();
FPURegister value(ToDoubleRegister(instr->value()));
if (key_is_constant) {
__ Daddu(address, external_pointer, address);
}
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
__ cvt_s_d(double_scratch0(), value);
__ swc1(double_scratch0(), MemOperand(address, base_offset));
} else { // Storing doubles, not floats.
element_size_shift, shift_size,
base_offset);
switch (elements_kind) {
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_INT8_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
case INT8_ELEMENTS:
__ sb(value, mem_operand);
break;
+ case EXTERNAL_INT16_ELEMENTS:
+ case EXTERNAL_UINT16_ELEMENTS:
case INT16_ELEMENTS:
case UINT16_ELEMENTS:
__ sh(value, mem_operand);
break;
+ case EXTERNAL_INT32_ELEMENTS:
+ case EXTERNAL_UINT32_ELEMENTS:
case INT32_ELEMENTS:
case UINT32_ELEMENTS:
__ sw(value, mem_operand);
break;
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
// By cases: external, fast double
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoStoreKeyedExternalArray(instr);
} else if (instr->hydrogen()->value()->representation().IsDouble()) {
DoStoreKeyedFixedDoubleArray(instr);
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LInstruction* result = NULL;
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
LOperand* obj = NULL;
if (instr->representation().IsDouble()) {
obj = UseRegister(instr->elements());
}
bool needs_environment;
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_external() || instr->is_fixed_typed_array()) {
// see LCodeGen::DoLoadKeyedExternalArray
- needs_environment = elements_kind == UINT32_ELEMENTS &&
+ needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) &&
!instr->CheckFlag(HInstruction::kUint32);
} else {
// see LCodeGen::DoLoadKeyedFixedDoubleArray and
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
DCHECK(instr->elements()->representation().IsTagged());
bool needs_write_barrier = instr->NeedsWriteBarrier();
LOperand* object = NULL;
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ bool is_external() const {
+ return hydrogen()->is_external();
+ }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
inputs_[2] = value;
}
+ bool is_external() const { return hydrogen()->is_external(); }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
break;
#define VERIFY_TYPED_ARRAY(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ARRAY_TYPE: \
+ External##Type##Array::cast(this)->External##Type##ArrayVerify(); \
+ break; \
case FIXED_##TYPE##_ARRAY_TYPE: \
Fixed##Type##Array::cast(this)->FixedTypedArrayVerify(); \
break;
}
+#define EXTERNAL_ARRAY_VERIFY(Type, type, TYPE, ctype, size) \
+ void External##Type##Array::External##Type##ArrayVerify() { \
+ CHECK(IsExternal##Type##Array()); \
+ }
+
+TYPED_ARRAYS(EXTERNAL_ARRAY_VERIFY)
+#undef EXTERNAL_ARRAY_VERIFY
+
+
template <class Traits>
void FixedTypedArray<Traits>::FixedTypedArrayVerify() {
CHECK(IsHeapObject() &&
HeapObject::cast(this)->map()->instance_type() ==
Traits::kInstanceType);
- if (base_pointer() == this) {
- CHECK(external_pointer() ==
- ExternalReference::fixed_typed_array_base_data_offset().address());
- } else {
- CHECK(base_pointer() == nullptr);
- }
+ CHECK(base_pointer() == this);
}
}
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS:
TYPED_ARRAYS(TYPED_ARRAY_CASE)
bool Object::IsFixedArrayBase() const {
- return IsFixedArray() || IsFixedDoubleArray() || IsFixedTypedArrayBase();
+ return IsFixedArray() || IsFixedDoubleArray() || IsFixedTypedArrayBase() ||
+ IsExternalArray();
}
bool Object::HasValidElements() {
// Dictionary is covered under FixedArray.
- return IsFixedArray() || IsFixedDoubleArray() || IsFixedTypedArrayBase();
+ return IsFixedArray() || IsFixedDoubleArray() || IsExternalArray() ||
+ IsFixedTypedArrayBase();
}
}
+bool Object::IsExternalArray() const {
+ if (!Object::IsHeapObject())
+ return false;
+ InstanceType instance_type =
+ HeapObject::cast(this)->map()->instance_type();
+ return (instance_type >= FIRST_EXTERNAL_ARRAY_TYPE &&
+ instance_type <= LAST_EXTERNAL_ARRAY_TYPE);
+}
+
#define TYPED_ARRAY_TYPE_CHECKER(Type, type, TYPE, ctype, size) \
+ TYPE_CHECKER(External##Type##Array, EXTERNAL_##TYPE##_ARRAY_TYPE) \
TYPE_CHECKER(Fixed##Type##Array, FIXED_##TYPE##_ARRAY_TYPE)
TYPED_ARRAYS(TYPED_ARRAY_TYPE_CHECKER)
has_fast_double_elements()) {
DCHECK(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array()));
return GetHeap()->empty_fixed_array();
+ } else if (has_external_array_elements()) {
+ ExternalArray* empty_array = GetHeap()->EmptyExternalArrayForMap(this);
+ DCHECK(!GetHeap()->InNewSpace(empty_array));
+ return empty_array;
} else if (has_fixed_typed_array_elements()) {
FixedTypedArrayBase* empty_array =
GetHeap()->EmptyFixedTypedArrayForMap(this);
CAST_ACCESSOR(DeoptimizationOutputData)
CAST_ACCESSOR(DependentCode)
CAST_ACCESSOR(DescriptorArray)
+CAST_ACCESSOR(ExternalArray)
CAST_ACCESSOR(ExternalOneByteString)
+CAST_ACCESSOR(ExternalFloat32Array)
+CAST_ACCESSOR(ExternalFloat64Array)
+CAST_ACCESSOR(ExternalInt16Array)
+CAST_ACCESSOR(ExternalInt32Array)
+CAST_ACCESSOR(ExternalInt8Array)
CAST_ACCESSOR(ExternalString)
CAST_ACCESSOR(ExternalTwoByteString)
+CAST_ACCESSOR(ExternalUint16Array)
+CAST_ACCESSOR(ExternalUint32Array)
+CAST_ACCESSOR(ExternalUint8Array)
+CAST_ACCESSOR(ExternalUint8ClampedArray)
CAST_ACCESSOR(FixedArray)
CAST_ACCESSOR(FixedArrayBase)
CAST_ACCESSOR(FixedDoubleArray)
}
+uint8_t* ExternalUint8ClampedArray::external_uint8_clamped_pointer() {
+ return reinterpret_cast<uint8_t*>(external_pointer());
+}
+
+
+uint8_t ExternalUint8ClampedArray::get_scalar(int index) {
+ DCHECK((index >= 0) && (index < this->length()));
+ uint8_t* ptr = external_uint8_clamped_pointer();
+ return ptr[index];
+}
+
+
+Handle<Object> ExternalUint8ClampedArray::get(
+ Handle<ExternalUint8ClampedArray> array,
+ int index) {
+ return Handle<Smi>(Smi::FromInt(array->get_scalar(index)),
+ array->GetIsolate());
+}
+
+
+void ExternalUint8ClampedArray::set(int index, uint8_t value) {
+ DCHECK((index >= 0) && (index < this->length()));
+ uint8_t* ptr = external_uint8_clamped_pointer();
+ ptr[index] = value;
+}
+
+
+void* ExternalArray::external_pointer() const {
+ intptr_t ptr = READ_INTPTR_FIELD(this, kExternalPointerOffset);
+ return reinterpret_cast<void*>(ptr);
+}
+
+
+void ExternalArray::set_external_pointer(void* value, WriteBarrierMode mode) {
+ intptr_t ptr = reinterpret_cast<intptr_t>(value);
+ WRITE_INTPTR_FIELD(this, kExternalPointerOffset, ptr);
+}
+
+
+int8_t ExternalInt8Array::get_scalar(int index) {
+ DCHECK((index >= 0) && (index < this->length()));
+ int8_t* ptr = static_cast<int8_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+Handle<Object> ExternalInt8Array::get(Handle<ExternalInt8Array> array,
+ int index) {
+ return Handle<Smi>(Smi::FromInt(array->get_scalar(index)),
+ array->GetIsolate());
+}
+
+
+void ExternalInt8Array::set(int index, int8_t value) {
+ DCHECK((index >= 0) && (index < this->length()));
+ int8_t* ptr = static_cast<int8_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+uint8_t ExternalUint8Array::get_scalar(int index) {
+ DCHECK((index >= 0) && (index < this->length()));
+ uint8_t* ptr = static_cast<uint8_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+Handle<Object> ExternalUint8Array::get(Handle<ExternalUint8Array> array,
+ int index) {
+ return Handle<Smi>(Smi::FromInt(array->get_scalar(index)),
+ array->GetIsolate());
+}
+
+
+void ExternalUint8Array::set(int index, uint8_t value) {
+ DCHECK((index >= 0) && (index < this->length()));
+ uint8_t* ptr = static_cast<uint8_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+int16_t ExternalInt16Array::get_scalar(int index) {
+ DCHECK((index >= 0) && (index < this->length()));
+ int16_t* ptr = static_cast<int16_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+Handle<Object> ExternalInt16Array::get(Handle<ExternalInt16Array> array,
+ int index) {
+ return Handle<Smi>(Smi::FromInt(array->get_scalar(index)),
+ array->GetIsolate());
+}
+
+
+void ExternalInt16Array::set(int index, int16_t value) {
+ DCHECK((index >= 0) && (index < this->length()));
+ int16_t* ptr = static_cast<int16_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+uint16_t ExternalUint16Array::get_scalar(int index) {
+ DCHECK((index >= 0) && (index < this->length()));
+ uint16_t* ptr = static_cast<uint16_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+Handle<Object> ExternalUint16Array::get(Handle<ExternalUint16Array> array,
+ int index) {
+ return Handle<Smi>(Smi::FromInt(array->get_scalar(index)),
+ array->GetIsolate());
+}
+
+
+void ExternalUint16Array::set(int index, uint16_t value) {
+ DCHECK((index >= 0) && (index < this->length()));
+ uint16_t* ptr = static_cast<uint16_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+int32_t ExternalInt32Array::get_scalar(int index) {
+ DCHECK((index >= 0) && (index < this->length()));
+ int32_t* ptr = static_cast<int32_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+Handle<Object> ExternalInt32Array::get(Handle<ExternalInt32Array> array,
+ int index) {
+ return array->GetIsolate()->factory()->
+ NewNumberFromInt(array->get_scalar(index));
+}
+
+
+void ExternalInt32Array::set(int index, int32_t value) {
+ DCHECK((index >= 0) && (index < this->length()));
+ int32_t* ptr = static_cast<int32_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+uint32_t ExternalUint32Array::get_scalar(int index) {
+ DCHECK((index >= 0) && (index < this->length()));
+ uint32_t* ptr = static_cast<uint32_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+Handle<Object> ExternalUint32Array::get(Handle<ExternalUint32Array> array,
+ int index) {
+ return array->GetIsolate()->factory()->
+ NewNumberFromUint(array->get_scalar(index));
+}
+
+
+void ExternalUint32Array::set(int index, uint32_t value) {
+ DCHECK((index >= 0) && (index < this->length()));
+ uint32_t* ptr = static_cast<uint32_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+float ExternalFloat32Array::get_scalar(int index) {
+ DCHECK((index >= 0) && (index < this->length()));
+ float* ptr = static_cast<float*>(external_pointer());
+ return ptr[index];
+}
+
+
+Handle<Object> ExternalFloat32Array::get(Handle<ExternalFloat32Array> array,
+ int index) {
+ return array->GetIsolate()->factory()->NewNumber(array->get_scalar(index));
+}
+
+
+void ExternalFloat32Array::set(int index, float value) {
+ DCHECK((index >= 0) && (index < this->length()));
+ float* ptr = static_cast<float*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+double ExternalFloat64Array::get_scalar(int index) {
+ DCHECK((index >= 0) && (index < this->length()));
+ double* ptr = static_cast<double*>(external_pointer());
+ return ptr[index];
+}
+
+
+Handle<Object> ExternalFloat64Array::get(Handle<ExternalFloat64Array> array,
+ int index) {
+ return array->GetIsolate()->factory()->NewNumber(array->get_scalar(index));
+}
+
+
+void ExternalFloat64Array::set(int index, double value) {
+ DCHECK((index >= 0) && (index < this->length()));
+ double* ptr = static_cast<double*>(external_pointer());
+ ptr[index] = value;
+}
+
+
ACCESSORS(FixedTypedArrayBase, base_pointer, Object, kBasePointerOffset)
int FixedTypedArrayBase::DataSize(InstanceType type) {
- if (base_pointer() == Smi::FromInt(0)) return 0;
return length() * ElementSize(type);
}
}
+bool JSObject::HasExternalArrayElements() {
+ HeapObject* array = elements();
+ DCHECK(array != NULL);
+ return array->IsExternalArray();
+}
+
+
+#define EXTERNAL_ELEMENTS_CHECK(Type, type, TYPE, ctype, size) \
+bool JSObject::HasExternal##Type##Elements() { \
+ HeapObject* array = elements(); \
+ DCHECK(array != NULL); \
+ if (!array->IsHeapObject()) \
+ return false; \
+ return array->map()->instance_type() == EXTERNAL_##TYPE##_ARRAY_TYPE; \
+}
+
+TYPED_ARRAYS(EXTERNAL_ELEMENTS_CHECK)
+
+#undef EXTERNAL_ELEMENTS_CHECK
+
+
bool JSObject::HasFixedTypedArrayElements() {
HeapObject* array = elements();
DCHECK(array != NULL);
bool JSArray::AllowsSetLength() {
bool result = elements()->IsFixedArray() || elements()->IsFixedDoubleArray();
- DCHECK(result == !HasFixedTypedArrayElements());
+ DCHECK(result == !HasExternalArrayElements());
return result;
}
FreeSpace::cast(this)->FreeSpacePrint(os);
break;
+#define PRINT_EXTERNAL_ARRAY(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ARRAY_TYPE: \
+ External##Type##Array::cast(this)->External##Type##ArrayPrint(os); \
+ break;
+
+ TYPED_ARRAYS(PRINT_EXTERNAL_ARRAY)
+#undef PRINT_EXTERNAL_ARRAY
+
#define PRINT_FIXED_TYPED_ARRAY(Type, type, TYPE, ctype, size) \
case Fixed##Type##Array::kInstanceType: \
Fixed##Type##Array::cast(this)->FixedTypedArrayPrint(os); \
}
+#define EXTERNAL_ARRAY_PRINTER(Type, type, TYPE, ctype, size) \
+ void External##Type##Array::External##Type##ArrayPrint(std::ostream& os) { \
+ os << "external " #type " array"; \
+ }
+
+TYPED_ARRAYS(EXTERNAL_ARRAY_PRINTER)
+
+#undef EXTERNAL_ARRAY_PRINTER
+
+
template <class Traits>
void FixedTypedArray<Traits>::FixedTypedArrayPrint(
std::ostream& os) { // NOLINT
break; \
}
+ PRINT_ELEMENTS(EXTERNAL_UINT8_CLAMPED_ELEMENTS, ExternalUint8ClampedArray)
+ PRINT_ELEMENTS(EXTERNAL_INT8_ELEMENTS, ExternalInt8Array)
+ PRINT_ELEMENTS(EXTERNAL_UINT8_ELEMENTS,
+ ExternalUint8Array)
+ PRINT_ELEMENTS(EXTERNAL_INT16_ELEMENTS, ExternalInt16Array)
+ PRINT_ELEMENTS(EXTERNAL_UINT16_ELEMENTS,
+ ExternalUint16Array)
+ PRINT_ELEMENTS(EXTERNAL_INT32_ELEMENTS, ExternalInt32Array)
+ PRINT_ELEMENTS(EXTERNAL_UINT32_ELEMENTS,
+ ExternalUint32Array)
+ PRINT_ELEMENTS(EXTERNAL_FLOAT32_ELEMENTS, ExternalFloat32Array)
+ PRINT_ELEMENTS(EXTERNAL_FLOAT64_ELEMENTS, ExternalFloat64Array)
+
PRINT_ELEMENTS(UINT8_ELEMENTS, FixedUint8Array)
PRINT_ELEMENTS(UINT8_CLAMPED_ELEMENTS, FixedUint8ClampedArray)
PRINT_ELEMENTS(INT8_ELEMENTS, FixedInt8Array)
os << "<FreeSpace[" << FreeSpace::cast(this)->Size() << "]>";
break;
#define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ARRAY_TYPE: \
+ os << "<External" #Type "Array[" \
+ << External##Type##Array::cast(this)->length() << "]>"; \
+ break; \
case FIXED_##TYPE##_ARRAY_TYPE: \
os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
<< "]>"; \
break;
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ARRAY_TYPE: \
+ break; \
+ \
case FIXED_##TYPE##_ARRAY_TYPE: \
reinterpret_cast<FixedTypedArrayBase*>(this) \
->FixedTypedArrayBaseIterateBody(v); \
Handle<Object> to_assign = value;
// Convert the incoming value to a number for storing into typed arrays.
- if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
+ if (it->IsElement() && (receiver->HasExternalArrayElements() ||
+ receiver->HasFixedTypedArrayElements())) {
if (!value->IsNumber() && !value->IsUndefined()) {
ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), to_assign,
Execution::ToNumber(it->isolate(), value),
}
if (FLAG_trace_external_array_abuse &&
- array->HasFixedTypedArrayElements()) {
+ (array->HasExternalArrayElements() ||
+ array->HasFixedTypedArrayElements())) {
CheckArrayAbuse(array, "typed elements write", it->index(), true);
}
- if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
+ if (FLAG_trace_js_array_abuse && !array->HasExternalArrayElements() &&
+ !array->HasFixedTypedArrayElements()) {
CheckArrayAbuse(array, "elements write", it->index(), false);
}
}
// Special case: properties of typed arrays cannot be reconfigured to
// non-writable nor to non-enumerable.
- if (it->IsElement() && object->HasFixedTypedArrayElements()) {
+ if (it->IsElement() && (object->HasExternalArrayElements() ||
+ object->HasFixedTypedArrayElements())) {
return RedefineNonconfigurableProperty(it->isolate(), it->GetName(),
value, STRICT);
}
Handle<SeededNumberDictionary> JSObject::NormalizeElements(
Handle<JSObject> object) {
- DCHECK(!object->HasFixedTypedArrayElements());
+ DCHECK(!object->HasExternalArrayElements() &&
+ !object->HasFixedTypedArrayElements());
Isolate* isolate = object->GetIsolate();
// Find the backing store.
// Raw pixels and external arrays do not reference other
// objects.
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
break;
}
// It's not possible to seal objects with external array elements
- if (object->HasFixedTypedArrayElements()) {
+ if (object->HasExternalArrayElements() ||
+ object->HasFixedTypedArrayElements()) {
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kCannotPreventExtExternalArray),
Object);
}
// It's not possible to seal or freeze objects with external array elements
- if (object->HasFixedTypedArrayElements()) {
+ if (object->HasExternalArrayElements() ||
+ object->HasFixedTypedArrayElements()) {
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kCannotPreventExtExternalArray),
Object);
// Deep copy own elements.
// Pixel elements cannot be created using an object literal.
- DCHECK(!copy->HasFixedTypedArrayElements());
+ DCHECK(!copy->HasExternalArrayElements());
switch (kind) {
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
TYPED_ARRAYS(TYPED_ARRAY_CASE)
}
// Ignore accessors on typed arrays.
- if (it.IsElement() && object->HasFixedTypedArrayElements()) {
+ if (it.IsElement() && (object->HasFixedTypedArrayElements() ||
+ object->HasExternalArrayElements())) {
return it.factory()->undefined_value();
}
}
// Ignore accessors on typed arrays.
- if (it.IsElement() && object->HasFixedTypedArrayElements()) {
+ if (it.IsElement() && (object->HasFixedTypedArrayElements() ||
+ object->HasExternalArrayElements())) {
return it.factory()->undefined_value();
}
Map* maybe_elements_transition_map = NULL;
if (flag == INSERT_TRANSITION) {
maybe_elements_transition_map = map->ElementsTransitionMap();
- DCHECK(maybe_elements_transition_map == NULL ||
- (maybe_elements_transition_map->elements_kind() ==
- DICTIONARY_ELEMENTS &&
- kind == DICTIONARY_ELEMENTS));
+ DCHECK(
+ maybe_elements_transition_map == NULL ||
+ ((maybe_elements_transition_map->elements_kind() ==
+ DICTIONARY_ELEMENTS ||
+ IsExternalArrayElementsKind(
+ maybe_elements_transition_map->elements_kind())) &&
+ (kind == DICTIONARY_ELEMENTS || IsExternalArrayElementsKind(kind))));
DCHECK(!IsFastElementsKind(kind) ||
IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
DCHECK(kind != map->elements_kind());
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case DICTIONARY_ELEMENTS:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
TYPED_ARRAYS(TYPED_ARRAY_CASE)
}
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
TYPED_ARRAYS(TYPED_ARRAY_CASE)
JSObject::ValidateElements(object);
JSObject::SetMapAndElements(object, new_map, fast_elements);
- } else if (object->HasFixedTypedArrayElements()) {
+ } else if (object->HasExternalArrayElements() ||
+ object->HasFixedTypedArrayElements()) {
// Typed arrays cannot have holes or undefined elements.
return handle(Smi::FromInt(
FixedArrayBase::cast(object->elements())->length()), isolate);
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;
size_t JSTypedArray::element_size() {
switch (elements()->map()->instance_type()) {
-#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
- case FIXED_##TYPE##_ARRAY_TYPE: \
- return size;
+#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ARRAY_TYPE: \
+ return size;
TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
#undef INSTANCE_TYPE_TO_ELEMENT_SIZE
void FixedDoubleArray::SetValue(uint32_t index, Object* value) {
set(index, value->Number());
}
+
+
+void ExternalUint8ClampedArray::SetValue(uint32_t index, Object* value) {
+ uint8_t clamped_value = 0;
+ if (value->IsSmi()) {
+ int int_value = Smi::cast(value)->value();
+ if (int_value < 0) {
+ clamped_value = 0;
+ } else if (int_value > 255) {
+ clamped_value = 255;
+ } else {
+ clamped_value = static_cast<uint8_t>(int_value);
+ }
+ } else if (value->IsHeapNumber()) {
+ double double_value = HeapNumber::cast(value)->value();
+ if (!(double_value > 0)) {
+ // NaN and less than zero clamp to zero.
+ clamped_value = 0;
+ } else if (double_value > 255) {
+ // Greater than 255 clamp to 255.
+ clamped_value = 255;
+ } else {
+ // Other doubles are rounded to the nearest integer.
+ clamped_value = static_cast<uint8_t>(lrint(double_value));
+ }
+ } else {
+ // Clamp undefined to zero (default). All other types have been
+ // converted to a number type further up in the call chain.
+ DCHECK(value->IsUndefined());
+ }
+ set(index, clamped_value);
+}
+
+
+template <typename ExternalArrayClass, typename ValueType>
+static void ExternalArrayIntSetter(ExternalArrayClass* receiver, uint32_t index,
+ Object* value) {
+ ValueType cast_value = 0;
+ if (value->IsSmi()) {
+ int int_value = Smi::cast(value)->value();
+ cast_value = static_cast<ValueType>(int_value);
+ } else if (value->IsHeapNumber()) {
+ double double_value = HeapNumber::cast(value)->value();
+ cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
+ } else {
+ // Clamp undefined to zero (default). All other types have been
+ // converted to a number type further up in the call chain.
+ DCHECK(value->IsUndefined());
+ }
+ receiver->set(index, cast_value);
+}
+
+
+void ExternalInt8Array::SetValue(uint32_t index, Object* value) {
+ ExternalArrayIntSetter<ExternalInt8Array, int8_t>(this, index, value);
+}
+
+
+void ExternalUint8Array::SetValue(uint32_t index, Object* value) {
+ ExternalArrayIntSetter<ExternalUint8Array, uint8_t>(this, index, value);
+}
+
+
+void ExternalInt16Array::SetValue(uint32_t index, Object* value) {
+ ExternalArrayIntSetter<ExternalInt16Array, int16_t>(this, index, value);
+}
+
+
+void ExternalUint16Array::SetValue(uint32_t index, Object* value) {
+ ExternalArrayIntSetter<ExternalUint16Array, uint16_t>(this, index, value);
+}
+
+
+void ExternalInt32Array::SetValue(uint32_t index, Object* value) {
+ ExternalArrayIntSetter<ExternalInt32Array, int32_t>(this, index, value);
+}
+
+
+void ExternalUint32Array::SetValue(uint32_t index, Object* value) {
+ uint32_t cast_value = 0;
+ if (value->IsSmi()) {
+ int int_value = Smi::cast(value)->value();
+ cast_value = static_cast<uint32_t>(int_value);
+ } else if (value->IsHeapNumber()) {
+ double double_value = HeapNumber::cast(value)->value();
+ cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
+ } else {
+ // Clamp undefined to zero (default). All other types have been
+ // converted to a number type further up in the call chain.
+ DCHECK(value->IsUndefined());
+ }
+ set(index, cast_value);
+}
+
+
+void ExternalFloat32Array::SetValue(uint32_t index, Object* value) {
+ float cast_value = std::numeric_limits<float>::quiet_NaN();
+ if (value->IsSmi()) {
+ int int_value = Smi::cast(value)->value();
+ cast_value = static_cast<float>(int_value);
+ } else if (value->IsHeapNumber()) {
+ double double_value = HeapNumber::cast(value)->value();
+ cast_value = static_cast<float>(double_value);
+ } else {
+ // Clamp undefined to NaN (default). All other types have been
+ // converted to a number type further up in the call chain.
+ DCHECK(value->IsUndefined());
+ }
+ set(index, cast_value);
+}
+
+
+void ExternalFloat64Array::SetValue(uint32_t index, Object* value) {
+ double double_value = std::numeric_limits<double>::quiet_NaN();
+ if (value->IsNumber()) {
+ double_value = value->Number();
+ } else {
+ // Clamp undefined to NaN (default). All other types have been
+ // converted to a number type further up in the call chain.
+ DCHECK(value->IsUndefined());
+ }
+ set(index, double_value);
+}
+
+
void GlobalObject::InvalidatePropertyCell(Handle<GlobalObject> global,
Handle<Name> name) {
DCHECK(!global->HasFastProperties());
}
+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) {
DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
+ Handle<Map> new_map = Map::TransitionElementsTo(
+ map,
+ FixedToExternalElementsKind(map->elements_kind()));
+
Handle<FixedTypedArrayBase> fixed_typed_array(
FixedTypedArrayBase::cast(typed_array->elements()));
memcpy(buffer->backing_store(),
fixed_typed_array->DataPtr(),
fixed_typed_array->DataSize());
- Handle<FixedTypedArrayBase> new_elements =
- isolate->factory()->NewFixedTypedArrayWithExternalPointer(
+ Handle<ExternalArray> new_elements =
+ isolate->factory()->NewExternalArray(
fixed_typed_array->length(), typed_array->type(),
static_cast<uint8_t*>(buffer->backing_store()));
- typed_array->set_elements(*new_elements);
+ JSObject::SetMapAndElements(typed_array, new_map, new_elements);
return buffer;
}
Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
- if (JSArrayBuffer::cast(buffer())->backing_store() != nullptr) {
+ if (IsExternalArrayElementsKind(map()->elements_kind())) {
Handle<Object> result(buffer(), GetIsolate());
return Handle<JSArrayBuffer>::cast(result);
}
// - ScriptContextTable
// - WeakFixedArray
// - FixedDoubleArray
+// - ExternalArray
+// - ExternalUint8ClampedArray
+// - ExternalInt8Array
+// - ExternalUint8Array
+// - ExternalInt16Array
+// - ExternalUint16Array
+// - ExternalInt32Array
+// - ExternalUint32Array
+// - ExternalFloat32Array
// - Name
// - String
// - SeqString
V(BYTE_ARRAY_TYPE) \
V(BYTECODE_ARRAY_TYPE) \
V(FREE_SPACE_TYPE) \
+ /* Note: the order of these external array */ \
+ /* types is relied upon in */ \
+ /* Object::IsExternalArray(). */ \
+ V(EXTERNAL_INT8_ARRAY_TYPE) \
+ V(EXTERNAL_UINT8_ARRAY_TYPE) \
+ V(EXTERNAL_INT16_ARRAY_TYPE) \
+ V(EXTERNAL_UINT16_ARRAY_TYPE) \
+ V(EXTERNAL_INT32_ARRAY_TYPE) \
+ V(EXTERNAL_UINT32_ARRAY_TYPE) \
+ V(EXTERNAL_FLOAT32_ARRAY_TYPE) \
+ V(EXTERNAL_FLOAT64_ARRAY_TYPE) \
+ V(EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE) \
\
V(FIXED_INT8_ARRAY_TYPE) \
V(FIXED_UINT8_ARRAY_TYPE) \
BYTE_ARRAY_TYPE,
BYTECODE_ARRAY_TYPE,
FREE_SPACE_TYPE,
+ EXTERNAL_INT8_ARRAY_TYPE, // FIRST_EXTERNAL_ARRAY_TYPE
+ EXTERNAL_UINT8_ARRAY_TYPE,
+ EXTERNAL_INT16_ARRAY_TYPE,
+ EXTERNAL_UINT16_ARRAY_TYPE,
+ EXTERNAL_INT32_ARRAY_TYPE,
+ EXTERNAL_UINT32_ARRAY_TYPE,
+ EXTERNAL_FLOAT32_ARRAY_TYPE,
+ EXTERNAL_FLOAT64_ARRAY_TYPE,
+ EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE
FIXED_INT8_ARRAY_TYPE, // FIRST_FIXED_TYPED_ARRAY_TYPE
FIXED_UINT8_ARRAY_TYPE,
FIXED_INT16_ARRAY_TYPE,
// Boundaries for testing for a SIMD type.
FIRST_SIMD_TYPE = FLOAT32X4_TYPE,
LAST_SIMD_TYPE = FLOAT32X4_TYPE,
+ // Boundaries for testing for an external array.
+ FIRST_EXTERNAL_ARRAY_TYPE = EXTERNAL_INT8_ARRAY_TYPE,
+ LAST_EXTERNAL_ARRAY_TYPE = EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE,
// Boundaries for testing for a fixed typed array.
FIRST_FIXED_TYPED_ARRAY_TYPE = FIXED_INT8_ARRAY_TYPE,
LAST_FIXED_TYPED_ARRAY_TYPE = FIXED_UINT8_CLAMPED_ARRAY_TYPE,
NUM_OF_CALLABLE_SPEC_OBJECT_TYPES = 2
};
+const int kExternalArrayTypeCount =
+ LAST_EXTERNAL_ARRAY_TYPE - FIRST_EXTERNAL_ARRAY_TYPE + 1;
+
STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType);
STATIC_ASSERT(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType);
STATIC_ASSERT(ODDBALL_TYPE == Internals::kOddballType);
V(InternalizedString) \
V(Symbol) \
\
+ V(ExternalArray) \
+ V(ExternalInt8Array) \
+ V(ExternalUint8Array) \
+ V(ExternalInt16Array) \
+ V(ExternalUint16Array) \
+ V(ExternalInt32Array) \
+ V(ExternalUint32Array) \
+ V(ExternalFloat32Array) \
+ V(ExternalFloat64Array) \
+ V(ExternalUint8ClampedArray) \
V(FixedTypedArrayBase) \
V(FixedUint8Array) \
V(FixedInt8Array) \
// writing to any element the array must be copied. Use
// EnsureWritableFastElements in this case.
//
- // In the slow mode the elements is either a NumberDictionary, a
- // FixedArray parameter map for a (sloppy) arguments object.
+ // In the slow mode the elements is either a NumberDictionary, an
+ // ExternalArray, or a FixedArray parameter map for a (sloppy)
+ // arguments object.
DECL_ACCESSORS(elements, FixedArrayBase)
inline void initialize_elements();
static void ResetElements(Handle<JSObject> object);
inline bool HasSloppyArgumentsElements();
inline bool HasDictionaryElements();
+ inline bool HasExternalUint8ClampedElements();
+ inline bool HasExternalArrayElements();
+ inline bool HasExternalInt8Elements();
+ inline bool HasExternalUint8Elements();
+ inline bool HasExternalInt16Elements();
+ inline bool HasExternalUint16Elements();
+ inline bool HasExternalInt32Elements();
+ inline bool HasExternalUint32Elements();
+ inline bool HasExternalFloat32Elements();
+ inline bool HasExternalFloat64Elements();
+
inline bool HasFixedTypedArrayElements();
inline bool HasFixedUint8ClampedElements();
V(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t, 1)
+
+// An ExternalArray represents a fixed-size array of primitive values
+// which live outside the JavaScript heap. Its subclasses are used to
+// implement the CanvasArray types being defined in the WebGL
+// specification. As of this writing the first public draft is not yet
+// available, but Khronos members can access the draft at:
+// https://cvs.khronos.org/svn/repos/3dweb/trunk/doc/spec/WebGL-spec.html
+//
+// The semantics of these arrays differ from CanvasPixelArray.
+// Out-of-range values passed to the setter are converted via a C
+// cast, not clamping. Out-of-range indices cause exceptions to be
+// raised rather than being silently ignored.
+class ExternalArray: public FixedArrayBase {
+ public:
+ inline bool is_the_hole(int index) { return false; }
+
+ // [external_pointer]: The pointer to the external memory area backing this
+ // external array.
+ DECL_ACCESSORS(external_pointer, void) // Pointer to the data store.
+
+ DECLARE_CAST(ExternalArray)
+
+ // Maximal acceptable length for an external array.
+ static const int kMaxLength = 0x3fffffff;
+
+ // ExternalArray headers are not quadword aligned.
+ static const int kExternalPointerOffset =
+ POINTER_SIZE_ALIGN(FixedArrayBase::kLengthOffset + kPointerSize);
+ static const int kSize = kExternalPointerOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalArray);
+};
+
+
+// A ExternalUint8ClampedArray represents a fixed-size byte array with special
+// semantics used for implementing the CanvasPixelArray object. Please see the
+// specification at:
+
+// http://www.whatwg.org/specs/web-apps/current-work/
+// multipage/the-canvas-element.html#canvaspixelarray
+// In particular, write access clamps the value written to 0 or 255 if the
+// value written is outside this range.
+class ExternalUint8ClampedArray: public ExternalArray {
+ public:
+ inline uint8_t* external_uint8_clamped_pointer();
+
+ // Setter and getter.
+ inline uint8_t get_scalar(int index);
+ static inline Handle<Object> get(Handle<ExternalUint8ClampedArray> array,
+ int index);
+ inline void set(int index, uint8_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined and clamps the converted value between 0 and 255.
+ void SetValue(uint32_t index, Object* value);
+
+ DECLARE_CAST(ExternalUint8ClampedArray)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalUint8ClampedArray)
+ DECLARE_VERIFIER(ExternalUint8ClampedArray)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint8ClampedArray);
+};
+
+
+class ExternalInt8Array: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline int8_t get_scalar(int index);
+ static inline Handle<Object> get(Handle<ExternalInt8Array> array, int index);
+ inline void set(int index, int8_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ void SetValue(uint32_t index, Object* value);
+
+ DECLARE_CAST(ExternalInt8Array)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalInt8Array)
+ DECLARE_VERIFIER(ExternalInt8Array)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalInt8Array);
+};
+
+
+class ExternalUint8Array: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline uint8_t get_scalar(int index);
+ static inline Handle<Object> get(Handle<ExternalUint8Array> array, int index);
+ inline void set(int index, uint8_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ void SetValue(uint32_t index, Object* value);
+
+ DECLARE_CAST(ExternalUint8Array)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalUint8Array)
+ DECLARE_VERIFIER(ExternalUint8Array)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint8Array);
+};
+
+
+class ExternalInt16Array: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline int16_t get_scalar(int index);
+ static inline Handle<Object> get(Handle<ExternalInt16Array> array, int index);
+ inline void set(int index, int16_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ void SetValue(uint32_t index, Object* value);
+
+ DECLARE_CAST(ExternalInt16Array)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalInt16Array)
+ DECLARE_VERIFIER(ExternalInt16Array)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalInt16Array);
+};
+
+
+class ExternalUint16Array: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline uint16_t get_scalar(int index);
+ static inline Handle<Object> get(Handle<ExternalUint16Array> array,
+ int index);
+ inline void set(int index, uint16_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ void SetValue(uint32_t index, Object* value);
+
+ DECLARE_CAST(ExternalUint16Array)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalUint16Array)
+ DECLARE_VERIFIER(ExternalUint16Array)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint16Array);
+};
+
+
+class ExternalInt32Array: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline int32_t get_scalar(int index);
+ static inline Handle<Object> get(Handle<ExternalInt32Array> array, int index);
+ inline void set(int index, int32_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ void SetValue(uint32_t index, Object* value);
+
+ DECLARE_CAST(ExternalInt32Array)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalInt32Array)
+ DECLARE_VERIFIER(ExternalInt32Array)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalInt32Array);
+};
+
+
+class ExternalUint32Array: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline uint32_t get_scalar(int index);
+ static inline Handle<Object> get(Handle<ExternalUint32Array> array,
+ int index);
+ inline void set(int index, uint32_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ void SetValue(uint32_t index, Object* value);
+
+ DECLARE_CAST(ExternalUint32Array)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalUint32Array)
+ DECLARE_VERIFIER(ExternalUint32Array)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint32Array);
+};
+
+
+class ExternalFloat32Array: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline float get_scalar(int index);
+ static inline Handle<Object> get(Handle<ExternalFloat32Array> array,
+ int index);
+ inline void set(int index, float value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ void SetValue(uint32_t index, Object* value);
+
+ DECLARE_CAST(ExternalFloat32Array)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalFloat32Array)
+ DECLARE_VERIFIER(ExternalFloat32Array)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloat32Array);
+};
+
+
+class ExternalFloat64Array: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline double get_scalar(int index);
+ static inline Handle<Object> get(Handle<ExternalFloat64Array> array,
+ int index);
+ inline void set(int index, double value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ void SetValue(uint32_t index, Object* value);
+
+ DECLARE_CAST(ExternalFloat64Array)
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(ExternalFloat64Array)
+ DECLARE_VERIFIER(ExternalFloat64Array)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloat64Array);
+};
+
+
class FixedTypedArrayBase: public FixedArrayBase {
public:
- // [base_pointer]: Either points to the FixedTypedArrayBase itself or nullptr.
+ // [base_pointer]: For now, points to the FixedTypedArrayBase itself.
DECL_ACCESSORS(base_pointer, Object)
- // [external_pointer]: Contains the offset between base_pointer and the start
- // of the data. If the base_pointer is a nullptr, the external_pointer
- // therefore points to the actual backing store.
+ // [external_pointer]: For now, contains the offset between base_pointer and
+ // the start of the data.
DECL_ACCESSORS(external_pointer, void)
// Dispatched behavior.
return IsSloppyArgumentsElements(elements_kind());
}
+ inline bool has_external_array_elements() {
+ return IsExternalArrayElementsKind(elements_kind());
+ }
+
inline bool has_fixed_typed_array_elements() {
return IsFixedTypedArrayElementsKind(elements_kind());
}
bool key_is_smi = instr->hydrogen()->key()->representation().IsSmi();
int base_offset = instr->base_offset();
- if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
DoubleRegister result = ToDoubleRegister(instr->result());
if (key_is_constant) {
__ Add(scratch0(), external_pointer, constant_key << element_size_shift,
__ IndexToArrayOffset(r0, key, element_size_shift, key_is_smi);
__ add(scratch0(), external_pointer, r0);
}
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
__ lfs(result, MemOperand(scratch0(), base_offset));
} else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
__ lfd(result, MemOperand(scratch0(), base_offset));
PrepareKeyedOperand(key, external_pointer, key_is_constant, key_is_smi,
constant_key, element_size_shift, base_offset);
switch (elements_kind) {
+ case EXTERNAL_INT8_ELEMENTS:
case INT8_ELEMENTS:
if (key_is_constant) {
__ LoadByte(result, mem_operand, r0);
}
__ extsb(result, result);
break;
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
if (key_is_constant) {
__ lbzx(result, mem_operand);
}
break;
+ case EXTERNAL_INT16_ELEMENTS:
case INT16_ELEMENTS:
if (key_is_constant) {
__ LoadHalfWordArith(result, mem_operand, r0);
__ lhax(result, mem_operand);
}
break;
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
if (key_is_constant) {
__ LoadHalfWord(result, mem_operand, r0);
__ lhzx(result, mem_operand);
}
break;
+ case EXTERNAL_INT32_ELEMENTS:
case INT32_ELEMENTS:
if (key_is_constant) {
__ LoadWordArith(result, mem_operand, r0);
__ lwax(result, mem_operand);
}
break;
+ case EXTERNAL_UINT32_ELEMENTS:
case UINT32_ELEMENTS:
if (key_is_constant) {
__ LoadWord(result, mem_operand, r0);
break;
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoLoadKeyedExternalArray(instr);
} else if (instr->hydrogen()->representation().IsDouble()) {
DoLoadKeyedFixedDoubleArray(instr);
bool key_is_smi = instr->hydrogen()->key()->representation().IsSmi();
int base_offset = instr->base_offset();
- if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
Register address = scratch0();
DoubleRegister value(ToDoubleRegister(instr->value()));
if (key_is_constant) {
__ IndexToArrayOffset(r0, key, element_size_shift, key_is_smi);
__ add(address, external_pointer, r0);
}
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
__ frsp(double_scratch0(), value);
__ stfs(double_scratch0(), MemOperand(address, base_offset));
} else { // Storing doubles, not floats.
PrepareKeyedOperand(key, external_pointer, key_is_constant, key_is_smi,
constant_key, element_size_shift, base_offset);
switch (elements_kind) {
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_INT8_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
case INT8_ELEMENTS:
__ stbx(value, mem_operand);
}
break;
+ case EXTERNAL_INT16_ELEMENTS:
+ case EXTERNAL_UINT16_ELEMENTS:
case INT16_ELEMENTS:
case UINT16_ELEMENTS:
if (key_is_constant) {
__ sthx(value, mem_operand);
}
break;
+ case EXTERNAL_INT32_ELEMENTS:
+ case EXTERNAL_UINT32_ELEMENTS:
case INT32_ELEMENTS:
case UINT32_ELEMENTS:
if (key_is_constant) {
break;
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
// By cases: external, fast double
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoStoreKeyedExternalArray(instr);
} else if (instr->hydrogen()->value()->representation().IsDouble()) {
DoStoreKeyedFixedDoubleArray(instr);
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LInstruction* result = NULL;
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
LOperand* obj = NULL;
if (instr->representation().IsDouble()) {
obj = UseRegister(instr->elements());
}
bool needs_environment;
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_external() || instr->is_fixed_typed_array()) {
// see LCodeGen::DoLoadKeyedExternalArray
- needs_environment = elements_kind == UINT32_ELEMENTS &&
+ needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) &&
!instr->CheckFlag(HInstruction::kUint32);
} else {
// see LCodeGen::DoLoadKeyedFixedDoubleArray and
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
DCHECK(instr->elements()->representation().IsTagged());
bool needs_write_barrier = instr->NeedsWriteBarrier();
LOperand* object = NULL;
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
ElementsKind elements_kind() const { return hydrogen()->elements_kind(); }
+ bool is_external() const { return hydrogen()->is_external(); }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
inputs_[2] = value;
}
+ bool is_external() const { return hydrogen()->is_external(); }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS:
TYPED_ARRAYS(TYPED_ARRAY_CASE)
}
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case TYPE##_ELEMENTS: \
+ case EXTERNAL_##TYPE##_ELEMENTS:
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
}
break;
}
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS: {
+ Handle<ExternalUint8ClampedArray> pixels(
+ ExternalUint8ClampedArray::cast(receiver->elements()));
+ for (uint32_t j = 0; j < length; j++) {
+ Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
+ visitor->visit(j, e);
+ }
+ break;
+ }
case UINT8_CLAMPED_ELEMENTS: {
Handle<FixedUint8ClampedArray> pixels(
FixedUint8ClampedArray::cast(receiver->elements()));
}
break;
}
+ case EXTERNAL_INT8_ELEMENTS: {
+ IterateTypedArrayElements<ExternalInt8Array, int8_t>(
+ isolate, receiver, true, true, visitor);
+ break;
+ }
case INT8_ELEMENTS: {
IterateTypedArrayElements<FixedInt8Array, int8_t>(
isolate, receiver, true, true, visitor);
break;
}
+ case EXTERNAL_UINT8_ELEMENTS: {
+ IterateTypedArrayElements<ExternalUint8Array, uint8_t>(
+ isolate, receiver, true, true, visitor);
+ break;
+ }
case UINT8_ELEMENTS: {
IterateTypedArrayElements<FixedUint8Array, uint8_t>(
isolate, receiver, true, true, visitor);
break;
}
+ case EXTERNAL_INT16_ELEMENTS: {
+ IterateTypedArrayElements<ExternalInt16Array, int16_t>(
+ isolate, receiver, true, true, visitor);
+ break;
+ }
case INT16_ELEMENTS: {
IterateTypedArrayElements<FixedInt16Array, int16_t>(
isolate, receiver, true, true, visitor);
break;
}
+ case EXTERNAL_UINT16_ELEMENTS: {
+ IterateTypedArrayElements<ExternalUint16Array, uint16_t>(
+ isolate, receiver, true, true, visitor);
+ break;
+ }
case UINT16_ELEMENTS: {
IterateTypedArrayElements<FixedUint16Array, uint16_t>(
isolate, receiver, true, true, visitor);
break;
}
+ case EXTERNAL_INT32_ELEMENTS: {
+ IterateTypedArrayElements<ExternalInt32Array, int32_t>(
+ isolate, receiver, true, false, visitor);
+ break;
+ }
case INT32_ELEMENTS: {
IterateTypedArrayElements<FixedInt32Array, int32_t>(
isolate, receiver, true, false, visitor);
break;
}
+ case EXTERNAL_UINT32_ELEMENTS: {
+ IterateTypedArrayElements<ExternalUint32Array, uint32_t>(
+ isolate, receiver, true, false, visitor);
+ break;
+ }
case UINT32_ELEMENTS: {
IterateTypedArrayElements<FixedUint32Array, uint32_t>(
isolate, receiver, true, false, visitor);
break;
}
+ case EXTERNAL_FLOAT32_ELEMENTS: {
+ IterateTypedArrayElements<ExternalFloat32Array, float>(
+ isolate, receiver, false, false, visitor);
+ break;
+ }
case FLOAT32_ELEMENTS: {
IterateTypedArrayElements<FixedFloat32Array, float>(
isolate, receiver, false, false, visitor);
break;
}
+ case EXTERNAL_FLOAT64_ELEMENTS: {
+ IterateTypedArrayElements<ExternalFloat64Array, double>(
+ isolate, receiver, false, false, visitor);
+ break;
+ }
case FLOAT64_ELEMENTS: {
IterateTypedArrayElements<FixedFloat64Array, double>(
isolate, receiver, false, false, visitor);
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
- RUNTIME_ASSERT(!array->HasFixedTypedArrayElements() &&
+ RUNTIME_ASSERT(!array->HasExternalArrayElements() &&
+ !array->HasFixedTypedArrayElements() &&
!array->IsJSGlobalProxy());
JSObject::NormalizeElements(array);
return *array;
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FixedTypedArrayElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
// Properties test sitting with elements tests - not fooling anyone.
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
+#define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \
+ RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) { \
+ CONVERT_ARG_CHECKED(JSObject, obj, 0); \
+ return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \
+ }
+
+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(Runtime_HasFixed##Type##Elements) { \
CONVERT_ARG_CHECKED(JSObject, obj, 0); \
void Runtime::ArrayIdToTypeAndSize(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;
ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
size_t element_size = 1; // Bogus initialization.
+ ElementsKind external_elements_kind =
+ EXTERNAL_INT8_ELEMENTS; // Bogus initialization.
ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
- Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &fixed_elements_kind,
- &element_size);
+ Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
+ &fixed_elements_kind, &element_size);
RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
size_t byte_offset = 0;
Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
holder->set_buffer(*buffer);
- Handle<FixedTypedArrayBase> elements =
- isolate->factory()->NewFixedTypedArrayWithExternalPointer(
- static_cast<int>(length), array_type,
- static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
- holder->set_elements(*elements);
+ 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);
+ JSObject::SetMapAndElements(holder, map, elements);
+ DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind()));
} else {
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
Runtime::SetupArrayBuffer(isolate, buffer, true, NULL, byte_length,
ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
size_t element_size = 1; // Bogus initialization.
+ ElementsKind external_elements_kind =
+ EXTERNAL_INT8_ELEMENTS; // Bogus intialization.
ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
- Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &fixed_elements_kind,
- &element_size);
+ Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
+ &fixed_elements_kind, &element_size);
RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
holder->set_byte_length(*byte_length_obj);
holder->set_length(*length_obj);
- Handle<FixedTypedArrayBase> elements =
- isolate->factory()->NewFixedTypedArrayWithExternalPointer(
- static_cast<int>(length), array_type,
- static_cast<uint8_t*>(buffer->backing_store()));
- holder->set_elements(*elements);
+ Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
+ static_cast<int>(length), array_type,
+ static_cast<uint8_t*>(buffer->backing_store()));
+ Handle<Map> map =
+ JSObject::GetElementsTransitionMap(holder, external_elements_kind);
+ JSObject::SetMapAndElements(holder, map, elements);
if (source->IsJSTypedArray()) {
Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
F(HasFastHoleyElements, 1, 1) \
F(HasDictionaryElements, 1, 1) \
F(HasSloppyArgumentsElements, 1, 1) \
- F(HasFixedTypedArrayElements, 1, 1) \
+ F(HasExternalArrayElements, 1, 1) \
F(HasFastProperties, 1, 1) \
+ F(HasExternalUint8Elements, 1, 1) \
+ F(HasExternalInt8Elements, 1, 1) \
+ F(HasExternalUint16Elements, 1, 1) \
+ F(HasExternalInt16Elements, 1, 1) \
+ F(HasExternalUint32Elements, 1, 1) \
+ F(HasExternalInt32Elements, 1, 1) \
+ F(HasExternalFloat32Elements, 1, 1) \
+ F(HasExternalFloat64Elements, 1, 1) \
+ F(HasExternalUint8ClampedElements, 1, 1) \
F(HasFixedUint8Elements, 1, 1) \
F(HasFixedInt8Elements, 1, 1) \
F(HasFixedUint16Elements, 1, 1) \
};
static void ArrayIdToTypeAndSize(int array_id, ExternalArrayType* type,
+ ElementsKind* external_elements_kind,
ElementsKind* fixed_elements_kind,
size_t* element_size);
elements_kind,
instr->base_offset()));
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
__ cvtss2sd(result, result);
- } else if (elements_kind == FLOAT64_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
__ movsd(ToDoubleRegister(instr->result()), operand);
} else {
Register result(ToRegister(instr->result()));
switch (elements_kind) {
+ case EXTERNAL_INT8_ELEMENTS:
case INT8_ELEMENTS:
__ movsxbl(result, operand);
break;
+ case EXTERNAL_UINT8_ELEMENTS:
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
__ movzxbl(result, operand);
break;
+ case EXTERNAL_INT16_ELEMENTS:
case INT16_ELEMENTS:
__ movsxwl(result, operand);
break;
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
__ movzxwl(result, operand);
break;
+ case EXTERNAL_INT32_ELEMENTS:
case INT32_ELEMENTS:
__ movl(result, operand);
break;
+ case EXTERNAL_UINT32_ELEMENTS:
case UINT32_ELEMENTS:
__ movl(result, operand);
if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
DeoptimizeIf(negative, instr, Deoptimizer::kNegativeValue);
}
break;
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
case FAST_ELEMENTS:
void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoLoadKeyedExternalArray(instr);
} else if (instr->hydrogen()->representation().IsDouble()) {
DoLoadKeyedFixedDoubleArray(instr);
elements_kind,
instr->base_offset()));
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
XMMRegister value(ToDoubleRegister(instr->value()));
__ cvtsd2ss(value, value);
__ movss(operand, value);
- } else if (elements_kind == FLOAT64_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
__ movsd(operand, ToDoubleRegister(instr->value()));
} else {
Register value(ToRegister(instr->value()));
switch (elements_kind) {
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_INT8_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case INT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
__ movb(operand, value);
break;
+ case EXTERNAL_INT16_ELEMENTS:
+ case EXTERNAL_UINT16_ELEMENTS:
case INT16_ELEMENTS:
case UINT16_ELEMENTS:
__ movw(operand, value);
break;
+ case EXTERNAL_INT32_ELEMENTS:
+ case EXTERNAL_UINT32_ELEMENTS:
case INT32_ELEMENTS:
case UINT32_ELEMENTS:
__ movl(operand, value);
break;
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
case FAST_ELEMENTS:
void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoStoreKeyedExternalArray(instr);
} else if (instr->hydrogen()->value()->representation().IsDouble()) {
DoStoreKeyedFixedDoubleArray(instr);
FindDehoistedKeyDefinitions(instr->key());
}
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
LOperand* obj = UseRegisterAtStart(instr->elements());
result = DefineAsRegister(new(zone()) LLoadKeyed(obj, key));
} else {
}
bool needs_environment;
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_external() || instr->is_fixed_typed_array()) {
// see LCodeGen::DoLoadKeyedExternalArray
- needs_environment = elements_kind == UINT32_ELEMENTS &&
+ needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) &&
!instr->CheckFlag(HInstruction::kUint32);
} else {
// see LCodeGen::DoLoadKeyedFixedDoubleArray and
FindDehoistedKeyDefinitions(instr->key());
}
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
DCHECK(instr->elements()->representation().IsTagged());
bool needs_write_barrier = instr->NeedsWriteBarrier();
LOperand* object = NULL;
(instr->value()->representation().IsDouble() &&
IsDoubleOrFloatElementsKind(elements_kind)));
DCHECK(instr->elements()->representation().IsExternal());
- bool val_is_temp_register = elements_kind == UINT8_CLAMPED_ELEMENTS ||
- elements_kind == FLOAT32_ELEMENTS;
+ bool val_is_temp_register =
+ elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS;
LOperand* val = val_is_temp_register ? UseTempRegister(instr->value())
: UseRegister(instr->value());
LOperand* key = NULL;
// an index cannot fold the scale operation into a load and need an extra
// temp register to do the work.
return SmiValuesAre31Bits() && key_representation.IsSmi() &&
- (elements_kind == UINT8_ELEMENTS || elements_kind == INT8_ELEMENTS ||
- elements_kind == UINT8_CLAMPED_ELEMENTS);
+ (elements_kind == EXTERNAL_INT8_ELEMENTS ||
+ elements_kind == EXTERNAL_UINT8_ELEMENTS ||
+ elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS ||
+ elements_kind == UINT8_ELEMENTS ||
+ elements_kind == INT8_ELEMENTS ||
+ elements_kind == UINT8_CLAMPED_ELEMENTS);
}
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
+ bool is_external() const {
+ return hydrogen()->is_external();
+ }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
void PrintDataTo(StringStream* stream) override;
inputs_[2] = value;
}
+ bool is_external() const { return hydrogen()->is_external(); }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
instr->hydrogen()->key()->representation(),
elements_kind,
instr->base_offset()));
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
X87Mov(ToX87Register(instr->result()), operand, kX87FloatOperand);
- } else if (elements_kind == FLOAT64_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
X87Mov(ToX87Register(instr->result()), operand);
} else {
Register result(ToRegister(instr->result()));
switch (elements_kind) {
+ case EXTERNAL_INT8_ELEMENTS:
case INT8_ELEMENTS:
__ movsx_b(result, operand);
break;
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
case UINT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
__ movzx_b(result, operand);
break;
+ case EXTERNAL_INT16_ELEMENTS:
case INT16_ELEMENTS:
__ movsx_w(result, operand);
break;
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
__ movzx_w(result, operand);
break;
+ case EXTERNAL_INT32_ELEMENTS:
case INT32_ELEMENTS:
__ mov(result, operand);
break;
+ case EXTERNAL_UINT32_ELEMENTS:
case UINT32_ELEMENTS:
__ mov(result, operand);
if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
DeoptimizeIf(negative, instr, Deoptimizer::kNegativeValue);
}
break;
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
case FAST_SMI_ELEMENTS:
void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoLoadKeyedExternalArray(instr);
} else if (instr->hydrogen()->representation().IsDouble()) {
DoLoadKeyedFixedDoubleArray(instr);
instr->hydrogen()->key()->representation(),
elements_kind,
instr->base_offset()));
- if (elements_kind == FLOAT32_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+ elements_kind == FLOAT32_ELEMENTS) {
X87Mov(operand, ToX87Register(instr->value()), kX87FloatOperand);
- } else if (elements_kind == FLOAT64_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+ elements_kind == FLOAT64_ELEMENTS) {
uint64_t int_val = kHoleNanInt64;
int32_t lower = static_cast<int32_t>(int_val);
int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
} else {
Register value = ToRegister(instr->value());
switch (elements_kind) {
+ case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+ case EXTERNAL_UINT8_ELEMENTS:
+ case EXTERNAL_INT8_ELEMENTS:
case UINT8_ELEMENTS:
case INT8_ELEMENTS:
case UINT8_CLAMPED_ELEMENTS:
__ mov_b(operand, value);
break;
+ case EXTERNAL_INT16_ELEMENTS:
+ case EXTERNAL_UINT16_ELEMENTS:
case UINT16_ELEMENTS:
case INT16_ELEMENTS:
__ mov_w(operand, value);
break;
+ case EXTERNAL_INT32_ELEMENTS:
+ case EXTERNAL_UINT32_ELEMENTS:
case UINT32_ELEMENTS:
case INT32_ELEMENTS:
__ mov(operand, value);
break;
+ case EXTERNAL_FLOAT32_ELEMENTS:
+ case EXTERNAL_FLOAT64_ELEMENTS:
case FLOAT32_ELEMENTS:
case FLOAT64_ELEMENTS:
case FAST_SMI_ELEMENTS:
void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
// By cases...external, fast-double, fast
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_typed_elements()) {
DoStoreKeyedExternalArray(instr);
} else if (instr->hydrogen()->value()->representation().IsDouble()) {
DoStoreKeyedFixedDoubleArray(instr);
: UseRegisterOrConstantAtStart(instr->key());
LInstruction* result = NULL;
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
LOperand* obj = UseRegisterAtStart(instr->elements());
result = DefineAsRegister(new(zone()) LLoadKeyed(obj, key));
} else {
}
bool needs_environment;
- if (instr->is_fixed_typed_array()) {
+ if (instr->is_external() || instr->is_fixed_typed_array()) {
// see LCodeGen::DoLoadKeyedExternalArray
- needs_environment = elements_kind == UINT32_ELEMENTS &&
+ needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) &&
!instr->CheckFlag(HInstruction::kUint32);
} else {
// see LCodeGen::DoLoadKeyedFixedDoubleArray and
// Determine if we need a byte register in this case for the value.
bool val_is_fixed_register =
+ elements_kind == EXTERNAL_INT8_ELEMENTS ||
+ elements_kind == EXTERNAL_UINT8_ELEMENTS ||
+ elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS ||
elements_kind == UINT8_ELEMENTS ||
elements_kind == INT8_ELEMENTS ||
elements_kind == UINT8_CLAMPED_ELEMENTS;
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
- if (!instr->is_fixed_typed_array()) {
+ if (!instr->is_typed_elements()) {
DCHECK(instr->elements()->representation().IsTagged());
DCHECK(instr->key()->representation().IsInteger32() ||
instr->key()->representation().IsSmi());
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ bool is_external() const {
+ return hydrogen()->is_external();
+ }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
// an index cannot fold the scale operation into a load and need an extra
// temp register to do the work.
return key_representation.IsSmi() &&
- (elements_kind == UINT8_ELEMENTS || elements_kind == INT8_ELEMENTS ||
- elements_kind == UINT8_CLAMPED_ELEMENTS);
+ (elements_kind == EXTERNAL_INT8_ELEMENTS ||
+ elements_kind == EXTERNAL_UINT8_ELEMENTS ||
+ elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS ||
+ elements_kind == UINT8_ELEMENTS ||
+ elements_kind == INT8_ELEMENTS ||
+ elements_kind == UINT8_CLAMPED_ELEMENTS);
}
inputs_[2] = val;
}
+ bool is_external() const { return hydrogen()->is_external(); }
bool is_fixed_typed_array() const {
return hydrogen()->is_fixed_typed_array();
}
+ bool is_typed_elements() const {
+ return is_external() || is_fixed_typed_array();
+ }
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
values_builder.AddFormatted("a[%d] = 0x%08x;", i, kValues[i]);
}
- // Note that below source creates two different typed arrays with the same
- // elements kind to get coverage for both (on heap / with external backing
- // store) access patterns.
+ // Note that below source creates two different typed arrays with distinct
+ // elements kind to get coverage for both access patterns:
+ // - IsFixedTypedArrayElementsKind(x)
+ // - IsExternalArrayElementsKind(y)
const char* source =
"(function(a) {"
" var x = (a = new %sArray(%d)); %s;"
" var y = (a = new %sArray(%d)); %s; %%TypedArrayGetBuffer(y);"
" if (!%%HasFixed%sElements(x)) %%AbortJS('x');"
- " if (!%%HasFixed%sElements(y)) %%AbortJS('y');"
+ " if (!%%HasExternal%sElements(y)) %%AbortJS('y');"
" function f(a,b) {"
" a = a | 0; b = b | 0;"
" return x[a] + y[b];"
values_builder.AddFormatted("a[%d] = 0x%08x;", i, kValues[i]);
}
- // Note that below source creates two different typed arrays with the same
- // elements kind to get coverage for both (on heap/with external backing
- // store) access patterns.
+ // Note that below source creates two different typed arrays with distinct
+ // elements kind to get coverage for both access patterns:
+ // - IsFixedTypedArrayElementsKind(x)
+ // - IsExternalArrayElementsKind(y)
const char* source =
"(function(a) {"
" var x = (a = new %sArray(%d)); %s;"
" var y = (a = new %sArray(%d)); %s; %%TypedArrayGetBuffer(y);"
" if (!%%HasFixed%sElements(x)) %%AbortJS('x');"
- " if (!%%HasFixed%sElements(y)) %%AbortJS('y');"
+ " if (!%%HasExternal%sElements(y)) %%AbortJS('y');"
" function f(a,b) {"
" a = a | 0; b = b | 0;"
" var t = x[a];"
THREADED_TEST(Uint8Array) {
- TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
+ TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array,
v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
}
THREADED_TEST(Int8Array) {
- TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
+ TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array,
v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F);
}
THREADED_TEST(Uint16Array) {
- TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
+ TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array,
v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF);
}
THREADED_TEST(Int16Array) {
- TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
+ TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array,
v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000,
0x7FFF);
}
THREADED_TEST(Uint32Array) {
- TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
+ TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array,
v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX);
}
THREADED_TEST(Int32Array) {
- TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
+ TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array,
v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN,
INT_MAX);
}
THREADED_TEST(Float32Array) {
- TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
+ TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array,
v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500);
}
THREADED_TEST(Float64Array) {
- TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
+ TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array,
v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500);
}
THREADED_TEST(Uint8ClampedArray) {
TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
- i::FixedUint8ClampedArray, v8::ArrayBuffer>(
+ i::ExternalUint8ClampedArray, v8::ArrayBuffer>(
i::kExternalUint8ClampedArray, 0, 0xFF);
}
THREADED_TEST(SharedUint8Array) {
i::FLAG_harmony_sharedarraybuffer = true;
- TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
+ TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array,
v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
}
THREADED_TEST(SharedInt8Array) {
i::FLAG_harmony_sharedarraybuffer = true;
- TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
+ TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array,
v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
0x7F);
}
THREADED_TEST(SharedUint16Array) {
i::FLAG_harmony_sharedarraybuffer = true;
- TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
+ TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array,
v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
0xFFFF);
}
THREADED_TEST(SharedInt16Array) {
i::FLAG_harmony_sharedarraybuffer = true;
- TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
+ TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array,
v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
0x7FFF);
}
THREADED_TEST(SharedUint32Array) {
i::FLAG_harmony_sharedarraybuffer = true;
- TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
+ TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array,
v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
UINT_MAX);
}
THREADED_TEST(SharedInt32Array) {
i::FLAG_harmony_sharedarraybuffer = true;
- TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
+ TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array,
v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
INT_MAX);
}
THREADED_TEST(SharedFloat32Array) {
i::FLAG_harmony_sharedarraybuffer = true;
- TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
+ TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array,
v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
500);
}
THREADED_TEST(SharedFloat64Array) {
i::FLAG_harmony_sharedarraybuffer = true;
- TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
+ TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array,
v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
500);
}
THREADED_TEST(SharedUint8ClampedArray) {
i::FLAG_harmony_sharedarraybuffer = true;
TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
- i::FixedUint8ClampedArray, v8::SharedArrayBuffer>(
+ i::ExternalUint8ClampedArray, v8::SharedArrayBuffer>(
i::kExternalUint8ClampedArray, 0, 0xFF);
}
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',
if (%HasFastDoubleElements(obj)) return elements_kind.fast_double;
if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
+ // Every external kind is also an external array.
+ if (%HasExternalInt8Elements(obj)) {
+ return elements_kind.external_int8;
+ }
+ if (%HasExternalUint8Elements(obj)) {
+ return elements_kind.external_uint8;
+ }
+ if (%HasExternalInt16Elements(obj)) {
+ return elements_kind.external_int16;
+ }
+ if (%HasExternalUint16Elements(obj)) {
+ return elements_kind.external_uint16;
+ }
+ if (%HasExternalInt32Elements(obj)) {
+ return elements_kind.external_int32;
+ }
+ if (%HasExternalUint32Elements(obj)) {
+ return elements_kind.external_uint32;
+ }
+ if (%HasExternalFloat32Elements(obj)) {
+ return elements_kind.external_float32;
+ }
+ if (%HasExternalFloat64Elements(obj)) {
+ return elements_kind.external_float64;
+ }
+ if (%HasExternalUint8ClampedElements(obj)) {
+ return elements_kind.external_uint8_clamped;
+ }
if (%HasFixedInt8Elements(obj)) {
return elements_kind.fixed_int8;
}
assertKind(elements_kind.fixed_uint8_clamped, new Uint8ClampedArray(512));
var ab = new ArrayBuffer(128);
- assertKind(elements_kind.fixed_int8, new Int8Array(ab));
- assertKind(elements_kind.fixed_uint8, new Uint8Array(ab));
- assertKind(elements_kind.fixed_int16, new Int16Array(ab));
- assertKind(elements_kind.fixed_uint16, new Uint16Array(ab));
- assertKind(elements_kind.fixed_int32, new Int32Array(ab));
- assertKind(elements_kind.fixed_uint32, new Uint32Array(ab));
- assertKind(elements_kind.fixed_float32, new Float32Array(ab));
- assertKind(elements_kind.fixed_float64, new Float64Array(ab));
- assertKind(elements_kind.fixed_uint8_clamped, new Uint8ClampedArray(ab));
+ 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) {
// Flags: --stress-runs=2
var elements_kind = {
- fast_smi_only : 'fast smi only elements',
- fast : 'fast elements',
- fast_double : 'fast double elements',
- dictionary : 'dictionary 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'
+ 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'
}
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;
-
- if (%HasFixedInt8Elements(obj)) {
- return elements_kind.fixed_int8;
+ // Every external kind is also an external array.
+ assertTrue(%HasExternalArrayElements(obj));
+ if (%HasExternalByteElements(obj)) {
+ return elements_kind.external_byte;
}
- if (%HasFixedUint8Elements(obj)) {
- return elements_kind.fixed_uint8;
+ if (%HasExternalUnsignedByteElements(obj)) {
+ return elements_kind.external_unsigned_byte;
}
- if (%HasFixedInt16Elements(obj)) {
- return elements_kind.fixed_int16;
+ if (%HasExternalShortElements(obj)) {
+ return elements_kind.external_short;
}
- if (%HasFixedUint16Elements(obj)) {
- return elements_kind.fixed_uint16;
+ if (%HasExternalUnsignedShortElements(obj)) {
+ return elements_kind.external_unsigned_short;
}
- if (%HasFixedInt32Elements(obj)) {
- return elements_kind.fixed_int32;
+ if (%HasExternalIntElements(obj)) {
+ return elements_kind.external_int;
}
- if (%HasFixedUint32Elements(obj)) {
- return elements_kind.fixed_uint32;
+ if (%HasExternalUnsignedIntElements(obj)) {
+ return elements_kind.external_unsigned_int;
}
- if (%HasFixedFloat32Elements(obj)) {
- return elements_kind.fixed_float32;
+ if (%HasExternalFloatElements(obj)) {
+ return elements_kind.external_float;
}
- if (%HasFixedFloat64Elements(obj)) {
- return elements_kind.fixed_float64;
+ if (%HasExternalDoubleElements(obj)) {
+ return elements_kind.external_double;
}
- if (%HasFixedUint8ClampedElements(obj)) {
- return elements_kind.fixed_uint8_clamped;
+ if (%HasExternalPixelElements(obj)) {
+ return elements_kind.external_pixel;
}
}
// Flags: --stress-runs=2
var elements_kind = {
- fast_smi_only : 'fast smi only elements',
- fast : 'fast elements',
- fast_double : 'fast double elements',
- dictionary : 'dictionary 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'
+ 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'
}
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;
-
- if (%HasFixedInt8Elements(obj)) {
- return elements_kind.fixed_int8;
+ // Every external kind is also an external array.
+ assertTrue(%HasExternalArrayElements(obj));
+ if (%HasExternalByteElements(obj)) {
+ return elements_kind.external_byte;
}
- if (%HasFixedUint8Elements(obj)) {
- return elements_kind.fixed_uint8;
+ if (%HasExternalUnsignedByteElements(obj)) {
+ return elements_kind.external_unsigned_byte;
}
- if (%HasFixedInt16Elements(obj)) {
- return elements_kind.fixed_int16;
+ if (%HasExternalShortElements(obj)) {
+ return elements_kind.external_short;
}
- if (%HasFixedUint16Elements(obj)) {
- return elements_kind.fixed_uint16;
+ if (%HasExternalUnsignedShortElements(obj)) {
+ return elements_kind.external_unsigned_short;
}
- if (%HasFixedInt32Elements(obj)) {
- return elements_kind.fixed_int32;
+ if (%HasExternalIntElements(obj)) {
+ return elements_kind.external_int;
}
- if (%HasFixedUint32Elements(obj)) {
- return elements_kind.fixed_uint32;
+ if (%HasExternalUnsignedIntElements(obj)) {
+ return elements_kind.external_unsigned_int;
}
- if (%HasFixedFloat32Elements(obj)) {
- return elements_kind.fixed_float32;
+ if (%HasExternalFloatElements(obj)) {
+ return elements_kind.external_float;
}
- if (%HasFixedFloat64Elements(obj)) {
- return elements_kind.fixed_float64;
+ if (%HasExternalDoubleElements(obj)) {
+ return elements_kind.external_double;
}
- if (%HasFixedUint8ClampedElements(obj)) {
- return elements_kind.fixed_uint8_clamped;
+ if (%HasExternalPixelElements(obj)) {
+ return elements_kind.external_pixel;
}
}