static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
static const int kContextHeaderSize = 2 * kApiPointerSize;
- static const int kContextEmbedderDataIndex = 80;
+ static const int kContextEmbedderDataIndex = 81;
static const int kFullStringRepresentationMask = 0x07;
static const int kStringEncodingMask = 0x4;
static const int kExternalTwoByteRepresentationTag = 0x02;
const int kNormalOffset =
Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX);
const int kAliasedOffset =
- Context::SlotOffset(Context::ALIASED_ARGUMENTS_MAP_INDEX);
+ Context::SlotOffset(Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
__ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
__ ldr(r4, FieldMemOperand(r4, GlobalObject::kNativeContextOffset));
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
__ Ldr(sloppy_args_map,
ContextMemOperand(global_ctx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
- __ Ldr(aliased_args_map,
- ContextMemOperand(global_ctx, Context::ALIASED_ARGUMENTS_MAP_INDEX));
+ __ Ldr(
+ aliased_args_map,
+ ContextMemOperand(global_ctx, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX));
__ Cmp(mapped_params, 0);
__ CmovX(sloppy_args_map, aliased_args_map, ne);
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
DCHECK(IsFastObjectElementsKind(map->elements_kind()));
}
- { // --- aliased arguments map
- Handle<Map> map =
- Map::Copy(isolate->sloppy_arguments_map(), "AliasedArguments");
- map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
+ { // --- fast and slow aliased arguments map
+ Handle<Map> map = isolate->sloppy_arguments_map();
+ map = Map::Copy(map, "FastAliasedArguments");
+ map->set_elements_kind(FAST_SLOPPY_ARGUMENTS_ELEMENTS);
+ DCHECK_EQ(2, map->pre_allocated_property_fields());
+ native_context()->set_fast_aliased_arguments_map(*map);
+
+ map = Map::Copy(map, "SlowAliasedArguments");
+ map->set_elements_kind(SLOW_SLOPPY_ARGUMENTS_ELEMENTS);
DCHECK_EQ(2, map->pre_allocated_property_fields());
- native_context()->set_aliased_arguments_map(*map);
+ native_context()->set_slow_aliased_arguments_map(*map);
}
{ // --- strict mode arguments map
{
AccessorConstantDescriptor d(factory()->iterator_symbol(),
arguments_iterator, attribs);
- Handle<Map> map(native_context()->aliased_arguments_map());
+ Handle<Map> map(native_context()->fast_aliased_arguments_map());
+ Map::EnsureDescriptorSlack(map, 1);
+ map->AppendDescriptor(&d);
+ }
+ {
+ AccessorConstantDescriptor d(factory()->iterator_symbol(),
+ arguments_iterator, attribs);
+ Handle<Map> map(native_context()->slow_aliased_arguments_map());
Map::EnsureDescriptorSlack(map, 1);
map->AppendDescriptor(&d);
}
}
kind_if.Else();
- // The SLOPPY_ARGUMENTS_ELEMENTS check generates a "kind_if.Then"
+ // The SLOW_SLOPPY_ARGUMENTS_ELEMENTS check generates a "kind_if.Then"
+ STATIC_ASSERT(FAST_SLOPPY_ARGUMENTS_ELEMENTS <
+ SLOW_SLOPPY_ARGUMENTS_ELEMENTS);
BuildElementsKindLimitCheck(&kind_if, bit_field2,
- SLOPPY_ARGUMENTS_ELEMENTS);
+ SLOW_SLOPPY_ARGUMENTS_ELEMENTS);
// Non-strict elements are not handled.
Add<HDeoptimize>(Deoptimizer::kNonStrictElementsInKeyedLoadGenericStub,
Deoptimizer::EAGER);
case DICTIONARY_ELEMENTS:
ElementHandlerCompiler::GenerateStoreSlow(masm);
break;
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
V(BOUND_FUNCTION_MAP_INDEX, Map, bound_function_map) \
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map) \
V(SLOPPY_ARGUMENTS_MAP_INDEX, Map, sloppy_arguments_map) \
- V(ALIASED_ARGUMENTS_MAP_INDEX, Map, aliased_arguments_map) \
+ V(FAST_ALIASED_ARGUMENTS_MAP_INDEX, Map, fast_aliased_arguments_map) \
+ V(SLOW_ALIASED_ARGUMENTS_MAP_INDEX, Map, slow_aliased_arguments_map) \
V(STRICT_ARGUMENTS_MAP_INDEX, Map, strict_arguments_map) \
V(MESSAGE_LISTENERS_INDEX, JSObject, message_listeners) \
V(MAKE_MESSAGE_FUN_INDEX, JSFunction, make_message_fun) \
GLOBAL_PROXY_INDEX = MIN_CONTEXT_SLOTS,
SECURITY_TOKEN_INDEX,
SLOPPY_ARGUMENTS_MAP_INDEX,
- ALIASED_ARGUMENTS_MAP_INDEX,
+ FAST_ALIASED_ARGUMENTS_MAP_INDEX,
+ SLOW_ALIASED_ARGUMENTS_MAP_INDEX,
STRICT_ARGUMENTS_MAP_INDEX,
REGEXP_RESULT_MAP_INDEX,
SLOPPY_FUNCTION_MAP_INDEX,
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
return kPointerSizeLog2;
}
UNREACHABLE();
}
-ElementsKind GetNextMoreGeneralFastElementsKind(ElementsKind elements_kind,
- bool allow_only_packed) {
- DCHECK(IsFastElementsKind(elements_kind));
- DCHECK(elements_kind != TERMINAL_FAST_ELEMENTS_KIND);
- while (true) {
- elements_kind = GetNextTransitionElementsKind(elements_kind);
- if (!IsFastHoleyElementsKind(elements_kind) || !allow_only_packed) {
- return elements_kind;
- }
- }
- UNREACHABLE();
- return TERMINAL_FAST_ELEMENTS_KIND;
-}
-
-
static bool IsTypedArrayElementsKind(ElementsKind elements_kind) {
return IsFixedTypedArrayElementsKind(elements_kind) ||
IsExternalArrayElementsKind(elements_kind);
// The "slow" kind.
DICTIONARY_ELEMENTS,
- SLOPPY_ARGUMENTS_ELEMENTS,
+
+ FAST_SLOPPY_ARGUMENTS_ELEMENTS,
+ SLOW_SLOPPY_ARGUMENTS_ELEMENTS,
+
// The "fast" kind for external arrays
EXTERNAL_INT8_ELEMENTS,
EXTERNAL_UINT8_ELEMENTS,
inline bool IsSloppyArgumentsElements(ElementsKind kind) {
- return kind == SLOPPY_ARGUMENTS_ELEMENTS;
+ return kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS ||
+ kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
}
inline bool IsTransitionElementsKind(ElementsKind kind) {
- return IsFastElementsKind(kind) || IsFixedTypedArrayElementsKind(kind);
+ return IsFastElementsKind(kind) || IsFixedTypedArrayElementsKind(kind) ||
+ kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
}
}
-ElementsKind GetNextMoreGeneralFastElementsKind(ElementsKind elements_kind,
- bool allow_only_packed);
-
-
-inline bool CanTransitionToMoreGeneralFastElementsKind(
- ElementsKind elements_kind,
- bool allow_only_packed) {
- return IsFastElementsKind(elements_kind) &&
- (elements_kind != TERMINAL_FAST_ELEMENTS_KIND &&
- (!allow_only_packed || elements_kind != FAST_ELEMENTS));
-}
-
-
} } // namespace v8::internal
#endif // V8_ELEMENTS_KIND_H_
// - FixedUint8ClampedElementsAccessor
// - DictionaryElementsAccessor
// - SloppyArgumentsElementsAccessor
+// - FastSloppyArgumentsElementsAccessor
+// - SlowSloppyArgumentsElementsAccessor
namespace v8 {
// fast element handler for smi-only arrays. The implementation is currently
// identical. Note that the order must match that of the ElementsKind enum for
// the |accessor_array[]| below to work.
-#define ELEMENTS_LIST(V) \
- V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \
- V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, \
- FixedArray) \
- V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
- V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \
- V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, \
- FixedDoubleArray) \
- V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \
- FixedDoubleArray) \
- V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, \
- SeededNumberDictionary) \
- V(SloppyArgumentsElementsAccessor, 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) \
- V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array) \
- V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array) \
- V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array) \
- V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array) \
- V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array) \
- V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, \
+#define ELEMENTS_LIST(V) \
+ V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \
+ V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray) \
+ V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
+ V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \
+ V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
+ V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \
+ FixedDoubleArray) \
+ V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary) \
+ V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS, \
+ 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) \
+ V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array) \
+ V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array) \
+ V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array) \
+ V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array) \
+ V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array) \
+ V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, \
FixedUint8ClampedArray)
typename ElementsTraitsParam>
class ElementsAccessorBase : public ElementsAccessor {
protected:
+ template <typename SloppyArgumentsElementsAccessorSubclass,
+ typename ArgumentsAccessor, typename KindTraits>
+ friend class SloppyArgumentsElementsAccessor;
explicit ElementsAccessorBase(const char* name)
: ElementsAccessor(name) { }
};
+class FastSloppyArgumentsElementsAccessor;
+class FastHoleyObjectElementsAccessor;
+template <typename SloppyArgumentsElementsAccessorSubclass,
+ typename ArgumentsAccessor, typename KindTraits>
+class SloppyArgumentsElementsAccessor;
+
// Super class for all fast element arrays.
template<typename FastElementsAccessorSubclass,
typename KindTraits>
protected:
friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
- friend class SloppyArgumentsElementsAccessor;
+ friend class SloppyArgumentsElementsAccessor<
+ FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
+ ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >;
typedef typename KindTraits::BackingStore BackingStore;
};
-static inline ElementsKind ElementsKindForArray(FixedArrayBase* array) {
- switch (array->map()->instance_type()) {
- case FIXED_ARRAY_TYPE:
- if (array->IsDictionary()) {
- return DICTIONARY_ELEMENTS;
- } else {
- return FAST_HOLEY_ELEMENTS;
- }
- case FIXED_DOUBLE_ARRAY_TYPE:
- return FAST_HOLEY_DOUBLE_ELEMENTS;
-
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ARRAY_TYPE: \
- return EXTERNAL_##TYPE##_ELEMENTS; \
- case FIXED_##TYPE##_ARRAY_TYPE: \
- return TYPE##_ELEMENTS;
-
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
-
- default:
- UNREACHABLE();
- }
- return FAST_HOLEY_ELEMENTS;
-}
-
-
template<typename FastElementsAccessorSubclass,
typename KindTraits>
class FastSmiOrObjectElementsAccessor
CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
copy_size);
break;
- case SLOPPY_ARGUMENTS_ELEMENTS: {
- // TODO(verwaest): This is a temporary hack to support extending
- // SLOPPY_ARGUMENTS_ELEMENTS in GrowCapacityAndConvert.
- // This case should be UNREACHABLE().
- FixedArray* parameter_map = FixedArray::cast(from);
- FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
- ElementsKind from_kind = ElementsKindForArray(arguments);
- CopyElementsImpl(arguments, from_start, to, from_kind,
- to_start, packed_size, copy_size);
- break;
- }
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
+ UNREACHABLE();
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
CopyDictionaryToDoubleElements(from, from_start, to, to_start,
copy_size);
break;
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
#undef FIXED_ELEMENTS_ACCESSOR
+class SlowSloppyArgumentsElementsAccessor;
+
class DictionaryElementsAccessor
: public ElementsAccessorBase<DictionaryElementsAccessor,
array->set_length(*length_obj);
}
+ static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
+ FixedArrayBase* to, ElementsKind from_kind,
+ uint32_t to_start, int packed_size,
+ int copy_size) {
+ UNREACHABLE();
+ }
+
+
+ protected:
+ friend class ElementsAccessorBase<DictionaryElementsAccessor,
+ ElementsKindTraits<DICTIONARY_ELEMENTS> >;
+ friend class SlowSloppyArgumentsElementsAccessor;
+ friend class SloppyArgumentsElementsAccessor<
+ SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
+ ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >;
+
static void DeleteCommon(Handle<JSObject> obj, uint32_t key,
LanguageMode language_mode) {
Isolate* isolate = obj->GetIsolate();
Handle<FixedArray> backing_store(FixedArray::cast(obj->elements()),
isolate);
- bool is_arguments =
- (obj->GetElementsKind() == SLOPPY_ARGUMENTS_ELEMENTS);
+ bool is_arguments = obj->HasSloppyArgumentsElements();
if (is_arguments) {
backing_store = handle(FixedArray::cast(backing_store->get(1)), isolate);
}
}
}
- static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
- FixedArrayBase* to, ElementsKind from_kind,
- uint32_t to_start, int packed_size,
- int copy_size) {
- UNREACHABLE();
- }
-
-
- protected:
- friend class ElementsAccessorBase<DictionaryElementsAccessor,
- ElementsKindTraits<DICTIONARY_ELEMENTS> >;
-
virtual void Delete(Handle<JSObject> obj, uint32_t key,
LanguageMode language_mode) final {
DeleteCommon(obj, key, language_mode);
};
-class SloppyArgumentsElementsAccessor : public ElementsAccessorBase<
- SloppyArgumentsElementsAccessor,
- ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> > {
+template <typename SloppyArgumentsElementsAccessorSubclass,
+ typename ArgumentsAccessor, typename KindTraits>
+class SloppyArgumentsElementsAccessor
+ : public ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
+ KindTraits> {
public:
explicit SloppyArgumentsElementsAccessor(const char* name)
- : ElementsAccessorBase<
- SloppyArgumentsElementsAccessor,
- ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
+ : ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
+ KindTraits>(name) {}
+
protected:
- friend class ElementsAccessorBase<
- SloppyArgumentsElementsAccessor,
- ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> >;
+ friend class ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
+ KindTraits>;
static Handle<Object> GetImpl(Handle<JSObject> obj, uint32_t key,
Handle<FixedArrayBase> parameters) {
// Object is not mapped, defer to the arguments.
Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)),
isolate);
- Handle<Object> result =
- ElementsAccessor::ForArray(arguments)->Get(obj, key, arguments);
+ Handle<Object> result = ArgumentsAccessor::GetImpl(obj, key, arguments);
// Elements of the arguments object in slow mode might be slow aliases.
if (result->IsAliasedArgumentsEntry()) {
DisallowHeapAllocation no_gc;
}
}
+ virtual void Delete(Handle<JSObject> obj, uint32_t key,
+ LanguageMode language_mode) final {
+ FixedArray* parameter_map = FixedArray::cast(obj->elements());
+ if (!GetParameterMapArg(parameter_map, key)->IsTheHole()) {
+ // TODO(kmillikin): We could check if this was the last aliased
+ // parameter, and revert to normal elements in that case. That
+ // would enable GC of the context.
+ parameter_map->set_the_hole(key + 2);
+ } else {
+ ArgumentsAccessor::DeleteCommon(obj, key, language_mode);
+ }
+ }
+
static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
uint32_t capacity) {
- Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
- Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
- ElementsKind from_kind = old_elements->IsDictionary() ? DICTIONARY_ELEMENTS
- : FAST_HOLEY_ELEMENTS;
- // This method should only be called if there's a reason to update the
- // elements.
- DCHECK(IsDictionaryElementsKind(from_kind) ||
- static_cast<uint32_t>(old_elements->length()) < capacity);
- Handle<FixedArrayBase> elements =
- ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
- parameter_map->set(1, *elements);
- JSObject::ValidateElements(object);
+ UNREACHABLE();
}
static void SetImpl(FixedArrayBase* store, uint32_t key, Object* value) {
context->set(context_index, value);
} else {
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- ElementsAccessor::ForArray(arguments)->Set(arguments, key, value);
- }
- }
-
- static void ReconfigureImpl(Handle<JSObject> object,
- Handle<FixedArrayBase> store, uint32_t index,
- Handle<Object> value,
- PropertyAttributes attributes) {
- Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
- uint32_t length = parameter_map->length() - 2;
- if (index < length) {
- Object* probe = parameter_map->get(index + 2);
- DCHECK(!probe->IsTheHole());
- Context* context = Context::cast(parameter_map->get(0));
- int context_index = Smi::cast(probe)->value();
- DCHECK(!context->get(context_index)->IsTheHole());
- context->set(context_index, *value);
-
- // Redefining attributes of an aliased element destroys fast aliasing.
- parameter_map->set_the_hole(index + 2);
- // For elements that are still writable we re-establish slow aliasing.
- if ((attributes & READ_ONLY) == 0) {
- Isolate* isolate = store->GetIsolate();
- value = isolate->factory()->NewAliasedArgumentsEntry(context_index);
- }
-
- PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
- Handle<SeededNumberDictionary> arguments =
- parameter_map->get(1)->IsSeededNumberDictionary()
- ? handle(SeededNumberDictionary::cast(parameter_map->get(1)))
- : JSObject::NormalizeElements(object);
- arguments = SeededNumberDictionary::AddNumberEntry(arguments, index,
- value, details);
- parameter_map->set(1, *arguments);
- } else {
- Handle<FixedArrayBase> arguments(
- FixedArrayBase::cast(parameter_map->get(1)));
- ElementsAccessor::ForArray(arguments)
- ->Reconfigure(object, arguments, index - length, value, attributes);
+ ArgumentsAccessor::SetImpl(arguments, key, value);
}
}
- static void AddImpl(Handle<JSObject> object, uint32_t key,
- Handle<Object> value, PropertyAttributes attributes,
- uint32_t new_capacity) {
- DCHECK_EQ(NONE, attributes);
- Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
- Handle<FixedArrayBase> old_elements(
- FixedArrayBase::cast(parameter_map->get(1)));
- if (old_elements->IsSeededNumberDictionary() ||
- static_cast<uint32_t>(old_elements->length()) < new_capacity) {
- GrowCapacityAndConvertImpl(object, new_capacity);
- }
- SetImpl(object->elements(), key, *value);
- }
-
static MaybeHandle<AccessorPair> GetAccessorPairImpl(
Handle<JSObject> obj, uint32_t key, Handle<FixedArrayBase> parameters) {
Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
} else {
// If not aliased, check the arguments.
Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
- return ElementsAccessor::ForArray(arguments)
- ->GetAccessorPair(obj, key, arguments);
+ return ArgumentsAccessor::GetAccessorPairImpl(obj, key, arguments);
}
}
UNREACHABLE();
}
- virtual void Delete(Handle<JSObject> obj, uint32_t key,
- LanguageMode language_mode) final {
- Isolate* isolate = obj->GetIsolate();
- Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
- Handle<Object> probe(GetParameterMapArg(*parameter_map, key), isolate);
- if (!probe->IsTheHole()) {
- // TODO(kmillikin): We could check if this was the last aliased
- // parameter, and revert to normal elements in that case. That
- // would enable GC of the context.
- parameter_map->set_the_hole(key + 2);
- } else {
- Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
- if (arguments->IsDictionary()) {
- DictionaryElementsAccessor::DeleteCommon(obj, key, language_mode);
- } else {
- // It's difficult to access the version of DeleteCommon that is declared
- // in the templatized super class, call the concrete implementation in
- // the class for the most generalized ElementsKind subclass.
- FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, language_mode);
- }
- }
- }
-
- static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
- FixedArrayBase* to, ElementsKind from_kind,
- uint32_t to_start, int packed_size,
- int copy_size) {
- DCHECK(!to->IsDictionary());
- if (from_kind == DICTIONARY_ELEMENTS) {
- CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
- to_start, copy_size);
- } else {
- DCHECK_EQ(FAST_HOLEY_ELEMENTS, from_kind);
- CopyObjectToObjectElements(from, from_kind, from_start, to,
- FAST_HOLEY_ELEMENTS, to_start, copy_size);
- }
- }
-
static uint32_t GetCapacityImpl(JSObject* holder,
FixedArrayBase* backing_store) {
FixedArray* parameter_map = FixedArray::cast(backing_store);
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
return parameter_map->length() - 2 +
- ForArray(arguments)->GetCapacity(holder, arguments);
+ ArgumentsAccessor::GetCapacityImpl(holder, arguments);
}
static bool HasIndexImpl(FixedArrayBase* parameters, uint32_t index) {
}
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
- return ForArray(arguments)->HasIndex(arguments, index - length);
+ return ArgumentsAccessor::HasIndexImpl(arguments, index - length);
}
static uint32_t GetKeyForIndexImpl(FixedArrayBase* parameters,
if (index < length) return index;
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- return ForArray(arguments)->GetKeyForIndex(arguments, index - length);
+ return ArgumentsAccessor::GetKeyForIndexImpl(arguments, index - length);
}
static uint32_t GetIndexForKeyImpl(JSObject* holder,
if (!probe->IsTheHole()) return key;
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- uint32_t index = ElementsAccessor::ForArray(arguments)
- ->GetIndexForKey(holder, arguments, key);
+ uint32_t index =
+ ArgumentsAccessor::GetIndexForKeyImpl(holder, arguments, key);
if (index == kMaxUInt32) return index;
return (parameter_map->length() - 2) + index;
}
}
index -= length;
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- return ElementsAccessor::ForArray(arguments)->GetDetails(arguments, index);
+ return ArgumentsAccessor::GetDetailsImpl(arguments, index);
}
- private:
static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t key) {
uint32_t length = parameter_map->length() - 2;
return key < length
};
-ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
- return elements_accessors_[ElementsKindForArray(array)];
-}
+class FastSloppyArgumentsElementsAccessor
+ : public SloppyArgumentsElementsAccessor<
+ FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
+ ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
+ public:
+ friend class SloppyArgumentsElementsAccessor<
+ FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
+ ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >;
+ friend class ElementsAccessorBase<
+ FastSloppyArgumentsElementsAccessor,
+ ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >;
+ explicit FastSloppyArgumentsElementsAccessor(const char* name)
+ : SloppyArgumentsElementsAccessor<
+ FastSloppyArgumentsElementsAccessor,
+ FastHoleyObjectElementsAccessor,
+ ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
+
+ protected:
+ static void AddImpl(Handle<JSObject> object, uint32_t key,
+ Handle<Object> value, PropertyAttributes attributes,
+ uint32_t new_capacity) {
+ DCHECK_EQ(NONE, attributes);
+ Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
+ Handle<FixedArrayBase> old_elements(
+ FixedArrayBase::cast(parameter_map->get(1)));
+ if (old_elements->IsSeededNumberDictionary() ||
+ static_cast<uint32_t>(old_elements->length()) < new_capacity) {
+ GrowCapacityAndConvertImpl(object, new_capacity);
+ }
+ SetImpl(object->elements(), key, *value);
+ }
+ static void ReconfigureImpl(Handle<JSObject> object,
+ Handle<FixedArrayBase> store, uint32_t index,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ Handle<SeededNumberDictionary> dictionary =
+ JSObject::NormalizeElements(object);
+ FixedArray::cast(*store)->set(1, *dictionary);
+ uint32_t length = static_cast<uint32_t>(store->length()) - 2;
+ if (index >= length) {
+ index = dictionary->FindEntry(index - length) + length;
+ }
+ object->GetElementsAccessor()->Reconfigure(object, store, index, value,
+ attributes);
+ }
-ElementsAccessor* ElementsAccessor::ForArray(Handle<FixedArrayBase> array) {
- return ForArray(*array);
-}
+ static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
+ FixedArrayBase* to, ElementsKind from_kind,
+ uint32_t to_start, int packed_size,
+ int copy_size) {
+ DCHECK(!to->IsDictionary());
+ if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
+ CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
+ to_start, copy_size);
+ } else {
+ DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
+ CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
+ FAST_HOLEY_ELEMENTS, to_start, copy_size);
+ }
+ }
+
+ static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
+ uint32_t capacity) {
+ Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
+ Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
+ ElementsKind from_kind = object->GetElementsKind();
+ // This method should only be called if there's a reason to update the
+ // elements.
+ DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
+ static_cast<uint32_t>(old_elements->length()) < capacity);
+ Handle<FixedArrayBase> elements =
+ ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
+ Handle<Map> new_map = JSObject::GetElementsTransitionMap(
+ object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
+ JSObject::MigrateToMap(object, new_map);
+ parameter_map->set(1, *elements);
+ JSObject::ValidateElements(object);
+ }
+};
+
+
+class SlowSloppyArgumentsElementsAccessor
+ : public SloppyArgumentsElementsAccessor<
+ SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
+ ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
+ public:
+ friend class ElementsAccessorBase<
+ SlowSloppyArgumentsElementsAccessor,
+ ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >;
+ friend class SloppyArgumentsElementsAccessor<
+ SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
+ ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >;
+ explicit SlowSloppyArgumentsElementsAccessor(const char* name)
+ : SloppyArgumentsElementsAccessor<
+ SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
+ ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
+
+ protected:
+ static void AddImpl(Handle<JSObject> object, uint32_t key,
+ Handle<Object> value, PropertyAttributes attributes,
+ uint32_t new_capacity) {
+ Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
+ Handle<FixedArrayBase> old_elements(
+ FixedArrayBase::cast(parameter_map->get(1)));
+ Handle<SeededNumberDictionary> dictionary =
+ old_elements->IsSeededNumberDictionary()
+ ? Handle<SeededNumberDictionary>::cast(old_elements)
+ : JSObject::NormalizeElements(object);
+ PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
+ Handle<SeededNumberDictionary> new_dictionary =
+ SeededNumberDictionary::AddNumberEntry(dictionary, key, value, details);
+ if (attributes != NONE) new_dictionary->set_requires_slow_elements();
+ if (*dictionary != *new_dictionary) {
+ FixedArray::cast(object->elements())->set(1, *new_dictionary);
+ }
+ }
+
+ static void ReconfigureImpl(Handle<JSObject> object,
+ Handle<FixedArrayBase> store, uint32_t index,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
+ uint32_t length = parameter_map->length() - 2;
+ if (index < length) {
+ Object* probe = parameter_map->get(index + 2);
+ DCHECK(!probe->IsTheHole());
+ Context* context = Context::cast(parameter_map->get(0));
+ int context_index = Smi::cast(probe)->value();
+ DCHECK(!context->get(context_index)->IsTheHole());
+ context->set(context_index, *value);
+
+ // Redefining attributes of an aliased element destroys fast aliasing.
+ parameter_map->set_the_hole(index + 2);
+ // For elements that are still writable we re-establish slow aliasing.
+ if ((attributes & READ_ONLY) == 0) {
+ Isolate* isolate = store->GetIsolate();
+ value = isolate->factory()->NewAliasedArgumentsEntry(context_index);
+ }
+
+ PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
+ Handle<SeededNumberDictionary> arguments(
+ SeededNumberDictionary::cast(parameter_map->get(1)));
+ arguments = SeededNumberDictionary::AddNumberEntry(arguments, index,
+ value, details);
+ parameter_map->set(1, *arguments);
+ } else {
+ Handle<FixedArrayBase> arguments(
+ FixedArrayBase::cast(parameter_map->get(1)));
+ DictionaryElementsAccessor::ReconfigureImpl(
+ object, arguments, index - length, value, attributes);
+ }
+ }
+};
void ElementsAccessor::InitializeOncePerProcess() {
uint32_t new_capacity) = 0;
protected:
- friend class SloppyArgumentsElementsAccessor;
friend class LookupIterator;
static ElementsAccessor* ForArray(FixedArrayBase* array);
static bool CanInlineElementAccess(Handle<Map> map) {
- return map->IsJSObjectMap() && !map->has_slow_elements_kind() &&
+ return map->IsJSObjectMap() && !map->has_dictionary_elements() &&
+ !map->has_sloppy_arguments_elements() &&
!map->has_indexed_interceptor() && !map->is_access_check_needed();
}
elements_kind != GetInitialFastElementsKind()) {
possible_transitioned_maps.Add(map);
}
- if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) {
+ if (IsSloppyArgumentsElements(elements_kind)) {
HInstruction* result = BuildKeyedGeneric(access_type, expr, object, key,
val);
*has_side_effects = result->HasObservableSideEffects();
for (int i = 0; i < maps->length(); ++i) {
Handle<Map> map = maps->at(i);
Handle<Map> transitioned_map =
- map->FindTransitionedMap(&possible_transitioned_maps);
+ Map::FindTransitionedMap(map, &possible_transitioned_maps);
transition_target.Add(transitioned_map);
}
__ jmp(&instantiate, Label::kNear);
__ bind(&has_mapped_parameters);
- __ mov(
- edi,
- Operand(edi, Context::SlotOffset(Context::ALIASED_ARGUMENTS_MAP_INDEX)));
+ __ mov(edi, Operand(edi, Context::SlotOffset(
+ Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX)));
__ bind(&instantiate);
// eax = address of new object (tagged)
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
Handle<Map> receiver_map(receiver_maps->at(i));
Handle<Code> cached_stub;
Handle<Map> transitioned_map =
- receiver_map->FindTransitionedMap(receiver_maps);
+ Map::FindTransitionedMap(receiver_map, receiver_maps);
// TODO(mvstanton): The code below is doing pessimistic elements
// transitions. I would like to stop doing that and rely on Allocation Site
const int kNormalOffset =
Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX);
const int kAliasedOffset =
- Context::SlotOffset(Context::ALIASED_ARGUMENTS_MAP_INDEX);
+ Context::SlotOffset(Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
__ lw(t0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
__ lw(t0, FieldMemOperand(t0, GlobalObject::kNativeContextOffset));
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
const int kNormalOffset =
Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX);
const int kAliasedOffset =
- Context::SlotOffset(Context::ALIASED_ARGUMENTS_MAP_INDEX);
+ Context::SlotOffset(Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
__ ld(a4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
__ ld(a4, FieldMemOperand(a4, GlobalObject::kNativeContextOffset));
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
VerifyHeapPointer(properties());
VerifyHeapPointer(elements());
- if (GetElementsKind() == SLOPPY_ARGUMENTS_ELEMENTS) {
+ if (HasSloppyArgumentsElements()) {
CHECK(this->elements()->IsFixedArray());
CHECK_GE(this->elements()->length(), 2);
}
dict->Capacity() - dict->NumberOfElements();
break;
}
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
break;
}
}
fixed_array->IsFixedArray() &&
fixed_array->IsDictionary()) ||
(kind > DICTIONARY_ELEMENTS));
- DCHECK((kind != SLOPPY_ARGUMENTS_ELEMENTS) ||
+ DCHECK(!IsSloppyArgumentsElements(kind) ||
(elements()->IsFixedArray() && elements()->length() >= 2));
}
#endif
}
+bool JSObject::HasFastArgumentsElements() {
+ return GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
+}
+
+
+bool JSObject::HasSlowArgumentsElements() {
+ return GetElementsKind() == SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
+}
+
+
bool JSObject::HasSloppyArgumentsElements() {
- return GetElementsKind() == SLOPPY_ARGUMENTS_ELEMENTS;
+ return IsSloppyArgumentsElements(GetElementsKind());
}
case DICTIONARY_ELEMENTS:
elements()->Print(os);
break;
- case SLOPPY_ARGUMENTS_ELEMENTS: {
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
FixedArray* p = FixedArray::cast(elements());
os << " parameter map:";
for (int i = 2; i < p->length(); i++) {
ElementsKind from_kind = root_map->elements_kind();
ElementsKind to_kind = old_map->elements_kind();
+ // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
+ to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
!(IsTransitionableFastElementsKind(from_kind) &&
IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
}
-static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
- DCHECK(!map.is_null());
+static bool ContainsMap(MapHandleList* maps, Map* map) {
+ DCHECK_NOT_NULL(map);
for (int i = 0; i < maps->length(); ++i) {
- if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
+ if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
}
return false;
}
-template <class T>
-static Handle<T> MaybeNull(T* p) {
- if (p == NULL) return Handle<T>::null();
- return Handle<T>(p);
-}
-
-
-Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
- ElementsKind kind = elements_kind();
- Handle<Map> transitioned_map = Handle<Map>::null();
- Handle<Map> current_map(this);
+Handle<Map> Map::FindTransitionedMap(Handle<Map> map,
+ MapHandleList* candidates) {
+ ElementsKind kind = map->elements_kind();
bool packed = IsFastPackedElementsKind(kind);
+
+ Map* transition = nullptr;
if (IsTransitionableFastElementsKind(kind)) {
- while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
- kind = GetNextMoreGeneralFastElementsKind(kind, false);
- Handle<Map> maybe_transitioned_map =
- MaybeNull(current_map->LookupElementsTransitionMap(kind));
- if (maybe_transitioned_map.is_null()) break;
- if (ContainsMap(candidates, maybe_transitioned_map) &&
- (packed || !IsFastPackedElementsKind(kind))) {
- transitioned_map = maybe_transitioned_map;
- if (!IsFastPackedElementsKind(kind)) packed = false;
+ for (Map* current = map->ElementsTransitionMap();
+ current != nullptr && current->has_fast_elements();
+ current = current->ElementsTransitionMap()) {
+ if (ContainsMap(candidates, current) &&
+ (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
+ transition = current;
+ packed = packed && IsFastPackedElementsKind(current->elements_kind());
}
- current_map = maybe_transitioned_map;
}
}
- return transitioned_map;
+ return transition == nullptr ? Handle<Map>() : handle(transition);
}
static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
Map* current_map = map;
- int target_kind =
- IsFastElementsKind(to_kind) || IsExternalArrayElementsKind(to_kind)
- ? to_kind
- : TERMINAL_FAST_ELEMENTS_KIND;
// Support for legacy API: SetIndexedPropertiesTo{External,Pixel}Data
// allows to change elements from arbitrary kind to any ExternalArray
}
ElementsKind kind = map->elements_kind();
- while (kind != target_kind) {
- kind = GetNextTransitionElementsKind(kind);
+ while (kind != to_kind) {
Map* next_map = current_map->ElementsTransitionMap();
- if (next_map == NULL) return current_map;
+ if (next_map == nullptr) return current_map;
+ kind = next_map->elements_kind();
current_map = next_map;
}
- Map* next_map = current_map->ElementsTransitionMap();
- if (to_kind != kind && next_map != NULL) {
- DCHECK(to_kind == DICTIONARY_ELEMENTS);
- if (next_map->elements_kind() == to_kind) return next_map;
- }
-
- DCHECK(current_map->elements_kind() == target_kind);
+ DCHECK_EQ(to_kind, current_map->elements_kind());
return current_map;
}
Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
Map* to_map = FindClosestElementsTransition(this, to_kind);
if (to_map->elements_kind() == to_kind) return to_map;
- return NULL;
+ return nullptr;
}
flag = OMIT_TRANSITION;
} else {
flag = INSERT_TRANSITION;
- while (kind != to_kind && !IsTerminalElementsKind(kind)) {
- kind = GetNextTransitionElementsKind(kind);
- current_map = Map::CopyAsElementsKind(current_map, kind, flag);
+ if (IsFastElementsKind(kind)) {
+ while (kind != to_kind && !IsTerminalElementsKind(kind)) {
+ kind = GetNextTransitionElementsKind(kind);
+ current_map = Map::CopyAsElementsKind(current_map, kind, flag);
+ }
}
}
Isolate* isolate = map->GetIsolate();
Context* native_context = isolate->context()->native_context();
- Object* maybe_array_maps = map->is_strong()
- ? native_context->js_array_strong_maps()
- : native_context->js_array_maps();
- if (maybe_array_maps->IsFixedArray()) {
- DisallowHeapAllocation no_gc;
- FixedArray* array_maps = FixedArray::cast(maybe_array_maps);
- if (array_maps->get(from_kind) == *map) {
- Object* maybe_transitioned_map = array_maps->get(to_kind);
- if (maybe_transitioned_map->IsMap()) {
- return handle(Map::cast(maybe_transitioned_map));
+ if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
+ if (*map == native_context->fast_aliased_arguments_map()) {
+ DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
+ return handle(native_context->slow_aliased_arguments_map());
+ }
+ } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
+ if (*map == native_context->slow_aliased_arguments_map()) {
+ DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
+ return handle(native_context->fast_aliased_arguments_map());
+ }
+ } else {
+ Object* maybe_array_maps = map->is_strong()
+ ? native_context->js_array_strong_maps()
+ : native_context->js_array_maps();
+ if (maybe_array_maps->IsFixedArray()) {
+ DisallowHeapAllocation no_gc;
+ FixedArray* array_maps = FixedArray::cast(maybe_array_maps);
+ if (array_maps->get(from_kind) == *map) {
+ Object* maybe_transitioned_map = array_maps->get(to_kind);
+ if (maybe_transitioned_map->IsMap()) {
+ return handle(Map::cast(maybe_transitioned_map));
+ }
}
}
}
bool allow_store_transition = IsTransitionElementsKind(from_kind);
// Only store fast element maps in ascending generality.
if (IsFastElementsKind(to_kind)) {
- allow_store_transition &=
- IsTransitionableFastElementsKind(from_kind) &&
+ allow_store_transition =
+ allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
IsMoreGeneralElementsKindTransition(from_kind, to_kind);
}
dictionary = CopyFastElementsToDictionary(array, length, dictionary);
// Switch to using the dictionary as the backing storage for elements.
+ ElementsKind target_kind =
+ is_arguments ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS : DICTIONARY_ELEMENTS;
+ Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
+ // Set the new map first to satify the elements type assert in set_elements().
+ JSObject::MigrateToMap(object, new_map);
+
if (is_arguments) {
FixedArray::cast(object->elements())->set(1, *dictionary);
} else {
- // Set the new map first to satify the elements type assert in
- // set_elements().
- Handle<Map> new_map =
- JSObject::GetElementsTransitionMap(object, DICTIONARY_ELEMENTS);
-
- JSObject::MigrateToMap(object, new_map);
object->set_elements(*dictionary);
}
}
#endif
- DCHECK(object->HasDictionaryElements() ||
- object->HasDictionaryArgumentsElements());
+ DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
return dictionary;
}
if (ReferencesObjectFromElements(elements, kind, obj)) return true;
break;
}
- case SLOPPY_ARGUMENTS_ELEMENTS: {
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
FixedArray* parameter_map = FixedArray::cast(elements());
// Check the mapped parameters.
int length = parameter_map->length();
// If there are fast elements we normalize.
Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
- DCHECK(object->HasDictionaryElements() ||
- object->HasDictionaryArgumentsElements());
+ DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
// Make sure that we never go back to fast case.
dictionary->set_requires_slow_elements();
}
break;
}
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNIMPLEMENTED();
break;
return;
}
break;
- case SLOPPY_ARGUMENTS_ELEMENTS: {
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
// Ascertain whether we have read-only properties or an existing
// getter/setter pair in an arguments elements dictionary backing
// store.
// Normalize elements to make this operation simple.
bool had_dictionary_elements = object->HasDictionaryElements();
Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
- DCHECK(object->HasDictionaryElements() ||
- object->HasDictionaryArgumentsElements());
+ DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
// Update the dictionary with the new ACCESSOR_CONSTANT property.
dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
details);
case FAST_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ 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:
}
-bool JSObject::HasFastArgumentsElements() {
- Heap* heap = GetHeap();
- if (!elements()->IsFixedArray()) return false;
- FixedArray* elements = FixedArray::cast(this->elements());
- if (elements->map() != heap->sloppy_arguments_elements_map()) {
- return false;
- }
- FixedArray* arguments = FixedArray::cast(elements->get(1));
- return !arguments->IsDictionary();
-}
-
-
-bool JSObject::HasDictionaryArgumentsElements() {
- Heap* heap = GetHeap();
- if (!elements()->IsFixedArray()) return false;
- FixedArray* elements = FixedArray::cast(this->elements());
- if (elements->map() != heap->sloppy_arguments_elements_map()) {
- return false;
- }
- FixedArray* arguments = FixedArray::cast(elements->get(1));
- return arguments->IsDictionary();
-}
-
-
ElementsAccessor* JSObject::GetElementsAccessor() {
return ElementsAccessor::ForKind(GetElementsKind());
}
static ElementsKind BestFittingFastElementsKind(JSObject* object) {
- if (object->HasSloppyArgumentsElements()) return SLOPPY_ARGUMENTS_ELEMENTS;
+ if (object->HasSloppyArgumentsElements()) {
+ return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
+ }
DCHECK(object->HasDictionaryElements());
SeededNumberDictionary* dictionary = object->element_dictionary();
ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
ElementsKind kind = object->GetElementsKind();
FixedArrayBase* elements = object->elements();
+ ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
if (IsSloppyArgumentsElements(kind)) {
elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
+ dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
}
if (attributes != NONE) {
- kind = DICTIONARY_ELEMENTS;
+ kind = dictionary_kind;
} else if (elements->IsSeededNumberDictionary()) {
kind = ShouldConvertToFastElements(*object,
SeededNumberDictionary::cast(elements),
index, &new_capacity)
? BestFittingFastElementsKind(*object)
- : DICTIONARY_ELEMENTS; // Overwrite in case of arguments.
+ : dictionary_kind; // Overwrite in case of arguments.
} else if (ShouldConvertToSlowElements(
*object, static_cast<uint32_t>(elements->length()), index,
&new_capacity)) {
- kind = DICTIONARY_ELEMENTS;
+ kind = dictionary_kind;
}
- if (kind == DICTIONARY_ELEMENTS && object->HasSloppyArgumentsElements()) {
- // TODO(verwaest): Distinguish fast/slow sloppy elements in ElementsKind.
- Handle<SeededNumberDictionary> dictionary =
- elements->IsSeededNumberDictionary()
- ? handle(SeededNumberDictionary::cast(elements))
- : NormalizeElements(object);
- PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
- Handle<SeededNumberDictionary> new_dictionary =
- SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
- details);
- if (attributes != NONE) new_dictionary->set_requires_slow_elements();
- if (*dictionary != *new_dictionary) {
- FixedArray::cast(object->elements())->set(1, *new_dictionary);
- }
- } else {
- ElementsKind to = value->OptimalElementsKind();
- if (IsHoleyElementsKind(kind) || !object->IsJSArray() ||
- index > old_length) {
- to = GetHoleyElementsKind(to);
- kind = GetHoleyElementsKind(kind);
- }
- to = IsMoreGeneralElementsKindTransition(kind, to) ? to : kind;
- ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
- accessor->Add(object, index, value, attributes, new_capacity);
+ ElementsKind to = value->OptimalElementsKind();
+ if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
+ to = GetHoleyElementsKind(to);
+ kind = GetHoleyElementsKind(kind);
}
+ to = IsMoreGeneralElementsKindTransition(kind, to) ? to : kind;
+ ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
+ accessor->Add(object, index, value, attributes, new_capacity);
uint32_t new_length = old_length;
Handle<Object> new_length_handle;
FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
FixedArray* backing_store = NULL;
switch (GetElementsKind()) {
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
backing_store_base =
FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
backing_store = FixedArray::cast(backing_store_base);
counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
break;
}
- case SLOPPY_ARGUMENTS_ELEMENTS: {
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
FixedArray* parameter_map = FixedArray::cast(elements());
int mapped_length = parameter_map->length() - 2;
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
inline bool HasFixedFloat32Elements();
inline bool HasFixedFloat64Elements();
- bool HasFastArgumentsElements();
- bool HasDictionaryArgumentsElements();
+ inline bool HasFastArgumentsElements();
+ inline bool HasSlowArgumentsElements();
inline SeededNumberDictionary* element_dictionary(); // Gets slow elements.
// Requires: HasFastElements().
}
inline bool has_sloppy_arguments_elements() {
- return elements_kind() == SLOPPY_ARGUMENTS_ELEMENTS;
+ return IsSloppyArgumentsElements(elements_kind());
}
inline bool has_external_array_elements() {
return IsDictionaryElementsKind(elements_kind());
}
- inline bool has_slow_elements_kind() {
- return elements_kind() == DICTIONARY_ELEMENTS
- || elements_kind() == SLOPPY_ARGUMENTS_ELEMENTS;
- }
-
static bool IsValidElementsTransition(ElementsKind from_kind,
ElementsKind to_kind);
// Returns the transitioned map for this map with the most generic
// elements_kind that's found in |candidates|, or null handle if no match is
// found at all.
- Handle<Map> FindTransitionedMap(MapHandleList* candidates);
+ static Handle<Map> FindTransitionedMap(Handle<Map> map,
+ MapHandleList* candidates);
bool CanTransition() {
// Only JSObject and subtypes have map transitions and back pointers.
const int kNormalOffset =
Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX);
const int kAliasedOffset =
- Context::SlotOffset(Context::ALIASED_ARGUMENTS_MAP_INDEX);
+ Context::SlotOffset(Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
__ LoadP(r7,
MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
}
break;
}
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ 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:
if (length == range) return; // All indices accounted for already.
break;
}
- case SLOPPY_ARGUMENTS_ELEMENTS: {
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
MaybeHandle<Object> length_obj =
Object::GetProperty(object, isolate->factory()->length_string());
double length_num = length_obj.ToHandleChecked()->Number();
isolate, receiver, false, false, visitor);
break;
}
- case SLOPPY_ARGUMENTS_ELEMENTS: {
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
for (uint32_t index = 0; index < length; index++) {
HandleScope loop_scope(isolate);
Handle<Object> element;
Handle<FixedArray> parameter_map =
isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
parameter_map->set_map(isolate->heap()->sloppy_arguments_elements_map());
-
- Handle<Map> map = Map::Copy(handle(result->map()), "NewSloppyArguments");
- map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
-
- result->set_map(*map);
+ result->set_map(isolate->native_context()->fast_aliased_arguments_map());
result->set_elements(*parameter_map);
// Store the context and the arguments array at the beginning of the
__ movp(rdi, Operand(rdi, Context::SlotOffset(kIndex)));
__ jmp(&instantiate, Label::kNear);
- const int kAliasedIndex = Context::ALIASED_ARGUMENTS_MAP_INDEX;
+ const int kAliasedIndex = Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX;
__ bind(&has_mapped_parameters);
__ movp(rdi, Operand(rdi, Context::SlotOffset(kAliasedIndex)));
__ bind(&instantiate);
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
__ jmp(&instantiate, Label::kNear);
__ bind(&has_mapped_parameters);
- __ mov(
- edi,
- Operand(edi, Context::SlotOffset(Context::ALIASED_ARGUMENTS_MAP_INDEX)));
+ __ mov(edi, Operand(edi, Context::SlotOffset(
+ Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX)));
__ bind(&instantiate);
// eax = address of new object (tagged)
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
case FAST_HOLEY_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}