summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects.cc')
-rw-r--r--deps/v8/src/objects.cc2476
1 files changed, 1360 insertions, 1116 deletions
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 414306f2b4..0eda4912e6 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -234,151 +234,22 @@ bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
}
-template<typename To>
-static inline To* CheckedCast(void *from) {
- uintptr_t temp = reinterpret_cast<uintptr_t>(from);
- DCHECK(temp % sizeof(To) == 0);
- return reinterpret_cast<To*>(temp);
-}
-
-
-static Handle<Object> PerformCompare(const BitmaskCompareDescriptor& descriptor,
- char* ptr,
- Isolate* isolate) {
- uint32_t bitmask = descriptor.bitmask;
- uint32_t compare_value = descriptor.compare_value;
- uint32_t value;
- switch (descriptor.size) {
- case 1:
- value = static_cast<uint32_t>(*CheckedCast<uint8_t>(ptr));
- compare_value &= 0xff;
- bitmask &= 0xff;
- break;
- case 2:
- value = static_cast<uint32_t>(*CheckedCast<uint16_t>(ptr));
- compare_value &= 0xffff;
- bitmask &= 0xffff;
- break;
- case 4:
- value = *CheckedCast<uint32_t>(ptr);
- break;
- default:
- UNREACHABLE();
- return isolate->factory()->undefined_value();
- }
- return isolate->factory()->ToBoolean(
- (bitmask & value) == (bitmask & compare_value));
-}
-
-
-static Handle<Object> PerformCompare(const PointerCompareDescriptor& descriptor,
- char* ptr,
- Isolate* isolate) {
- uintptr_t compare_value =
- reinterpret_cast<uintptr_t>(descriptor.compare_value);
- uintptr_t value = *CheckedCast<uintptr_t>(ptr);
- return isolate->factory()->ToBoolean(compare_value == value);
-}
-
-
-static Handle<Object> GetPrimitiveValue(
- const PrimitiveValueDescriptor& descriptor,
- char* ptr,
- Isolate* isolate) {
- int32_t int32_value = 0;
- switch (descriptor.data_type) {
- case kDescriptorInt8Type:
- int32_value = *CheckedCast<int8_t>(ptr);
- break;
- case kDescriptorUint8Type:
- int32_value = *CheckedCast<uint8_t>(ptr);
- break;
- case kDescriptorInt16Type:
- int32_value = *CheckedCast<int16_t>(ptr);
- break;
- case kDescriptorUint16Type:
- int32_value = *CheckedCast<uint16_t>(ptr);
- break;
- case kDescriptorInt32Type:
- int32_value = *CheckedCast<int32_t>(ptr);
- break;
- case kDescriptorUint32Type: {
- uint32_t value = *CheckedCast<uint32_t>(ptr);
- AllowHeapAllocation allow_gc;
- return isolate->factory()->NewNumberFromUint(value);
- }
- case kDescriptorBoolType: {
- uint8_t byte = *CheckedCast<uint8_t>(ptr);
- return isolate->factory()->ToBoolean(
- byte & (0x1 << descriptor.bool_offset));
- }
- case kDescriptorFloatType: {
- float value = *CheckedCast<float>(ptr);
- AllowHeapAllocation allow_gc;
- return isolate->factory()->NewNumber(value);
- }
- case kDescriptorDoubleType: {
- double value = *CheckedCast<double>(ptr);
- AllowHeapAllocation allow_gc;
- return isolate->factory()->NewNumber(value);
- }
- }
- AllowHeapAllocation allow_gc;
- return isolate->factory()->NewNumberFromInt(int32_value);
-}
-
-
-static Handle<Object> GetDeclaredAccessorProperty(
- Handle<Object> receiver,
- Handle<DeclaredAccessorInfo> info,
- Isolate* isolate) {
- DisallowHeapAllocation no_gc;
- char* current = reinterpret_cast<char*>(*receiver);
- DeclaredAccessorDescriptorIterator iterator(info->descriptor());
- while (true) {
- const DeclaredAccessorDescriptorData* data = iterator.Next();
- switch (data->type) {
- case kDescriptorReturnObject: {
- DCHECK(iterator.Complete());
- current = *CheckedCast<char*>(current);
- return handle(*CheckedCast<Object*>(current), isolate);
- }
- case kDescriptorPointerDereference:
- DCHECK(!iterator.Complete());
- current = *reinterpret_cast<char**>(current);
- break;
- case kDescriptorPointerShift:
- DCHECK(!iterator.Complete());
- current += data->pointer_shift_descriptor.byte_offset;
- break;
- case kDescriptorObjectDereference: {
- DCHECK(!iterator.Complete());
- Object* object = CheckedCast<Object>(current);
- int field = data->object_dereference_descriptor.internal_field;
- Object* smi = JSObject::cast(object)->GetInternalField(field);
- DCHECK(smi->IsSmi());
- current = reinterpret_cast<char*>(smi);
- break;
- }
- case kDescriptorBitmaskCompare:
- DCHECK(iterator.Complete());
- return PerformCompare(data->bitmask_compare_descriptor,
- current,
- isolate);
- case kDescriptorPointerCompare:
- DCHECK(iterator.Complete());
- return PerformCompare(data->pointer_compare_descriptor,
- current,
- isolate);
- case kDescriptorPrimitiveValue:
- DCHECK(iterator.Complete());
- return GetPrimitiveValue(data->primitive_value_descriptor,
- current,
- isolate);
- }
+// TODO(dcarney): CallOptimization duplicates this logic, merge.
+Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate,
+ Object* receiver) {
+ // API calls are only supported with JSObject receivers.
+ if (!receiver->IsJSObject()) return isolate->heap()->null_value();
+ Object* recv_type = this->signature();
+ // No signature, return holder.
+ if (recv_type->IsUndefined()) return receiver;
+ FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
+ // Check the receiver.
+ for (PrototypeIterator iter(isolate, receiver,
+ PrototypeIterator::START_AT_RECEIVER);
+ !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
+ if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent();
}
- UNREACHABLE();
- return isolate->factory()->undefined_value();
+ return isolate->heap()->null_value();
}
@@ -420,18 +291,12 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver,
if (structure->IsAccessorInfo()) {
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
if (!info->IsCompatibleReceiver(*receiver)) {
- Handle<Object> args[2] = { name, receiver };
+ Handle<Object> args[] = {name, receiver};
THROW_NEW_ERROR(isolate,
NewTypeError("incompatible_method_receiver",
HandleVector(args, arraysize(args))),
Object);
}
- if (structure->IsDeclaredAccessorInfo()) {
- return GetDeclaredAccessorProperty(
- receiver,
- Handle<DeclaredAccessorInfo>::cast(structure),
- isolate);
- }
Handle<ExecutableAccessorInfo> data =
Handle<ExecutableAccessorInfo>::cast(structure);
@@ -466,11 +331,10 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver,
}
-bool AccessorInfo::IsCompatibleReceiverType(Isolate* isolate,
- Handle<AccessorInfo> info,
- Handle<HeapType> type) {
+bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
+ Handle<AccessorInfo> info,
+ Handle<Map> map) {
if (!info->HasExpectedReceiverType()) return true;
- Handle<Map> map = IC::TypeToMap(*type, isolate);
if (!map->IsJSObjectMap()) return false;
return FunctionTemplateInfo::cast(info->expected_receiver_type())
->IsTemplateFor(*map);
@@ -479,7 +343,8 @@ bool AccessorInfo::IsCompatibleReceiverType(Isolate* isolate,
MaybeHandle<Object> Object::SetPropertyWithAccessor(
Handle<Object> receiver, Handle<Name> name, Handle<Object> value,
- Handle<JSObject> holder, Handle<Object> structure, StrictMode strict_mode) {
+ Handle<JSObject> holder, Handle<Object> structure,
+ LanguageMode language_mode) {
Isolate* isolate = name->GetIsolate();
// We should never get here to initialize a const with the hole
@@ -491,7 +356,7 @@ MaybeHandle<Object> Object::SetPropertyWithAccessor(
// api style callbacks
ExecutableAccessorInfo* info = ExecutableAccessorInfo::cast(*structure);
if (!info->IsCompatibleReceiver(*receiver)) {
- Handle<Object> args[2] = { name, receiver };
+ Handle<Object> args[] = {name, receiver};
THROW_NEW_ERROR(isolate,
NewTypeError("incompatible_method_receiver",
HandleVector(args, arraysize(args))),
@@ -517,19 +382,15 @@ MaybeHandle<Object> Object::SetPropertyWithAccessor(
return SetPropertyWithDefinedSetter(
receiver, Handle<JSReceiver>::cast(setter), value);
} else {
- if (strict_mode == SLOPPY) return value;
- Handle<Object> args[2] = { name, holder };
- THROW_NEW_ERROR(
- isolate, NewTypeError("no_setter_in_callback", HandleVector(args, 2)),
- Object);
+ if (is_sloppy(language_mode)) return value;
+ Handle<Object> args[] = {name, holder};
+ THROW_NEW_ERROR(isolate,
+ NewTypeError("no_setter_in_callback",
+ HandleVector(args, arraysize(args))),
+ Object);
}
}
- // TODO(dcarney): Handle correctly.
- if (structure->IsDeclaredAccessorInfo()) {
- return value;
- }
-
UNREACHABLE();
return MaybeHandle<Object>();
}
@@ -572,12 +433,19 @@ MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
static bool FindAllCanReadHolder(LookupIterator* it) {
- for (; it->IsFound(); it->Next()) {
+ // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
+ // which have already been checked.
+ DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
+ it->state() == LookupIterator::INTERCEPTOR);
+ for (it->Next(); it->IsFound(); it->Next()) {
if (it->state() == LookupIterator::ACCESSOR) {
- Handle<Object> accessors = it->GetAccessors();
+ auto accessors = it->GetAccessors();
if (accessors->IsAccessorInfo()) {
if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
}
+ } else if (it->state() == LookupIterator::INTERCEPTOR) {
+ auto holder = it->GetHolder<JSObject>();
+ if (holder->GetNamedInterceptor()->all_can_read()) return true;
}
}
return false;
@@ -587,10 +455,18 @@ static bool FindAllCanReadHolder(LookupIterator* it) {
MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
LookupIterator* it) {
Handle<JSObject> checked = it->GetHolder<JSObject>();
- if (FindAllCanReadHolder(it)) {
- return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
- it->GetHolder<JSObject>(),
- it->GetAccessors());
+ while (FindAllCanReadHolder(it)) {
+ if (it->state() == LookupIterator::ACCESSOR) {
+ return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
+ it->GetHolder<JSObject>(),
+ it->GetAccessors());
+ }
+ DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
+ auto receiver = Handle<JSObject>::cast(it->GetReceiver());
+ auto result = GetPropertyWithInterceptor(it->GetHolder<JSObject>(),
+ receiver, it->name());
+ if (it->isolate()->has_scheduled_exception()) break;
+ if (!result.is_null()) return result;
}
it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET);
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
@@ -601,8 +477,16 @@ MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
LookupIterator* it) {
Handle<JSObject> checked = it->GetHolder<JSObject>();
- if (FindAllCanReadHolder(it))
- return maybe(it->property_details().attributes());
+ while (FindAllCanReadHolder(it)) {
+ if (it->state() == LookupIterator::ACCESSOR) {
+ return maybe(it->property_details().attributes());
+ }
+ DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
+ auto result = GetPropertyAttributesWithInterceptor(
+ it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
+ if (it->isolate()->has_scheduled_exception()) break;
+ if (result.has_value && result.value != ABSENT) return result;
+ }
it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS);
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(),
Maybe<PropertyAttributes>());
@@ -624,12 +508,12 @@ static bool FindAllCanWriteHolder(LookupIterator* it) {
MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck(
- LookupIterator* it, Handle<Object> value, StrictMode strict_mode) {
+ LookupIterator* it, Handle<Object> value, LanguageMode language_mode) {
Handle<JSObject> checked = it->GetHolder<JSObject>();
if (FindAllCanWriteHolder(it)) {
return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
it->GetHolder<JSObject>(),
- it->GetAccessors(), strict_mode);
+ it->GetAccessors(), language_mode);
}
it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_SET);
@@ -689,50 +573,62 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
}
-Handle<Object> JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
- Handle<Name> name,
- DeleteMode mode) {
- DCHECK(!object->HasFastProperties());
- Isolate* isolate = object->GetIsolate();
- Handle<NameDictionary> dictionary(object->property_dictionary());
- int entry = dictionary->FindEntry(name);
- if (entry != NameDictionary::kNotFound) {
- // If we have a global object set the cell to the hole.
- if (object->IsGlobalObject()) {
- PropertyDetails details = dictionary->DetailsAt(entry);
- if (!details.IsConfigurable()) {
- if (mode != FORCE_DELETION) return isolate->factory()->false_value();
- // When forced to delete global properties, we have to make a
- // map change to invalidate any ICs that think they can load
- // from the non-configurable cell without checking if it contains
- // the hole value.
- Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
- DCHECK(new_map->is_dictionary_map());
-#if TRACE_MAPS
- if (FLAG_trace_maps) {
- PrintF("[TraceMaps: GlobalDeleteNormalized from= %p to= %p ]\n",
- reinterpret_cast<void*>(object->map()),
- reinterpret_cast<void*>(*new_map));
- }
-#endif
- JSObject::MigrateToMap(object, new_map);
- }
- Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
- Handle<Object> value = isolate->factory()->the_hole_value();
- PropertyCell::SetValueInferType(cell, value);
- dictionary->DetailsAtPut(entry, details.AsDeleted());
- } else {
- Handle<Object> deleted(
- NameDictionary::DeleteProperty(dictionary, entry, mode));
- if (*deleted == isolate->heap()->true_value()) {
- Handle<NameDictionary> new_properties =
- NameDictionary::Shrink(dictionary, name);
- object->set_properties(*new_properties);
- }
- return deleted;
- }
+static MaybeHandle<JSObject> FindIndexedAllCanReadHolder(
+ Isolate* isolate, Handle<JSObject> js_object,
+ PrototypeIterator::WhereToStart where_to_start) {
+ for (PrototypeIterator iter(isolate, js_object, where_to_start);
+ !iter.IsAtEnd(); iter.Advance()) {
+ auto curr = PrototypeIterator::GetCurrent(iter);
+ if (!curr->IsJSObject()) break;
+ auto obj = Handle<JSObject>::cast(curr);
+ if (!obj->HasIndexedInterceptor()) continue;
+ if (obj->GetIndexedInterceptor()->all_can_read()) return obj;
}
- return isolate->factory()->true_value();
+ return MaybeHandle<JSObject>();
+}
+
+
+MaybeHandle<Object> JSObject::GetElementWithFailedAccessCheck(
+ Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver,
+ uint32_t index) {
+ Handle<JSObject> holder = object;
+ PrototypeIterator::WhereToStart where_to_start =
+ PrototypeIterator::START_AT_RECEIVER;
+ while (true) {
+ auto all_can_read_holder =
+ FindIndexedAllCanReadHolder(isolate, holder, where_to_start);
+ if (!all_can_read_holder.ToHandle(&holder)) break;
+ auto result =
+ JSObject::GetElementWithInterceptor(holder, receiver, index, false);
+ if (isolate->has_scheduled_exception()) break;
+ if (!result.is_null()) return result;
+ where_to_start = PrototypeIterator::START_AT_PROTOTYPE;
+ }
+ isolate->ReportFailedAccessCheck(object, v8::ACCESS_GET);
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ return isolate->factory()->undefined_value();
+}
+
+
+Maybe<PropertyAttributes> JSObject::GetElementAttributesWithFailedAccessCheck(
+ Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver,
+ uint32_t index) {
+ Handle<JSObject> holder = object;
+ PrototypeIterator::WhereToStart where_to_start =
+ PrototypeIterator::START_AT_RECEIVER;
+ while (true) {
+ auto all_can_read_holder =
+ FindIndexedAllCanReadHolder(isolate, holder, where_to_start);
+ if (!all_can_read_holder.ToHandle(&holder)) break;
+ auto result =
+ JSObject::GetElementAttributeFromInterceptor(object, receiver, index);
+ if (isolate->has_scheduled_exception()) break;
+ if (result.has_value && result.value != ABSENT) return result;
+ where_to_start = PrototypeIterator::START_AT_PROTOTYPE;
+ }
+ isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
+ return maybe(ABSENT);
}
@@ -768,14 +664,14 @@ MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate,
// Check access rights if needed.
if (js_object->IsAccessCheckNeeded()) {
if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
- isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
- return isolate->factory()->undefined_value();
+ return JSObject::GetElementWithFailedAccessCheck(isolate, js_object,
+ receiver, index);
}
}
if (js_object->HasIndexedInterceptor()) {
- return JSObject::GetElementWithInterceptor(js_object, receiver, index);
+ return JSObject::GetElementWithInterceptor(js_object, receiver, index,
+ true);
}
if (js_object->elements() != isolate->heap()->empty_fixed_array()) {
@@ -794,7 +690,7 @@ MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate,
MaybeHandle<Object> Object::SetElementWithReceiver(
Isolate* isolate, Handle<Object> object, Handle<Object> receiver,
- uint32_t index, Handle<Object> value, StrictMode strict_mode) {
+ uint32_t index, Handle<Object> value, LanguageMode language_mode) {
// Iterate up the prototype chain until an element is found or the null
// prototype is encountered.
bool done = false;
@@ -828,7 +724,7 @@ MaybeHandle<Object> Object::SetElementWithReceiver(
if (!from_interceptor.has_value) return MaybeHandle<Object>();
if ((from_interceptor.value & READ_ONLY) != 0) {
return WriteToReadOnlyElement(isolate, receiver, index, value,
- strict_mode);
+ language_mode);
}
done = from_interceptor.value != ABSENT;
}
@@ -836,17 +732,15 @@ MaybeHandle<Object> Object::SetElementWithReceiver(
if (!done &&
js_object->elements() != isolate->heap()->empty_fixed_array()) {
ElementsAccessor* accessor = js_object->GetElementsAccessor();
- PropertyAttributes attrs =
- accessor->GetAttributes(receiver, js_object, index);
+ PropertyAttributes attrs = accessor->GetAttributes(js_object, index);
if ((attrs & READ_ONLY) != 0) {
return WriteToReadOnlyElement(isolate, receiver, index, value,
- strict_mode);
+ language_mode);
}
- Handle<AccessorPair> accessor_pair;
- if (accessor->GetAccessorPair(receiver, js_object, index)
- .ToHandle(&accessor_pair)) {
- return JSObject::SetElementWithCallback(receiver, accessor_pair, index,
- value, js_object, strict_mode);
+ Handle<AccessorPair> pair;
+ if (accessor->GetAccessorPair(js_object, index).ToHandle(&pair)) {
+ return JSObject::SetElementWithCallback(receiver, pair, index, value,
+ js_object, language_mode);
} else {
done = attrs != ABSENT;
}
@@ -854,17 +748,18 @@ MaybeHandle<Object> Object::SetElementWithReceiver(
}
if (!receiver->IsJSObject()) {
- return WriteToReadOnlyElement(isolate, receiver, index, value, strict_mode);
+ return WriteToReadOnlyElement(isolate, receiver, index, value,
+ language_mode);
}
Handle<JSObject> target = Handle<JSObject>::cast(receiver);
ElementsAccessor* accessor = target->GetElementsAccessor();
- PropertyAttributes attrs = accessor->GetAttributes(receiver, target, index);
- if ((attrs & READ_ONLY) != 0) {
- return WriteToReadOnlyElement(isolate, receiver, index, value, strict_mode);
+ PropertyAttributes attrs = accessor->GetAttributes(target, index);
+ if (attrs == ABSENT) {
+ return JSObject::SetElement(target, index, value, NONE, language_mode,
+ false);
}
- PropertyAttributes new_attrs = attrs != ABSENT ? attrs : NONE;
- return JSObject::SetElement(target, index, value, new_attrs, strict_mode,
- false);
+ return JSObject::SetElement(target, index, value, attrs, language_mode, false,
+ DEFINE_PROPERTY);
}
@@ -904,7 +799,9 @@ Object* Object::GetHash() {
// The object is either a number, a name, an odd-ball,
// a real JS object, or a Harmony proxy.
if (IsNumber()) {
- uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
+ uint32_t hash = std::isnan(Number())
+ ? Smi::kMaxValue
+ : ComputeLongHash(double_to_uint64(Number()));
return Smi::FromInt(hash & Smi::kMaxValue);
}
if (IsName()) {
@@ -1369,6 +1266,25 @@ void JSObject::PrintElementsTransition(
}
+void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
+ PropertyAttributes attributes) {
+ OFStream os(file);
+ os << "[reconfiguring ";
+ constructor_name()->PrintOn(file);
+ os << "] ";
+ Name* name = instance_descriptors()->GetKey(modify_index);
+ if (name->IsString()) {
+ String::cast(name)->PrintOn(file);
+ } else {
+ os << "{symbol " << static_cast<void*>(name) << "}";
+ }
+ os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
+ os << attributes << " [";
+ JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
+ os << "]\n";
+}
+
+
void Map::PrintGeneralization(FILE* file,
const char* reason,
int modify_index,
@@ -1425,8 +1341,8 @@ void JSObject::PrintInstanceMigration(FILE* file,
if (!o_r.Equals(n_r)) {
String::cast(o->GetKey(i))->PrintOn(file);
PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
- } else if (o->GetDetails(i).type() == CONSTANT &&
- n->GetDetails(i).type() == FIELD) {
+ } else if (o->GetDetails(i).type() == DATA_CONSTANT &&
+ n->GetDetails(i).type() == DATA) {
Name* name = o->GetKey(i);
if (name->IsString()) {
String::cast(name)->PrintOn(file);
@@ -1804,7 +1720,7 @@ MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
type = HeapType::Any(isolate);
}
- FieldDescriptor new_field_desc(name, index, type, attributes, representation);
+ DataDescriptor new_field_desc(name, index, type, attributes, representation);
Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
int unused_property_fields = new_map->unused_property_fields() - 1;
if (unused_property_fields < 0) {
@@ -1826,7 +1742,7 @@ MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
}
// Allocate new instance descriptors with (name, constant) added.
- ConstantDescriptor new_constant_desc(name, constant, attributes);
+ DataConstantDescriptor new_constant_desc(name, constant, attributes);
return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
}
@@ -1847,16 +1763,14 @@ void JSObject::AddSlowProperty(Handle<JSObject> object,
// Assign an enumeration index to the property and update
// SetNextEnumerationIndex.
int index = dict->NextEnumerationIndex();
- PropertyDetails details(attributes, FIELD, index);
+ PropertyDetails details(attributes, DATA, index);
dict->SetNextEnumerationIndex(index + 1);
dict->SetEntry(entry, name, cell, details);
return;
}
- Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(value);
- PropertyCell::SetValueInferType(cell, value);
- value = cell;
+ value = isolate->factory()->NewPropertyCell(value);
}
- PropertyDetails details(attributes, FIELD, 0);
+ PropertyDetails details(attributes, DATA, 0);
Handle<NameDictionary> result =
NameDictionary::Add(dict, name, value, details);
if (*dict != *result) object->set_properties(*result);
@@ -2051,7 +1965,7 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
} else {
value = isolate->factory()->uninitialized_value();
}
- DCHECK(details.type() == FIELD);
+ DCHECK(details.type() == DATA);
int target_index = details.field_index() - inobject;
DCHECK(target_index >= 0); // Must be a backing store index.
new_storage->set(target_index, *value);
@@ -2077,18 +1991,21 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
for (int i = 0; i < old_nof; i++) {
PropertyDetails details = new_descriptors->GetDetails(i);
- if (details.type() != FIELD) continue;
+ if (details.type() != DATA) continue;
PropertyDetails old_details = old_descriptors->GetDetails(i);
- if (old_details.type() == CALLBACKS) {
- DCHECK(details.representation().IsTagged());
- continue;
- }
Representation old_representation = old_details.representation();
Representation representation = details.representation();
- DCHECK(old_details.type() == CONSTANT ||
- old_details.type() == FIELD);
Handle<Object> value;
- if (old_details.type() == CONSTANT) {
+ if (old_details.type() == ACCESSOR_CONSTANT) {
+ // In case of kAccessor -> kData property reconfiguration, the property
+ // must already be prepared for data or certain type.
+ DCHECK(!details.representation().IsNone());
+ if (details.representation().IsDouble()) {
+ value = isolate->factory()->NewHeapNumber(0, MUTABLE);
+ } else {
+ value = isolate->factory()->uninitialized_value();
+ }
+ } else if (old_details.type() == DATA_CONSTANT) {
value = handle(old_descriptors->GetValue(i), isolate);
DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
} else {
@@ -2119,7 +2036,7 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
for (int i = old_nof; i < new_nof; i++) {
PropertyDetails details = new_descriptors->GetDetails(i);
- if (details.type() != FIELD) continue;
+ if (details.type() != DATA) continue;
Handle<Object> value;
if (details.representation().IsDouble()) {
value = isolate->factory()->NewHeapNumber(0, MUTABLE);
@@ -2182,17 +2099,15 @@ int Map::NumberOfFields() {
DescriptorArray* descriptors = instance_descriptors();
int result = 0;
for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
- if (descriptors->GetDetails(i).type() == FIELD) result++;
+ if (descriptors->GetDetails(i).location() == kField) result++;
}
return result;
}
-Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
- int modify_index,
- StoreMode store_mode,
- PropertyAttributes attributes,
- const char* reason) {
+Handle<Map> Map::CopyGeneralizeAllRepresentations(
+ Handle<Map> map, int modify_index, StoreMode store_mode, PropertyKind kind,
+ PropertyAttributes attributes, const char* reason) {
Isolate* isolate = map->GetIsolate();
Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
int number_of_own_descriptors = map->NumberOfOwnDescriptors();
@@ -2201,7 +2116,7 @@ Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
for (int i = 0; i < number_of_own_descriptors; i++) {
descriptors->SetRepresentation(i, Representation::Tagged());
- if (descriptors->GetDetails(i).type() == FIELD) {
+ if (descriptors->GetDetails(i).type() == DATA) {
descriptors->SetValue(i, HeapType::Any());
}
}
@@ -2213,52 +2128,43 @@ Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
// Unless the instance is being migrated, ensure that modify_index is a field.
- PropertyDetails details = descriptors->GetDetails(modify_index);
- if (store_mode == FORCE_IN_OBJECT &&
- (details.type() != FIELD || details.attributes() != attributes)) {
- int field_index = details.type() == FIELD ? details.field_index()
- : new_map->NumberOfFields();
- FieldDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
- field_index, attributes, Representation::Tagged());
- descriptors->Replace(modify_index, &d);
- if (details.type() != FIELD) {
- int unused_property_fields = new_map->unused_property_fields() - 1;
- if (unused_property_fields < 0) {
- unused_property_fields += JSObject::kFieldsAdded;
+ if (modify_index >= 0) {
+ PropertyDetails details = descriptors->GetDetails(modify_index);
+ if (store_mode == FORCE_FIELD &&
+ (details.type() != DATA || details.attributes() != attributes)) {
+ int field_index = details.type() == DATA ? details.field_index()
+ : new_map->NumberOfFields();
+ DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
+ field_index, attributes, Representation::Tagged());
+ descriptors->Replace(modify_index, &d);
+ if (details.type() != DATA) {
+ int unused_property_fields = new_map->unused_property_fields() - 1;
+ if (unused_property_fields < 0) {
+ unused_property_fields += JSObject::kFieldsAdded;
+ }
+ new_map->set_unused_property_fields(unused_property_fields);
}
- new_map->set_unused_property_fields(unused_property_fields);
+ } else {
+ DCHECK(details.attributes() == attributes);
}
- } else {
- DCHECK(details.attributes() == attributes);
- }
- if (FLAG_trace_generalization) {
- HeapType* field_type = (details.type() == FIELD)
- ? map->instance_descriptors()->GetFieldType(modify_index)
- : NULL;
- map->PrintGeneralization(
- stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
- new_map->NumberOfOwnDescriptors(),
- details.type() == CONSTANT && store_mode == FORCE_IN_OBJECT,
- details.representation(), Representation::Tagged(), field_type,
- HeapType::Any());
+ if (FLAG_trace_generalization) {
+ HeapType* field_type =
+ (details.type() == DATA)
+ ? map->instance_descriptors()->GetFieldType(modify_index)
+ : NULL;
+ map->PrintGeneralization(
+ stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
+ new_map->NumberOfOwnDescriptors(),
+ details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD,
+ details.representation(), Representation::Tagged(), field_type,
+ HeapType::Any());
+ }
}
return new_map;
}
-// static
-Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
- int modify_index,
- StoreMode store_mode,
- const char* reason) {
- PropertyDetails details =
- map->instance_descriptors()->GetDetails(modify_index);
- return CopyGeneralizeAllRepresentations(map, modify_index, store_mode,
- details.attributes(), reason);
-}
-
-
void Map::DeprecateTransitionTree() {
if (is_deprecated()) return;
if (HasTransitionArray()) {
@@ -2274,6 +2180,13 @@ void Map::DeprecateTransitionTree() {
}
+static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
+ if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds.
+ // TODO(ishell): compare AccessorPairs.
+ return false;
+}
+
+
// Invalidates a transition target at |key|, and installs |new_descriptors| over
// the current instance_descriptors to ensure proper sharing of descriptor
// arrays.
@@ -2327,7 +2240,7 @@ Map* Map::FindLastMatchMap(int verbatim,
DisallowHeapAllocation no_allocation;
// This can only be called on roots of transition trees.
- DCHECK(GetBackPointer()->IsUndefined());
+ DCHECK_EQ(verbatim, NumberOfOwnDescriptors());
Map* current = this;
@@ -2344,16 +2257,22 @@ Map* Map::FindLastMatchMap(int verbatim,
DescriptorArray* next_descriptors = next->instance_descriptors();
PropertyDetails next_details = next_descriptors->GetDetails(i);
- if (details.type() != next_details.type()) break;
- if (details.attributes() != next_details.attributes()) break;
+ DCHECK_EQ(details.kind(), next_details.kind());
+ DCHECK_EQ(details.attributes(), next_details.attributes());
+ if (details.location() != next_details.location()) break;
if (!details.representation().Equals(next_details.representation())) break;
- if (next_details.type() == FIELD) {
- if (!descriptors->GetFieldType(i)->NowIs(
- next_descriptors->GetFieldType(i))) break;
+
+ if (next_details.location() == kField) {
+ HeapType* next_field_type = next_descriptors->GetFieldType(i);
+ if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
+ break;
+ }
} else {
- if (descriptors->GetValue(i) != next_descriptors->GetValue(i)) break;
+ if (!EqualImmutableValues(descriptors->GetValue(i),
+ next_descriptors->GetValue(i))) {
+ break;
+ }
}
-
current = next;
}
return current;
@@ -2362,7 +2281,7 @@ Map* Map::FindLastMatchMap(int verbatim,
Map* Map::FindFieldOwner(int descriptor) {
DisallowHeapAllocation no_allocation;
- DCHECK_EQ(FIELD, instance_descriptors()->GetDetails(descriptor).type());
+ DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type());
Map* result = this;
while (true) {
Object* back = result->GetBackPointer();
@@ -2380,7 +2299,7 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
Handle<HeapType> new_type) {
DisallowHeapAllocation no_allocation;
PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
- if (details.type() != FIELD) return;
+ if (details.type() != DATA) return;
if (HasTransitionArray()) {
TransitionArray* transitions = this->transitions();
for (int i = 0; i < transitions->number_of_transitions(); ++i) {
@@ -2394,8 +2313,8 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
// Skip if already updated the shared descriptor.
if (instance_descriptors()->GetFieldType(descriptor) == *new_type) return;
- FieldDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
- new_type, details.attributes(), new_representation);
+ DataDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
+ new_type, details.attributes(), new_representation);
instance_descriptors()->Replace(descriptor, &d);
}
@@ -2404,18 +2323,8 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
Handle<HeapType> Map::GeneralizeFieldType(Handle<HeapType> type1,
Handle<HeapType> type2,
Isolate* isolate) {
- static const int kMaxClassesPerFieldType = 5;
if (type1->NowIs(type2)) return type2;
if (type2->NowIs(type1)) return type1;
- if (type1->NowStable() && type2->NowStable()) {
- Handle<HeapType> type = HeapType::Union(type1, type2, isolate);
- if (type->NumClasses() <= kMaxClassesPerFieldType) {
- DCHECK(type->NowStable());
- DCHECK(type1->NowIs(type));
- DCHECK(type2->NowIs(type));
- return type;
- }
- }
return HeapType::Any(isolate);
}
@@ -2469,16 +2378,42 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
}
-// Generalize the representation of the descriptor at |modify_index|.
-// This method rewrites the transition tree to reflect the new change. To avoid
-// high degrees over polymorphism, and to stabilize quickly, on every rewrite
-// the new type is deduced by merging the current type with any potential new
-// (partial) version of the type in the transition tree.
+static inline Handle<HeapType> GetFieldType(Isolate* isolate,
+ Handle<DescriptorArray> descriptors,
+ int descriptor,
+ PropertyLocation location,
+ Representation representation) {
+#ifdef DEBUG
+ PropertyDetails details = descriptors->GetDetails(descriptor);
+ DCHECK_EQ(kData, details.kind());
+ DCHECK_EQ(details.location(), location);
+#endif
+ if (location == kField) {
+ return handle(descriptors->GetFieldType(descriptor), isolate);
+ } else {
+ return descriptors->GetValue(descriptor)
+ ->OptimalType(isolate, representation);
+ }
+}
+
+
+// Reconfigures property at |modify_index| with |new_kind|, |new_attributes|,
+// |store_mode| and/or |new_representation|/|new_field_type|.
+// If |modify_index| is negative then no properties are reconfigured but the
+// map is migrated to the up-to-date non-deprecated state.
+//
+// This method rewrites or completes the transition tree to reflect the new
+// change. To avoid high degrees over polymorphism, and to stabilize quickly,
+// on every rewrite the new type is deduced by merging the current type with
+// any potential new (partial) version of the type in the transition tree.
// To do this, on each rewrite:
// - Search the root of the transition tree using FindRootMap.
-// - Find |target_map|, the newest matching version of this map using the keys
-// in the |old_map|'s descriptor array to walk the transition tree.
-// - Merge/generalize the descriptor array of the |old_map| and |target_map|.
+// - Find |target_map|, the newest matching version of this map using the
+// virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at
+// |modify_index| is considered to be of |new_kind| and having
+// |new_attributes|) to walk the transition tree.
+// - Merge/generalize the "enhanced" descriptor array of the |old_map| and
+// descriptor array of the |target_map|.
// - Generalize the |modify_index| descriptor using |new_representation| and
// |new_field_type|.
// - Walk the tree again starting from the root towards |target_map|. Stop at
@@ -2488,68 +2423,128 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
// Return it.
// - Otherwise, invalidate the outdated transition target from |target_map|, and
// replace its transition tree with a new branch for the updated descriptors.
-Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
- int modify_index,
- Representation new_representation,
- Handle<HeapType> new_field_type,
- StoreMode store_mode) {
+Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
+ PropertyKind new_kind,
+ PropertyAttributes new_attributes,
+ Representation new_representation,
+ Handle<HeapType> new_field_type,
+ StoreMode store_mode) {
+ DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet.
+ DCHECK(store_mode != FORCE_FIELD || modify_index >= 0);
Isolate* isolate = old_map->GetIsolate();
Handle<DescriptorArray> old_descriptors(
old_map->instance_descriptors(), isolate);
int old_nof = old_map->NumberOfOwnDescriptors();
- PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
- Representation old_representation = old_details.representation();
-
- // It's fine to transition from None to anything but double without any
- // modification to the object, because the default uninitialized value for
- // representation None can be overwritten by both smi and tagged values.
- // Doubles, however, would require a box allocation.
- if (old_representation.IsNone() && !new_representation.IsNone() &&
+
+ // If it's just a representation generalization case (i.e. property kind and
+ // attributes stays unchanged) it's fine to transition from None to anything
+ // but double without any modification to the object, because the default
+ // uninitialized value for representation None can be overwritten by both
+ // smi and tagged values. Doubles, however, would require a box allocation.
+ if (modify_index >= 0 && !new_representation.IsNone() &&
!new_representation.IsDouble()) {
- DCHECK(old_details.type() == FIELD);
- if (FLAG_trace_generalization) {
- old_map->PrintGeneralization(
- stdout, "uninitialized field",
- modify_index, old_map->NumberOfOwnDescriptors(),
- old_map->NumberOfOwnDescriptors(), false,
- old_representation, new_representation,
- old_descriptors->GetFieldType(modify_index), *new_field_type);
- }
- Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
+ PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
+ Representation old_representation = old_details.representation();
+
+ if (old_representation.IsNone()) {
+ DCHECK_EQ(new_kind, old_details.kind());
+ DCHECK_EQ(new_attributes, old_details.attributes());
+ DCHECK_EQ(DATA, old_details.type());
+ if (FLAG_trace_generalization) {
+ old_map->PrintGeneralization(
+ stdout, "uninitialized field", modify_index,
+ old_map->NumberOfOwnDescriptors(),
+ old_map->NumberOfOwnDescriptors(), false, old_representation,
+ new_representation, old_descriptors->GetFieldType(modify_index),
+ *new_field_type);
+ }
+ Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
- GeneralizeFieldType(field_owner, modify_index, new_representation,
- new_field_type);
- DCHECK(old_descriptors->GetDetails(modify_index).representation().Equals(
- new_representation));
- DCHECK(old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
- return old_map;
+ GeneralizeFieldType(field_owner, modify_index, new_representation,
+ new_field_type);
+ DCHECK(old_descriptors->GetDetails(modify_index)
+ .representation()
+ .Equals(new_representation));
+ DCHECK(
+ old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
+ return old_map;
+ }
}
// Check the state of the root map.
Handle<Map> root_map(old_map->FindRootMap(), isolate);
if (!old_map->EquivalentToForTransition(*root_map)) {
return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+ new_kind, new_attributes,
"GenAll_NotEquivalent");
}
+
+ ElementsKind from_kind = root_map->elements_kind();
+ ElementsKind to_kind = old_map->elements_kind();
+ if (from_kind != to_kind &&
+ !(IsTransitionableFastElementsKind(from_kind) &&
+ IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
+ return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+ new_kind, new_attributes,
+ "GenAll_InvalidElementsTransition");
+ }
int root_nof = root_map->NumberOfOwnDescriptors();
- if (modify_index < root_nof) {
+ if (modify_index >= 0 && modify_index < root_nof) {
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
- if ((old_details.type() != FIELD && store_mode == FORCE_IN_OBJECT) ||
- (old_details.type() == FIELD &&
+ if (old_details.kind() != new_kind ||
+ old_details.attributes() != new_attributes) {
+ return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+ new_kind, new_attributes,
+ "GenAll_RootModification1");
+ }
+ if ((old_details.type() != DATA && store_mode == FORCE_FIELD) ||
+ (old_details.type() == DATA &&
(!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
!new_representation.fits_into(old_details.representation())))) {
return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
- "GenAll_RootModification");
+ new_kind, new_attributes,
+ "GenAll_RootModification2");
}
}
+ // From here on, use the map with correct elements kind as root map.
+ if (from_kind != to_kind) {
+ root_map = Map::AsElementsKind(root_map, to_kind);
+ }
+
Handle<Map> target_map = root_map;
for (int i = root_nof; i < old_nof; ++i) {
PropertyDetails old_details = old_descriptors->GetDetails(i);
- int j = target_map->SearchTransition(old_details.kind(),
- old_descriptors->GetKey(i),
- old_details.attributes());
+ PropertyKind next_kind;
+ PropertyLocation next_location;
+ PropertyAttributes next_attributes;
+ Representation next_representation;
+ bool property_kind_reconfiguration = false;
+
+ if (modify_index == i) {
+ DCHECK_EQ(FORCE_FIELD, store_mode);
+ property_kind_reconfiguration = old_details.kind() != new_kind;
+
+ next_kind = new_kind;
+ next_location = kField;
+ next_attributes = new_attributes;
+ // If property kind is not reconfigured merge the result with
+ // representation/field type from the old descriptor.
+ next_representation = new_representation;
+ if (!property_kind_reconfiguration) {
+ next_representation =
+ next_representation.generalize(old_details.representation());
+ }
+
+ } else {
+ next_kind = old_details.kind();
+ next_location = old_details.location();
+ next_attributes = old_details.attributes();
+ next_representation = old_details.representation();
+ }
+ int j = target_map->SearchTransition(next_kind, old_descriptors->GetKey(i),
+ next_attributes);
if (j == TransitionArray::kNotFound) break;
Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
Handle<DescriptorArray> tmp_descriptors = handle(
@@ -2557,42 +2552,48 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
// Check if target map is incompatible.
PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
- PropertyType old_type = old_details.type();
- PropertyType tmp_type = tmp_details.type();
- DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
- if ((tmp_type == CALLBACKS || old_type == CALLBACKS) &&
- (tmp_type != old_type ||
- tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
+ DCHECK_EQ(next_kind, tmp_details.kind());
+ DCHECK_EQ(next_attributes, tmp_details.attributes());
+ if (next_kind == kAccessor &&
+ !EqualImmutableValues(old_descriptors->GetValue(i),
+ tmp_descriptors->GetValue(i))) {
return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+ new_kind, new_attributes,
"GenAll_Incompatible");
}
- Representation old_representation = old_details.representation();
+ if (next_location == kField && tmp_details.location() == kDescriptor) break;
+
Representation tmp_representation = tmp_details.representation();
- if (!old_representation.fits_into(tmp_representation) ||
- (!new_representation.fits_into(tmp_representation) &&
- modify_index == i)) {
- break;
- }
- if (tmp_type == FIELD) {
- // Generalize the field type as necessary.
- Handle<HeapType> old_field_type = (old_type == FIELD)
- ? handle(old_descriptors->GetFieldType(i), isolate)
- : old_descriptors->GetValue(i)->OptimalType(
- isolate, tmp_representation);
- if (modify_index == i) {
- old_field_type = GeneralizeFieldType(
- new_field_type, old_field_type, isolate);
- }
- GeneralizeFieldType(tmp_map, i, tmp_representation, old_field_type);
- } else if (tmp_type == CONSTANT) {
- if (old_type != CONSTANT ||
- old_descriptors->GetConstant(i) != tmp_descriptors->GetConstant(i)) {
- break;
+ if (!next_representation.fits_into(tmp_representation)) break;
+
+ PropertyLocation old_location = old_details.location();
+ PropertyLocation tmp_location = tmp_details.location();
+ if (tmp_location == kField) {
+ if (next_kind == kData) {
+ Handle<HeapType> next_field_type;
+ if (modify_index == i) {
+ next_field_type = new_field_type;
+ if (!property_kind_reconfiguration) {
+ Handle<HeapType> old_field_type =
+ GetFieldType(isolate, old_descriptors, i,
+ old_details.location(), tmp_representation);
+ next_field_type =
+ GeneralizeFieldType(next_field_type, old_field_type, isolate);
+ }
+ } else {
+ Handle<HeapType> old_field_type =
+ GetFieldType(isolate, old_descriptors, i, old_details.location(),
+ tmp_representation);
+ next_field_type = old_field_type;
+ }
+ GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type);
}
- } else {
- DCHECK_EQ(tmp_type, old_type);
- DCHECK_EQ(tmp_descriptors->GetValue(i), old_descriptors->GetValue(i));
+ } else if (old_location == kField ||
+ !EqualImmutableValues(old_descriptors->GetValue(i),
+ tmp_descriptors->GetValue(i))) {
+ break;
}
+ DCHECK(!tmp_map->is_deprecated());
target_map = tmp_map;
}
@@ -2601,37 +2602,56 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
target_map->instance_descriptors(), isolate);
int target_nof = target_map->NumberOfOwnDescriptors();
if (target_nof == old_nof &&
- (store_mode != FORCE_IN_OBJECT ||
- target_descriptors->GetDetails(modify_index).type() == FIELD)) {
- DCHECK(modify_index < target_nof);
- DCHECK(new_representation.fits_into(
- target_descriptors->GetDetails(modify_index).representation()));
- DCHECK(target_descriptors->GetDetails(modify_index).type() != FIELD ||
- new_field_type->NowIs(
- target_descriptors->GetFieldType(modify_index)));
+ (store_mode != FORCE_FIELD ||
+ (modify_index >= 0 &&
+ target_descriptors->GetDetails(modify_index).location() == kField))) {
+#ifdef DEBUG
+ if (modify_index >= 0) {
+ PropertyDetails details = target_descriptors->GetDetails(modify_index);
+ DCHECK_EQ(new_kind, details.kind());
+ DCHECK_EQ(new_attributes, details.attributes());
+ DCHECK(new_representation.fits_into(details.representation()));
+ DCHECK(details.location() != kField ||
+ new_field_type->NowIs(
+ target_descriptors->GetFieldType(modify_index)));
+ }
+#endif
return target_map;
}
// Find the last compatible target map in the transition tree.
for (int i = target_nof; i < old_nof; ++i) {
PropertyDetails old_details = old_descriptors->GetDetails(i);
- int j = target_map->SearchTransition(old_details.kind(),
- old_descriptors->GetKey(i),
- old_details.attributes());
+ PropertyKind next_kind;
+ PropertyAttributes next_attributes;
+ if (modify_index == i) {
+ next_kind = new_kind;
+ next_attributes = new_attributes;
+ } else {
+ next_kind = old_details.kind();
+ next_attributes = old_details.attributes();
+ }
+ int j = target_map->SearchTransition(next_kind, old_descriptors->GetKey(i),
+ next_attributes);
if (j == TransitionArray::kNotFound) break;
Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
Handle<DescriptorArray> tmp_descriptors(
tmp_map->instance_descriptors(), isolate);
// Check if target map is compatible.
+#ifdef DEBUG
PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
- DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
- if ((tmp_details.type() == CALLBACKS || old_details.type() == CALLBACKS) &&
- (tmp_details.type() != old_details.type() ||
- tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
+ DCHECK_EQ(next_kind, tmp_details.kind());
+ DCHECK_EQ(next_attributes, tmp_details.attributes());
+#endif
+ if (next_kind == kAccessor &&
+ !EqualImmutableValues(old_descriptors->GetValue(i),
+ tmp_descriptors->GetValue(i))) {
return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+ new_kind, new_attributes,
"GenAll_Incompatible");
}
+ DCHECK(!tmp_map->is_deprecated());
target_map = tmp_map;
}
target_nof = target_map->NumberOfOwnDescriptors();
@@ -2654,7 +2674,7 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
int current_offset = 0;
for (int i = 0; i < root_nof; ++i) {
PropertyDetails old_details = old_descriptors->GetDetails(i);
- if (old_details.type() == FIELD) {
+ if (old_details.location() == kField) {
current_offset += old_details.field_width_in_words();
}
Descriptor d(handle(old_descriptors->GetKey(i), isolate),
@@ -2668,41 +2688,85 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
PropertyDetails old_details = old_descriptors->GetDetails(i);
PropertyDetails target_details = target_descriptors->GetDetails(i);
- target_details = target_details.CopyWithRepresentation(
- old_details.representation().generalize(
- target_details.representation()));
+
+ PropertyKind next_kind;
+ PropertyAttributes next_attributes;
+ PropertyLocation next_location;
+ Representation next_representation;
+ bool property_kind_reconfiguration = false;
+
if (modify_index == i) {
- target_details = target_details.CopyWithRepresentation(
- new_representation.generalize(target_details.representation()));
- }
- DCHECK_EQ(old_details.attributes(), target_details.attributes());
- if (old_details.type() == FIELD || target_details.type() == FIELD ||
- (modify_index == i && store_mode == FORCE_IN_OBJECT) ||
- (target_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
- Handle<HeapType> old_field_type = (old_details.type() == FIELD)
- ? handle(old_descriptors->GetFieldType(i), isolate)
- : old_descriptors->GetValue(i)->OptimalType(
- isolate, target_details.representation());
- Handle<HeapType> target_field_type = (target_details.type() == FIELD)
- ? handle(target_descriptors->GetFieldType(i), isolate)
- : target_descriptors->GetValue(i)->OptimalType(
- isolate, target_details.representation());
- target_field_type = GeneralizeFieldType(
- target_field_type, old_field_type, isolate);
- if (modify_index == i) {
- target_field_type = GeneralizeFieldType(
- target_field_type, new_field_type, isolate);
+ DCHECK_EQ(FORCE_FIELD, store_mode);
+ property_kind_reconfiguration = old_details.kind() != new_kind;
+
+ next_kind = new_kind;
+ next_attributes = new_attributes;
+ next_location = kField;
+
+ // Merge new representation/field type with ones from the target
+ // descriptor. If property kind is not reconfigured merge the result with
+ // representation/field type from the old descriptor.
+ next_representation =
+ new_representation.generalize(target_details.representation());
+ if (!property_kind_reconfiguration) {
+ next_representation =
+ next_representation.generalize(old_details.representation());
+ }
+ } else {
+ // Merge old_descriptor and target_descriptor entries.
+ DCHECK_EQ(target_details.kind(), old_details.kind());
+ next_kind = target_details.kind();
+ next_attributes = target_details.attributes();
+ next_location =
+ old_details.location() == kField ||
+ target_details.location() == kField ||
+ !EqualImmutableValues(target_descriptors->GetValue(i),
+ old_descriptors->GetValue(i))
+ ? kField
+ : kDescriptor;
+
+ next_representation = old_details.representation().generalize(
+ target_details.representation());
+ }
+ DCHECK_EQ(next_kind, target_details.kind());
+ DCHECK_EQ(next_attributes, target_details.attributes());
+
+ if (next_location == kField) {
+ if (next_kind == kData) {
+ Handle<HeapType> target_field_type =
+ GetFieldType(isolate, target_descriptors, i,
+ target_details.location(), next_representation);
+
+ Handle<HeapType> next_field_type;
+ if (modify_index == i) {
+ next_field_type =
+ GeneralizeFieldType(target_field_type, new_field_type, isolate);
+ if (!property_kind_reconfiguration) {
+ Handle<HeapType> old_field_type =
+ GetFieldType(isolate, old_descriptors, i,
+ old_details.location(), next_representation);
+ next_field_type =
+ GeneralizeFieldType(next_field_type, old_field_type, isolate);
+ }
+ } else {
+ Handle<HeapType> old_field_type =
+ GetFieldType(isolate, old_descriptors, i, old_details.location(),
+ next_representation);
+ next_field_type =
+ GeneralizeFieldType(target_field_type, old_field_type, isolate);
+ }
+ DataDescriptor d(target_key, current_offset, next_field_type,
+ next_attributes, next_representation);
+ current_offset += d.GetDetails().field_width_in_words();
+ new_descriptors->Set(i, &d);
+ } else {
+ UNIMPLEMENTED(); // TODO(ishell): implement.
}
- FieldDescriptor d(target_key, current_offset, target_field_type,
- target_details.attributes(),
- target_details.representation());
- current_offset += d.GetDetails().field_width_in_words();
- new_descriptors->Set(i, &d);
} else {
- DCHECK_NE(FIELD, target_details.type());
- Descriptor d(target_key,
- handle(target_descriptors->GetValue(i), isolate),
- target_details);
+ PropertyDetails details(next_attributes, next_kind, next_location,
+ next_representation);
+ Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate),
+ details);
new_descriptors->Set(i, &d);
}
}
@@ -2711,46 +2775,74 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
for (int i = target_nof; i < old_nof; ++i) {
PropertyDetails old_details = old_descriptors->GetDetails(i);
Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
+
+ // Merge old_descriptor entry and modified details together.
+ PropertyKind next_kind;
+ PropertyAttributes next_attributes;
+ PropertyLocation next_location;
+ Representation next_representation;
+ bool property_kind_reconfiguration = false;
+
if (modify_index == i) {
- old_details = old_details.CopyWithRepresentation(
- new_representation.generalize(old_details.representation()));
- }
- if (old_details.type() == FIELD) {
- Handle<HeapType> old_field_type(
- old_descriptors->GetFieldType(i), isolate);
- if (modify_index == i) {
- old_field_type = GeneralizeFieldType(
- old_field_type, new_field_type, isolate);
+ DCHECK_EQ(FORCE_FIELD, store_mode);
+ // In case of property kind reconfiguration it is not necessary to
+ // take into account representation/field type of the old descriptor.
+ property_kind_reconfiguration = old_details.kind() != new_kind;
+
+ next_kind = new_kind;
+ next_attributes = new_attributes;
+ next_location = kField;
+ next_representation = new_representation;
+ if (!property_kind_reconfiguration) {
+ next_representation =
+ next_representation.generalize(old_details.representation());
}
- FieldDescriptor d(old_key, current_offset, old_field_type,
- old_details.attributes(), old_details.representation());
- current_offset += d.GetDetails().field_width_in_words();
- new_descriptors->Set(i, &d);
} else {
- DCHECK(old_details.type() == CONSTANT || old_details.type() == CALLBACKS);
- if (modify_index == i && store_mode == FORCE_IN_OBJECT) {
- FieldDescriptor d(
- old_key, current_offset,
- GeneralizeFieldType(old_descriptors->GetValue(i)->OptimalType(
- isolate, old_details.representation()),
- new_field_type, isolate),
- old_details.attributes(), old_details.representation());
+ next_kind = old_details.kind();
+ next_attributes = old_details.attributes();
+ next_location = old_details.location();
+ next_representation = old_details.representation();
+ }
+
+ if (next_location == kField) {
+ if (next_kind == kData) {
+ Handle<HeapType> next_field_type;
+ if (modify_index == i) {
+ next_field_type = new_field_type;
+ if (!property_kind_reconfiguration) {
+ Handle<HeapType> old_field_type =
+ GetFieldType(isolate, old_descriptors, i,
+ old_details.location(), next_representation);
+ next_field_type =
+ GeneralizeFieldType(next_field_type, old_field_type, isolate);
+ }
+ } else {
+ Handle<HeapType> old_field_type =
+ GetFieldType(isolate, old_descriptors, i, old_details.location(),
+ next_representation);
+ next_field_type = old_field_type;
+ }
+
+ DataDescriptor d(old_key, current_offset, next_field_type,
+ next_attributes, next_representation);
current_offset += d.GetDetails().field_width_in_words();
new_descriptors->Set(i, &d);
} else {
- DCHECK_NE(FIELD, old_details.type());
- Descriptor d(old_key,
- handle(old_descriptors->GetValue(i), isolate),
- old_details);
- new_descriptors->Set(i, &d);
+ UNIMPLEMENTED(); // TODO(ishell): implement.
}
+ } else {
+ PropertyDetails details(next_attributes, next_kind, next_location,
+ next_representation);
+ Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate),
+ details);
+ new_descriptors->Set(i, &d);
}
}
new_descriptors->Sort();
- DCHECK(store_mode != FORCE_IN_OBJECT ||
- new_descriptors->GetDetails(modify_index).type() == FIELD);
+ DCHECK(store_mode != FORCE_FIELD ||
+ new_descriptors->GetDetails(modify_index).location() == kField);
Handle<Map> split_map(root_map->FindLastMatchMap(
root_nof, old_nof, *new_descriptors), isolate);
@@ -2759,34 +2851,48 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
Handle<LayoutDescriptor> new_layout_descriptor =
LayoutDescriptor::New(split_map, new_descriptors, old_nof);
- PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
+
+ PropertyKind split_kind;
+ PropertyAttributes split_attributes;
+ if (modify_index == split_nof) {
+ split_kind = new_kind;
+ split_attributes = new_attributes;
+ } else {
+ PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
+ split_kind = split_prop_details.kind();
+ split_attributes = split_prop_details.attributes();
+ }
bool transition_target_deprecated = split_map->DeprecateTarget(
- split_prop_details.kind(), old_descriptors->GetKey(split_nof),
- split_prop_details.attributes(), *new_descriptors,
- *new_layout_descriptor);
+ split_kind, old_descriptors->GetKey(split_nof), split_attributes,
+ *new_descriptors, *new_layout_descriptor);
// If |transition_target_deprecated| is true then the transition array
// already contains entry for given descriptor. This means that the transition
// could be inserted regardless of whether transitions array is full or not.
if (!transition_target_deprecated && !split_map->CanHaveMoreTransitions()) {
return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+ new_kind, new_attributes,
"GenAll_CantHaveMoreTransitions");
}
- if (FLAG_trace_generalization) {
+ if (FLAG_trace_generalization && modify_index >= 0) {
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
- Handle<HeapType> old_field_type = (old_details.type() == FIELD)
- ? handle(old_descriptors->GetFieldType(modify_index), isolate)
- : HeapType::Constant(handle(old_descriptors->GetValue(modify_index),
- isolate), isolate);
- Handle<HeapType> new_field_type = (new_details.type() == FIELD)
- ? handle(new_descriptors->GetFieldType(modify_index), isolate)
- : HeapType::Constant(handle(new_descriptors->GetValue(modify_index),
- isolate), isolate);
+ Handle<HeapType> old_field_type =
+ (old_details.type() == DATA)
+ ? handle(old_descriptors->GetFieldType(modify_index), isolate)
+ : HeapType::Constant(
+ handle(old_descriptors->GetValue(modify_index), isolate),
+ isolate);
+ Handle<HeapType> new_field_type =
+ (new_details.type() == DATA)
+ ? handle(new_descriptors->GetFieldType(modify_index), isolate)
+ : HeapType::Constant(
+ handle(new_descriptors->GetValue(modify_index), isolate),
+ isolate);
old_map->PrintGeneralization(
stdout, "", modify_index, split_nof, old_nof,
- old_details.type() == CONSTANT && store_mode == FORCE_IN_OBJECT,
+ old_details.location() == kDescriptor && store_mode == FORCE_FIELD,
old_details.representation(), new_details.representation(),
*old_field_type, *new_field_type);
}
@@ -2802,15 +2908,16 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
}
-// Generalize the representation of all FIELD descriptors.
+// Generalize the representation of all DATA descriptors.
Handle<Map> Map::GeneralizeAllFieldRepresentations(
Handle<Map> map) {
Handle<DescriptorArray> descriptors(map->instance_descriptors());
for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
- if (descriptors->GetDetails(i).type() == FIELD) {
- map = GeneralizeRepresentation(map, i, Representation::Tagged(),
- HeapType::Any(map->GetIsolate()),
- FORCE_IN_OBJECT);
+ PropertyDetails details = descriptors->GetDetails(i);
+ if (details.type() == DATA) {
+ map = ReconfigureProperty(map, i, kData, details.attributes(),
+ Representation::Tagged(),
+ HeapType::Any(map->GetIsolate()), FORCE_FIELD);
}
}
return map;
@@ -2834,9 +2941,9 @@ MaybeHandle<Map> Map::TryUpdate(Handle<Map> map) {
// static
Handle<Map> Map::Update(Handle<Map> map) {
if (!map->is_deprecated()) return map;
- return GeneralizeRepresentation(map, 0, Representation::None(),
- HeapType::None(map->GetIsolate()),
- ALLOW_IN_DESCRIPTOR);
+ return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
+ HeapType::None(map->GetIsolate()),
+ ALLOW_IN_DESCRIPTOR);
}
@@ -2874,27 +2981,27 @@ MaybeHandle<Map> Map::TryUpdateInternal(Handle<Map> old_map) {
Object* new_value = new_descriptors->GetValue(i);
Object* old_value = old_descriptors->GetValue(i);
switch (new_details.type()) {
- case FIELD: {
+ case DATA: {
PropertyType old_type = old_details.type();
- if (old_type == FIELD) {
+ if (old_type == DATA) {
if (!HeapType::cast(old_value)->NowIs(HeapType::cast(new_value))) {
return MaybeHandle<Map>();
}
} else {
- DCHECK(old_type == CONSTANT);
+ DCHECK(old_type == DATA_CONSTANT);
if (!HeapType::cast(new_value)->NowContains(old_value)) {
return MaybeHandle<Map>();
}
}
break;
}
- case ACCESSOR_FIELD:
+ case ACCESSOR:
DCHECK(HeapType::Any()->Is(HeapType::cast(new_value)));
break;
- case CONSTANT:
- case CALLBACKS:
- if (old_details.location() == IN_OBJECT || old_value != new_value) {
+ case DATA_CONSTANT:
+ case ACCESSOR_CONSTANT:
+ if (old_details.location() == kField || old_value != new_value) {
return MaybeHandle<Map>();
}
break;
@@ -2933,22 +3040,24 @@ MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
Handle<Name> name, Handle<Object> value,
- StrictMode strict_mode,
+ LanguageMode language_mode,
StoreFromKeyed store_mode) {
LookupIterator it(object, name);
- return SetProperty(&it, value, strict_mode, store_mode);
+ return SetProperty(&it, value, language_mode, store_mode);
}
-MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
- Handle<Object> value,
- StrictMode strict_mode,
- StoreFromKeyed store_mode,
- StorePropertyMode data_store_mode) {
+MaybeHandle<Object> Object::SetPropertyInternal(LookupIterator* it,
+ Handle<Object> value,
+ LanguageMode language_mode,
+ StoreFromKeyed store_mode,
+ bool* found) {
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
AssertNoContextChange ncc(it->isolate());
+ *found = true;
+
bool done = false;
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
@@ -2961,20 +3070,20 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
// until we find the property.
if (it->HasAccess(v8::ACCESS_SET)) break;
return JSObject::SetPropertyWithFailedAccessCheck(it, value,
- strict_mode);
+ language_mode);
case LookupIterator::JSPROXY:
if (it->HolderIsReceiverOrHiddenPrototype()) {
return JSProxy::SetPropertyWithHandler(it->GetHolder<JSProxy>(),
it->GetReceiver(), it->name(),
- value, strict_mode);
+ value, language_mode);
} else {
// TODO(verwaest): Use the MaybeHandle to indicate result.
bool has_result = false;
MaybeHandle<Object> maybe_result =
JSProxy::SetPropertyViaPrototypesWithHandler(
it->GetHolder<JSProxy>(), it->GetReceiver(), it->name(),
- value, strict_mode, &has_result);
+ value, language_mode, &has_result);
if (has_result) return maybe_result;
done = true;
}
@@ -2993,27 +3102,22 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
if (!maybe_attributes.has_value) return MaybeHandle<Object>();
done = maybe_attributes.value != ABSENT;
if (done && (maybe_attributes.value & READ_ONLY) != 0) {
- return WriteToReadOnlyProperty(it, value, strict_mode);
+ return WriteToReadOnlyProperty(it, value, language_mode);
}
}
break;
case LookupIterator::ACCESSOR:
if (it->property_details().IsReadOnly()) {
- return WriteToReadOnlyProperty(it, value, strict_mode);
- }
- if (it->HolderIsReceiverOrHiddenPrototype() ||
- !it->GetAccessors()->IsDeclaredAccessorInfo()) {
- return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
- it->GetHolder<JSObject>(),
- it->GetAccessors(), strict_mode);
+ return WriteToReadOnlyProperty(it, value, language_mode);
}
- done = true;
- break;
+ return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
+ it->GetHolder<JSObject>(),
+ it->GetAccessors(), language_mode);
case LookupIterator::DATA:
if (it->property_details().IsReadOnly()) {
- return WriteToReadOnlyProperty(it, value, strict_mode);
+ return WriteToReadOnlyProperty(it, value, language_mode);
}
if (it->HolderIsReceiverOrHiddenPrototype()) {
return SetDataProperty(it, value);
@@ -3032,34 +3136,103 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
// If the receiver is the JSGlobalObject, the store was contextual. In case
// the property did not exist yet on the global object itself, we have to
// throw a reference error in strict mode.
- if (it->GetReceiver()->IsJSGlobalObject() && strict_mode == STRICT) {
- Handle<Object> args[1] = {it->name()};
- THROW_NEW_ERROR(it->isolate(),
- NewReferenceError("not_defined", HandleVector(args, 1)),
- Object);
+ if (it->GetReceiver()->IsJSGlobalObject() && is_strict(language_mode)) {
+ Handle<Object> args[] = {it->name()};
+ THROW_NEW_ERROR(
+ it->isolate(),
+ NewReferenceError("not_defined", HandleVector(args, arraysize(args))),
+ Object);
}
- if (data_store_mode == SUPER_PROPERTY) {
- LookupIterator own_lookup(it->GetReceiver(), it->name(),
- LookupIterator::OWN);
+ *found = false;
+ return MaybeHandle<Object>();
+}
+
+
+MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
+ Handle<Object> value,
+ LanguageMode language_mode,
+ StoreFromKeyed store_mode) {
+ bool found = false;
+ MaybeHandle<Object> result =
+ SetPropertyInternal(it, value, language_mode, store_mode, &found);
+ if (found) return result;
+ return AddDataProperty(it, value, NONE, language_mode, store_mode);
+}
+
+
+MaybeHandle<Object> Object::SetSuperProperty(LookupIterator* it,
+ Handle<Object> value,
+ LanguageMode language_mode,
+ StoreFromKeyed store_mode) {
+ bool found = false;
+ MaybeHandle<Object> result =
+ SetPropertyInternal(it, value, language_mode, store_mode, &found);
+ if (found) return result;
+
+ LookupIterator own_lookup(it->GetReceiver(), it->name(), LookupIterator::OWN);
+
+ switch (own_lookup.state()) {
+ case LookupIterator::NOT_FOUND:
+ return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode,
+ store_mode);
+
+ case LookupIterator::DATA: {
+ PropertyDetails details = own_lookup.property_details();
+ if (details.IsConfigurable() || !details.IsReadOnly()) {
+ return JSObject::SetOwnPropertyIgnoreAttributes(
+ Handle<JSObject>::cast(it->GetReceiver()), it->name(), value,
+ details.attributes());
+ }
+ return WriteToReadOnlyProperty(&own_lookup, value, language_mode);
+ }
- return JSObject::SetProperty(&own_lookup, value, strict_mode, store_mode,
- NORMAL_PROPERTY);
+ case LookupIterator::ACCESSOR: {
+ PropertyDetails details = own_lookup.property_details();
+ if (details.IsConfigurable()) {
+ return JSObject::SetOwnPropertyIgnoreAttributes(
+ Handle<JSObject>::cast(it->GetReceiver()), it->name(), value,
+ details.attributes());
+ }
+
+ return RedefineNonconfigurableProperty(it->isolate(), it->name(), value,
+ language_mode);
+ }
+
+ case LookupIterator::TRANSITION:
+ UNREACHABLE();
+ break;
+
+ case LookupIterator::INTERCEPTOR:
+ case LookupIterator::JSPROXY:
+ case LookupIterator::ACCESS_CHECK: {
+ bool found = false;
+ MaybeHandle<Object> result = SetPropertyInternal(
+ &own_lookup, value, language_mode, store_mode, &found);
+ if (found) return result;
+ return SetDataProperty(&own_lookup, value);
+ }
}
- return AddDataProperty(it, value, NONE, strict_mode, store_mode);
+ UNREACHABLE();
+ return MaybeHandle<Object>();
}
-MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it,
- Handle<Object> value,
- StrictMode strict_mode) {
- if (strict_mode != STRICT) return value;
+MaybeHandle<Object> Object::WriteToReadOnlyProperty(
+ LookupIterator* it, Handle<Object> value, LanguageMode language_mode) {
+ return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), it->name(),
+ value, language_mode);
+}
+
- Handle<Object> args[] = {it->name(), it->GetReceiver()};
- THROW_NEW_ERROR(it->isolate(),
- NewTypeError("strict_read_only_property",
- HandleVector(args, arraysize(args))),
+MaybeHandle<Object> Object::WriteToReadOnlyProperty(
+ Isolate* isolate, Handle<Object> receiver, Handle<Object> name,
+ Handle<Object> value, LanguageMode language_mode) {
+ if (is_sloppy(language_mode)) return value;
+ Handle<Object> args[] = {name, receiver};
+ THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
+ HandleVector(args, arraysize(args))),
Object);
}
@@ -3068,12 +3241,19 @@ MaybeHandle<Object> Object::WriteToReadOnlyElement(Isolate* isolate,
Handle<Object> receiver,
uint32_t index,
Handle<Object> value,
- StrictMode strict_mode) {
- if (strict_mode != STRICT) return value;
+ LanguageMode language_mode) {
+ return WriteToReadOnlyProperty(isolate, receiver,
+ isolate->factory()->NewNumberFromUint(index),
+ value, language_mode);
+}
- Handle<Object> args[] = {isolate->factory()->NewNumberFromUint(index),
- receiver};
- THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
+
+MaybeHandle<Object> Object::RedefineNonconfigurableProperty(
+ Isolate* isolate, Handle<Object> name, Handle<Object> value,
+ LanguageMode language_mode) {
+ if (is_sloppy(language_mode)) return value;
+ Handle<Object> args[] = {name};
+ THROW_NEW_ERROR(isolate, NewTypeError("redefine_disallowed",
HandleVector(args, arraysize(args))),
Object);
}
@@ -3118,12 +3298,12 @@ MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
Handle<Object> value,
PropertyAttributes attributes,
- StrictMode strict_mode,
+ LanguageMode language_mode,
StoreFromKeyed store_mode) {
DCHECK(!it->GetReceiver()->IsJSProxy());
if (!it->GetReceiver()->IsJSObject()) {
// TODO(verwaest): Throw a TypeError with a more specific message.
- return WriteToReadOnlyProperty(it, value, strict_mode);
+ return WriteToReadOnlyProperty(it, value, language_mode);
}
Handle<JSObject> receiver = it->GetStoreTarget();
@@ -3140,9 +3320,9 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
// |value| under it->name() with |attributes|.
it->PrepareTransitionToDataProperty(value, attributes, store_mode);
if (it->state() != LookupIterator::TRANSITION) {
- if (strict_mode == SLOPPY) return value;
+ if (is_sloppy(language_mode)) return value;
- Handle<Object> args[1] = {it->name()};
+ Handle<Object> args[] = {it->name()};
THROW_NEW_ERROR(it->isolate(),
NewTypeError("object_not_extensible",
HandleVector(args, arraysize(args))),
@@ -3154,6 +3334,7 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
if (receiver->map()->is_dictionary_map()) {
// TODO(verwaest): Probably should ensure this is done beforehand.
it->InternalizeName();
+ // TODO(dcarney): just populate TransitionPropertyCell here?
JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
} else {
// Write the property value.
@@ -3174,34 +3355,42 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes(
- Handle<JSObject> object,
- uint32_t index,
- Handle<Object> value,
- bool* found,
- StrictMode strict_mode) {
- Isolate *isolate = object->GetIsolate();
+ Handle<JSObject> object, uint32_t index, Handle<Object> value, bool* found,
+ LanguageMode language_mode) {
+ Isolate* isolate = object->GetIsolate();
for (PrototypeIterator iter(isolate, object); !iter.IsAtEnd();
iter.Advance()) {
if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
return JSProxy::SetPropertyViaPrototypesWithHandler(
Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), object,
isolate->factory()->Uint32ToString(index), // name
- value, strict_mode, found);
+ value, language_mode, found);
}
Handle<JSObject> js_proto =
Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+
+ if (js_proto->IsAccessCheckNeeded()) {
+ if (!isolate->MayIndexedAccess(js_proto, index, v8::ACCESS_SET)) {
+ *found = true;
+ isolate->ReportFailedAccessCheck(js_proto, v8::ACCESS_SET);
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ return MaybeHandle<Object>();
+ }
+ }
+
if (!js_proto->HasDictionaryElements()) {
continue;
}
+
Handle<SeededNumberDictionary> dictionary(js_proto->element_dictionary());
int entry = dictionary->FindEntry(index);
if (entry != SeededNumberDictionary::kNotFound) {
PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() == CALLBACKS) {
+ if (details.type() == ACCESSOR_CONSTANT) {
*found = true;
Handle<Object> structure(dictionary->ValueAt(entry), isolate);
return SetElementWithCallback(object, structure, index, value, js_proto,
- strict_mode);
+ language_mode);
}
}
}
@@ -3304,7 +3493,7 @@ struct DescriptorArrayAppender {
int valid_descriptors,
Handle<DescriptorArray> array) {
DisallowHeapAllocation no_gc;
- CallbacksDescriptor desc(key, entry, entry->property_attributes());
+ AccessorConstantDescriptor desc(key, entry, entry->property_attributes());
array->Append(&desc);
}
};
@@ -3473,19 +3662,21 @@ static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
Handle<Map> current_map = map;
ElementsKind kind = map->elements_kind();
- if (!map->is_prototype_map()) {
+ TransitionFlag flag;
+ if (map->is_prototype_map()) {
+ flag = OMIT_TRANSITION;
+ } else {
+ flag = INSERT_TRANSITION;
while (kind != to_kind && !IsTerminalElementsKind(kind)) {
kind = GetNextTransitionElementsKind(kind);
- current_map =
- Map::CopyAsElementsKind(current_map, kind, INSERT_TRANSITION);
+ current_map = Map::CopyAsElementsKind(current_map, kind, flag);
}
}
// In case we are exiting the fast elements kind system, just add the map in
// the end.
if (kind != to_kind) {
- current_map = Map::CopyAsElementsKind(
- current_map, to_kind, INSERT_TRANSITION);
+ current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
}
DCHECK(current_map->elements_kind() == to_kind);
@@ -3582,11 +3773,9 @@ Maybe<bool> JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy,
}
-MaybeHandle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy,
- Handle<Object> receiver,
- Handle<Name> name,
- Handle<Object> value,
- StrictMode strict_mode) {
+MaybeHandle<Object> JSProxy::SetPropertyWithHandler(
+ Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name,
+ Handle<Object> value, LanguageMode language_mode) {
Isolate* isolate = proxy->GetIsolate();
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
@@ -3608,7 +3797,7 @@ MaybeHandle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy,
MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name,
- Handle<Object> value, StrictMode strict_mode, bool* done) {
+ Handle<Object> value, LanguageMode language_mode, bool* done) {
Isolate* isolate = proxy->GetIsolate();
Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy.
@@ -3679,11 +3868,8 @@ MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
DCHECK(writable->IsBoolean());
*done = writable->IsFalse();
if (!*done) return isolate->factory()->the_hole_value();
- if (strict_mode == SLOPPY) return value;
- Handle<Object> args[] = { name, receiver };
- THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
- HandleVector(args, arraysize(args))),
- Object);
+ return WriteToReadOnlyProperty(isolate, receiver, name, value,
+ language_mode);
}
// We have an AccessorDescriptor.
@@ -3696,7 +3882,7 @@ MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
receiver, Handle<JSReceiver>::cast(setter), value);
}
- if (strict_mode == SLOPPY) return value;
+ if (is_sloppy(language_mode)) return value;
Handle<Object> args2[] = { name, proxy };
THROW_NEW_ERROR(isolate, NewTypeError("no_setter_in_callback",
HandleVector(args2, arraysize(args2))),
@@ -3705,7 +3891,7 @@ MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
- Handle<JSProxy> proxy, Handle<Name> name, DeleteMode mode) {
+ Handle<JSProxy> proxy, Handle<Name> name, LanguageMode language_mode) {
Isolate* isolate = proxy->GetIsolate();
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
@@ -3723,7 +3909,7 @@ MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
Object);
bool result_bool = result->BooleanValue();
- if (mode == STRICT_DELETION && !result_bool) {
+ if (is_strict(language_mode) && !result_bool) {
Handle<Object> handler(proxy->handler(), isolate);
Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
STATIC_CHAR_VECTOR("delete"));
@@ -3737,10 +3923,10 @@ MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
MaybeHandle<Object> JSProxy::DeleteElementWithHandler(
- Handle<JSProxy> proxy, uint32_t index, DeleteMode mode) {
+ Handle<JSProxy> proxy, uint32_t index, LanguageMode language_mode) {
Isolate* isolate = proxy->GetIsolate();
Handle<String> name = isolate->factory()->Uint32ToString(index);
- return JSProxy::DeletePropertyWithHandler(proxy, name, mode);
+ return JSProxy::DeletePropertyWithHandler(proxy, name, language_mode);
}
@@ -3934,7 +4120,7 @@ void JSObject::WriteToField(int descriptor, Object* value) {
DescriptorArray* desc = map()->instance_descriptors();
PropertyDetails details = desc->GetDetails(descriptor);
- DCHECK(details.type() == FIELD);
+ DCHECK(details.type() == DATA);
FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
if (details.representation().IsDouble()) {
@@ -4043,7 +4229,6 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
}
it.ReconfigureDataProperty(value, attributes);
- it.PrepareForDataProperty(value);
value = it.WriteDataValue(value);
if (is_observed) {
@@ -4068,7 +4253,6 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
if (is_observed) old_value = it.GetDataValue();
it.ReconfigureDataProperty(value, attributes);
- it.PrepareForDataProperty(value);
value = it.WriteDataValue(value);
if (is_observed) {
@@ -4184,9 +4368,8 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeWithReceiver(
// Check access rights if needed.
if (object->IsAccessCheckNeeded()) {
if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
- isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
- return maybe(ABSENT);
+ return GetElementAttributesWithFailedAccessCheck(isolate, object,
+ receiver, index);
}
}
@@ -4263,8 +4446,8 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeFromInterceptor(
Maybe<PropertyAttributes> JSObject::GetElementAttributeWithoutInterceptor(
Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index,
bool check_prototype) {
- PropertyAttributes attr = object->GetElementsAccessor()->GetAttributes(
- receiver, object, index);
+ PropertyAttributes attr =
+ object->GetElementsAccessor()->GetAttributes(object, index);
if (attr != ABSENT) return maybe(attr);
// Handle [] on String objects.
@@ -4372,13 +4555,13 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
PropertyDetails details = descs->GetDetails(i);
Handle<Name> key(descs->GetKey(i));
switch (details.type()) {
- case CONSTANT: {
+ case DATA_CONSTANT: {
Handle<Object> value(descs->GetConstant(i), isolate);
- PropertyDetails d(details.attributes(), FIELD, i + 1);
+ PropertyDetails d(details.attributes(), DATA, i + 1);
dictionary = NameDictionary::Add(dictionary, key, value, d);
break;
}
- case FIELD: {
+ case DATA: {
FieldIndex index = FieldIndex::ForDescriptor(*map, i);
Handle<Object> value;
if (object->IsUnboxedDoubleField(index)) {
@@ -4392,20 +4575,20 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
value = isolate->factory()->NewHeapNumber(old->value());
}
}
- PropertyDetails d(details.attributes(), FIELD, i + 1);
+ PropertyDetails d(details.attributes(), DATA, i + 1);
dictionary = NameDictionary::Add(dictionary, key, value, d);
break;
}
- case ACCESSOR_FIELD: {
+ case ACCESSOR: {
FieldIndex index = FieldIndex::ForDescriptor(*map, i);
Handle<Object> value(object->RawFastPropertyAt(index), isolate);
- PropertyDetails d(details.attributes(), CALLBACKS, i + 1);
+ PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1);
dictionary = NameDictionary::Add(dictionary, key, value, d);
break;
}
- case CALLBACKS: {
+ case ACCESSOR_CONSTANT: {
Handle<Object> value(descs->GetCallbacksObject(i), isolate);
- PropertyDetails d(details.attributes(), CALLBACKS, i + 1);
+ PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1);
dictionary = NameDictionary::Add(dictionary, key, value, d);
break;
}
@@ -4489,7 +4672,7 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Object* value = dictionary->ValueAt(index);
PropertyType type = dictionary->DetailsAt(index).type();
- if (type == FIELD && !value->IsJSFunction()) {
+ if (type == DATA && !value->IsJSFunction()) {
number_of_fields += 1;
}
}
@@ -4558,9 +4741,10 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
PropertyType type = details.type();
if (value->IsJSFunction()) {
- ConstantDescriptor d(key, handle(value, isolate), details.attributes());
+ DataConstantDescriptor d(key, handle(value, isolate),
+ details.attributes());
descriptors->Set(enumeration_index - 1, &d);
- } else if (type == FIELD) {
+ } else if (type == DATA) {
if (current_offset < inobject_props) {
object->InObjectPropertyAtPut(current_offset, value,
UPDATE_WRITE_BARRIER);
@@ -4568,13 +4752,14 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
int offset = current_offset - inobject_props;
fields->set(offset, value);
}
- FieldDescriptor d(key, current_offset, details.attributes(),
- // TODO(verwaest): value->OptimalRepresentation();
- Representation::Tagged());
+ DataDescriptor d(key, current_offset, details.attributes(),
+ // TODO(verwaest): value->OptimalRepresentation();
+ Representation::Tagged());
current_offset += d.GetDetails().field_width_in_words();
descriptors->Set(enumeration_index - 1, &d);
- } else if (type == CALLBACKS) {
- CallbacksDescriptor d(key, handle(value, isolate), details.attributes());
+ } else if (type == ACCESSOR_CONSTANT) {
+ AccessorConstantDescriptor d(key, handle(value, isolate),
+ details.attributes());
descriptors->Set(enumeration_index - 1, &d);
} else {
UNREACHABLE();
@@ -4636,7 +4821,7 @@ static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
value = handle(Handle<FixedArray>::cast(array)->get(i), isolate);
}
if (!value->IsTheHole()) {
- PropertyDetails details(NONE, FIELD, 0);
+ PropertyDetails details(NONE, DATA, 0);
dictionary =
SeededNumberDictionary::AddNumberEntry(dictionary, i, value, details);
}
@@ -4905,7 +5090,7 @@ Object* JSObject::GetHiddenPropertiesHashTable() {
int sorted_index = descriptors->GetSortedKeyIndex(0);
if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
sorted_index < map()->NumberOfOwnDescriptors()) {
- DCHECK(descriptors->GetType(sorted_index) == FIELD);
+ DCHECK(descriptors->GetType(sorted_index) == DATA);
DCHECK(descriptors->GetDetails(sorted_index).representation().
IsCompatibleForLoad(Representation::Tagged()));
FieldIndex index = FieldIndex::ForDescriptor(this->map(),
@@ -5018,15 +5203,16 @@ MaybeHandle<Object> JSObject::DeleteElementWithInterceptor(
// Rebox CustomArguments::kReturnValueOffset before returning.
return handle(*result_internal, isolate);
}
- MaybeHandle<Object> delete_result = object->GetElementsAccessor()->Delete(
- object, index, NORMAL_DELETION);
+ // TODO(verwaest): Shouldn't this be the mode that was passed in?
+ MaybeHandle<Object> delete_result =
+ object->GetElementsAccessor()->Delete(object, index, SLOPPY);
return delete_result;
}
MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
uint32_t index,
- DeleteMode mode) {
+ LanguageMode language_mode) {
Isolate* isolate = object->GetIsolate();
Factory* factory = isolate->factory();
@@ -5039,12 +5225,13 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
}
if (object->IsStringObjectWithCharacterAt(index)) {
- if (mode == STRICT_DELETION) {
+ if (is_strict(language_mode)) {
// Deleting a non-configurable property in strict mode.
Handle<Object> name = factory->NewNumberFromUint(index);
- Handle<Object> args[2] = { name, object };
- THROW_NEW_ERROR(isolate, NewTypeError("strict_delete_property",
- HandleVector(args, 2)),
+ Handle<Object> args[] = {name, object};
+ THROW_NEW_ERROR(isolate,
+ NewTypeError("strict_delete_property",
+ HandleVector(args, arraysize(args))),
Object);
}
return factory->false_value();
@@ -5056,7 +5243,7 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
return DeleteElement(
Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index,
- mode);
+ language_mode);
}
Handle<Object> old_value;
@@ -5077,10 +5264,11 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
// Skip interceptor if forcing deletion.
MaybeHandle<Object> maybe_result;
- if (object->HasIndexedInterceptor() && mode != FORCE_DELETION) {
+ if (object->HasIndexedInterceptor()) {
maybe_result = DeleteElementWithInterceptor(object, index);
} else {
- maybe_result = object->GetElementsAccessor()->Delete(object, index, mode);
+ maybe_result =
+ object->GetElementsAccessor()->Delete(object, index, language_mode);
}
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, maybe_result, Object);
@@ -5100,23 +5288,44 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
}
+void JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
+ Handle<Name> name) {
+ DCHECK(!object->HasFastProperties());
+ Isolate* isolate = object->GetIsolate();
+ Handle<NameDictionary> dictionary(object->property_dictionary());
+ int entry = dictionary->FindEntry(name);
+ DCHECK_NE(NameDictionary::kNotFound, entry);
+
+ // If we have a global object set the cell to the hole.
+ if (object->IsGlobalObject()) {
+ PropertyDetails details = dictionary->DetailsAt(entry);
+ DCHECK(details.IsConfigurable());
+ Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
+ Handle<Object> value = isolate->factory()->the_hole_value();
+ PropertyCell::SetValueInferType(cell, value);
+ dictionary->DetailsAtPut(entry, details.AsDeleted());
+ return;
+ }
+
+ NameDictionary::DeleteProperty(dictionary, entry);
+ Handle<NameDictionary> new_properties =
+ NameDictionary::Shrink(dictionary, name);
+ object->set_properties(*new_properties);
+}
+
+
MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
Handle<Name> name,
- DeleteMode delete_mode) {
+ LanguageMode language_mode) {
// ECMA-262, 3rd, 8.6.2.5
DCHECK(name->IsName());
uint32_t index = 0;
if (name->AsArrayIndex(&index)) {
- return DeleteElement(object, index, delete_mode);
+ return DeleteElement(object, index, language_mode);
}
- // Skip interceptors on FORCE_DELETION.
- LookupIterator::Configuration config =
- delete_mode == FORCE_DELETION ? LookupIterator::HIDDEN_SKIP_INTERCEPTOR
- : LookupIterator::HIDDEN;
-
- LookupIterator it(object, name, config);
+ LookupIterator it(object, name, LookupIterator::HIDDEN);
bool is_observed = object->map()->is_observed() &&
!it.isolate()->IsInternallyUsedPropertyName(name);
@@ -5150,10 +5359,10 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
}
// Fall through.
case LookupIterator::ACCESSOR: {
- if (delete_mode != FORCE_DELETION && !it.IsConfigurable()) {
+ if (!it.IsConfigurable()) {
// Fail if the property is not configurable.
- if (delete_mode == STRICT_DELETION) {
- Handle<Object> args[2] = {name, object};
+ if (is_strict(language_mode)) {
+ Handle<Object> args[] = {name, object};
THROW_NEW_ERROR(it.isolate(),
NewTypeError("strict_delete_property",
HandleVector(args, arraysize(args))),
@@ -5172,9 +5381,9 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
!(object->IsJSGlobalProxy() && holder->IsJSGlobalObject())) {
return it.isolate()->factory()->true_value();
}
+
NormalizeProperties(holder, mode, 0, "DeletingProperty");
- Handle<Object> result =
- DeleteNormalizedProperty(holder, name, delete_mode);
+ DeleteNormalizedProperty(holder, name);
ReoptimizeIfPrototype(holder);
if (is_observed) {
@@ -5183,7 +5392,7 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
EnqueueChangeRecord(object, "delete", name, old_value), Object);
}
- return result;
+ return it.isolate()->factory()->true_value();
}
}
}
@@ -5194,23 +5403,25 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
MaybeHandle<Object> JSReceiver::DeleteElement(Handle<JSReceiver> object,
uint32_t index,
- DeleteMode mode) {
+ LanguageMode language_mode) {
if (object->IsJSProxy()) {
- return JSProxy::DeleteElementWithHandler(
- Handle<JSProxy>::cast(object), index, mode);
+ return JSProxy::DeleteElementWithHandler(Handle<JSProxy>::cast(object),
+ index, language_mode);
}
- return JSObject::DeleteElement(Handle<JSObject>::cast(object), index, mode);
+ return JSObject::DeleteElement(Handle<JSObject>::cast(object), index,
+ language_mode);
}
MaybeHandle<Object> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
Handle<Name> name,
- DeleteMode mode) {
+ LanguageMode language_mode) {
if (object->IsJSProxy()) {
- return JSProxy::DeletePropertyWithHandler(
- Handle<JSProxy>::cast(object), name, mode);
+ return JSProxy::DeletePropertyWithHandler(Handle<JSProxy>::cast(object),
+ name, language_mode);
}
- return JSObject::DeleteProperty(Handle<JSObject>::cast(object), name, mode);
+ return JSObject::DeleteProperty(Handle<JSObject>::cast(object), name,
+ language_mode);
}
@@ -5446,7 +5657,7 @@ static void ApplyAttributesToDictionary(Dictionary* dictionary,
PropertyDetails details = dictionary->DetailsAt(i);
int attrs = attributes;
// READ_ONLY is an invalid attribute for JS setters/getters.
- if ((attributes & READ_ONLY) && details.type() == CALLBACKS) {
+ if ((attributes & READ_ONLY) && details.type() == ACCESSOR_CONSTANT) {
Object* v = dictionary->ValueAt(i);
if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
@@ -5686,7 +5897,7 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
int limit = copy->map()->NumberOfOwnDescriptors();
for (int i = 0; i < limit; i++) {
PropertyDetails details = descriptors->GetDetails(i);
- if (details.type() != FIELD) continue;
+ if (details.type() != DATA) continue;
FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
if (object->IsUnboxedDoubleField(index)) {
if (copying) {
@@ -5911,7 +6122,7 @@ int Map::NextFreePropertyIndex() {
DescriptorArray* descs = instance_descriptors();
for (int i = 0; i < number_of_own_descriptors; i++) {
PropertyDetails details = descs->GetDetails(i);
- if (details.type() == FIELD) {
+ if (details.location() == kField) {
int candidate = details.field_index() + details.field_width_in_words();
if (candidate > free_index) free_index = candidate;
}
@@ -6002,7 +6213,7 @@ static Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
if (!(details.IsDontEnum() || key->IsSymbol())) {
storage->set(index, key);
if (!indices.is_null()) {
- if (details.type() != FIELD) {
+ if (details.type() != DATA) {
indices = Handle<FixedArray>();
} else {
FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
@@ -6165,12 +6376,11 @@ static bool UpdateGetterSetterInDictionary(
if (entry != SeededNumberDictionary::kNotFound) {
Object* result = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() == CALLBACKS && result->IsAccessorPair()) {
+ if (details.type() == ACCESSOR_CONSTANT && result->IsAccessorPair()) {
DCHECK(details.IsConfigurable());
if (details.attributes() != attributes) {
dictionary->DetailsAtPut(
- entry,
- PropertyDetails(attributes, CALLBACKS, index));
+ entry, PropertyDetails(attributes, ACCESSOR_CONSTANT, index));
}
AccessorPair::cast(result)->SetComponents(getter, setter);
return true;
@@ -6272,14 +6482,14 @@ void JSObject::SetElementCallback(Handle<JSObject> object,
Handle<Object> structure,
PropertyAttributes attributes) {
Heap* heap = object->GetHeap();
- PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
+ PropertyDetails details = PropertyDetails(attributes, ACCESSOR_CONSTANT, 0);
// Normalize elements to make this operation simple.
bool had_dictionary_elements = object->HasDictionaryElements();
Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
DCHECK(object->HasDictionaryElements() ||
object->HasDictionaryArgumentsElements());
- // Update the dictionary with the new CALLBACKS property.
+ // Update the dictionary with the new ACCESSOR_CONSTANT property.
dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
details);
dictionary->set_requires_slow_elements();
@@ -6337,8 +6547,8 @@ void JSObject::SetPropertyCallback(Handle<JSObject> object,
Deoptimizer::DeoptimizeGlobalObject(*object);
}
- // Update the dictionary with the new CALLBACKS property.
- PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
+ // Update the dictionary with the new ACCESSOR_CONSTANT property.
+ PropertyDetails details = PropertyDetails(attributes, ACCESSOR_CONSTANT, 0);
SetNormalizedProperty(object, name, structure, details);
ReoptimizeIfPrototype(object);
@@ -6552,7 +6762,7 @@ MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
int entry = dictionary->FindEntry(index);
if (entry != SeededNumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
- if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
+ if (dictionary->DetailsAt(entry).type() == ACCESSOR_CONSTANT &&
element->IsAccessorPair()) {
return handle(AccessorPair::cast(element)->GetComponent(component),
isolate);
@@ -6603,7 +6813,7 @@ Object* JSObject::SlowReverseLookup(Object* value) {
DescriptorArray* descs = map()->instance_descriptors();
bool value_is_number = value->IsNumber();
for (int i = 0; i < number_of_own_descriptors; i++) {
- if (descs->GetType(i) == FIELD) {
+ if (descs->GetType(i) == DATA) {
FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
if (IsUnboxedDoubleField(field_index)) {
if (value_is_number) {
@@ -6623,7 +6833,7 @@ Object* JSObject::SlowReverseLookup(Object* value) {
return descs->GetKey(i);
}
}
- } else if (descs->GetType(i) == CONSTANT) {
+ } else if (descs->GetType(i) == DATA_CONSTANT) {
if (descs->GetConstant(i) == value) {
return descs->GetKey(i);
}
@@ -6776,7 +6986,7 @@ Handle<Map> Map::ShareDescriptor(Handle<Map> map,
Handle<LayoutDescriptor> layout_descriptor =
FLAG_unbox_double_fields
- ? LayoutDescriptor::Append(map, descriptor->GetDetails())
+ ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
: handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
{
@@ -6868,7 +7078,7 @@ Handle<Map> Map::CopyReplaceDescriptors(
int length = descriptors->number_of_descriptors();
for (int i = 0; i < length; i++) {
descriptors->SetRepresentation(i, Representation::Tagged());
- if (descriptors->GetDetails(i).type() == FIELD) {
+ if (descriptors->GetDetails(i).type() == DATA) {
descriptors->SetValue(i, HeapType::Any());
}
}
@@ -6907,7 +7117,7 @@ Handle<Map> Map::CopyInstallDescriptors(
int unused_property_fields = map->unused_property_fields();
PropertyDetails details = descriptors->GetDetails(new_descriptor);
- if (details.type() == FIELD) {
+ if (details.location() == kField) {
unused_property_fields = map->unused_property_fields() - 1;
if (unused_property_fields < 0) {
unused_property_fields += JSObject::kFieldsAdded;
@@ -6920,7 +7130,14 @@ Handle<Map> Map::CopyInstallDescriptors(
LayoutDescriptor::AppendIfFastOrUseFull(map, details,
full_layout_descriptor);
result->set_layout_descriptor(*layout_descriptor);
+#ifdef VERIFY_HEAP
+ // TODO(ishell): remove these checks from VERIFY_HEAP mode.
+ if (FLAG_verify_heap) {
+ CHECK(result->layout_descriptor()->IsConsistentWithMap(*result));
+ }
+#else
SLOW_DCHECK(result->layout_descriptor()->IsConsistentWithMap(*result));
+#endif
result->set_visitor_id(StaticVisitorBase::GetVisitorId(*result));
}
@@ -6950,31 +7167,18 @@ Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
map->CanHaveMoreTransitions() &&
!map->HasElementsTransition();
- if (insert_transition && map->owns_descriptors()) {
- // In case the map owned its own descriptors, share the descriptors and
- // transfer ownership to the new map.
- Handle<Map> new_map = CopyDropDescriptors(map);
+ if (insert_transition) {
+ Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
+ new_map->set_elements_kind(kind);
ConnectElementsTransition(map, new_map);
- new_map->set_elements_kind(kind);
- // The properties did not change, so reuse descriptors.
- new_map->InitializeDescriptors(map->instance_descriptors(),
- map->GetLayoutDescriptor());
return new_map;
}
- // In case the map did not own its own descriptors, a split is forced by
- // copying the map; creating a new descriptor array cell.
// Create a new free-floating map only if we are not allowed to store it.
Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
-
new_map->set_elements_kind(kind);
-
- if (insert_transition) {
- ConnectElementsTransition(map, new_map);
- }
-
return new_map;
}
@@ -6984,27 +7188,55 @@ Handle<Map> Map::CopyForObserved(Handle<Map> map) {
Isolate* isolate = map->GetIsolate();
- // In case the map owned its own descriptors, share the descriptors and
- // transfer ownership to the new map.
- Handle<Map> new_map;
- if (map->owns_descriptors()) {
- new_map = CopyDropDescriptors(map);
- } else {
- DCHECK(!map->is_prototype_map());
- new_map = Copy(map, "CopyForObserved");
+ bool insert_transition =
+ map->CanHaveMoreTransitions() && !map->is_prototype_map();
+
+ if (insert_transition) {
+ Handle<Map> new_map = CopyForTransition(map, "CopyForObserved");
+ new_map->set_is_observed();
+
+ Handle<Name> name = isolate->factory()->observed_symbol();
+ ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
+ return new_map;
}
+ // Create a new free-floating map only if we are not allowed to store it.
+ Handle<Map> new_map = Map::Copy(map, "CopyForObserved");
new_map->set_is_observed();
+ return new_map;
+}
+
+
+Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
+ DCHECK(!map->is_prototype_map());
+ Handle<Map> new_map = CopyDropDescriptors(map);
+
if (map->owns_descriptors()) {
+ // In case the map owned its own descriptors, share the descriptors and
+ // transfer ownership to the new map.
// The properties did not change, so reuse descriptors.
new_map->InitializeDescriptors(map->instance_descriptors(),
map->GetLayoutDescriptor());
+ } else {
+ // In case the map did not own its own descriptors, a split is forced by
+ // copying the map; creating a new descriptor array cell.
+ Handle<DescriptorArray> descriptors(map->instance_descriptors());
+ int number_of_own_descriptors = map->NumberOfOwnDescriptors();
+ Handle<DescriptorArray> new_descriptors =
+ DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
+ Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
+ map->GetIsolate());
+ new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
}
- if (map->CanHaveMoreTransitions()) {
- Handle<Name> name = isolate->factory()->observed_symbol();
- ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
+#if TRACE_MAPS
+ if (FLAG_trace_maps) {
+ PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
+ reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
+ reason);
}
+#endif
+
return new_map;
}
@@ -7071,17 +7303,17 @@ Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
bool DescriptorArray::CanHoldValue(int descriptor, Object* value) {
PropertyDetails details = GetDetails(descriptor);
switch (details.type()) {
- case FIELD:
+ case DATA:
return value->FitsRepresentation(details.representation()) &&
GetFieldType(descriptor)->NowContains(value);
- case CONSTANT:
+ case DATA_CONSTANT:
DCHECK(GetConstant(descriptor) != value ||
value->FitsRepresentation(details.representation()));
return GetConstant(descriptor) == value;
- case ACCESSOR_FIELD:
- case CALLBACKS:
+ case ACCESSOR:
+ case ACCESSOR_CONSTANT:
return false;
}
@@ -7103,11 +7335,13 @@ Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
if (descriptors->CanHoldValue(descriptor, *value)) return map;
Isolate* isolate = map->GetIsolate();
+ PropertyAttributes attributes =
+ descriptors->GetDetails(descriptor).attributes();
Representation representation = value->OptimalRepresentation();
Handle<HeapType> type = value->OptimalType(isolate, representation);
- return GeneralizeRepresentation(map, descriptor, representation, type,
- FORCE_IN_OBJECT);
+ return ReconfigureProperty(map, descriptor, kData, attributes, representation,
+ type, FORCE_FIELD);
}
@@ -7121,7 +7355,7 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
// Migrate to the newest map before storing the property.
map = Update(map);
- int index = map->SearchTransition(DATA, *name, attributes);
+ int index = map->SearchTransition(kData, *name, attributes);
if (index != TransitionArray::kNotFound) {
Handle<Map> transition(map->GetTransition(index));
int descriptor = transition->LastAdded();
@@ -7164,16 +7398,29 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
}
-Handle<Map> Map::ReconfigureDataProperty(Handle<Map> map, int descriptor,
- PropertyAttributes attributes) {
+Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
+ PropertyKind kind,
+ PropertyAttributes attributes) {
// Dictionaries have to be reconfigured in-place.
DCHECK(!map->is_dictionary_map());
- // For now, give up on transitioning and just create a unique map.
- // TODO(verwaest/ishell): Cache transitions with different attributes.
- return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_IN_OBJECT,
- attributes,
- "GenAll_AttributesMismatch");
+ if (!map->GetBackPointer()->IsMap()) {
+ // There is no benefit from reconstructing transition tree for maps without
+ // back pointers.
+ return CopyGeneralizeAllRepresentations(
+ map, descriptor, FORCE_FIELD, kind, attributes,
+ "GenAll_AttributesMismatchProtoMap");
+ }
+
+ if (FLAG_trace_generalization) {
+ map->PrintReconfiguration(stdout, descriptor, kind, attributes);
+ }
+
+ Isolate* isolate = map->GetIsolate();
+ Handle<Map> new_map = ReconfigureProperty(
+ map, descriptor, kind, attributes, Representation::None(),
+ HeapType::None(isolate), FORCE_FIELD);
+ return new_map;
}
@@ -7199,14 +7446,14 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
? KEEP_INOBJECT_PROPERTIES
: CLEAR_INOBJECT_PROPERTIES;
- int index = map->SearchTransition(ACCESSOR, *name, attributes);
+ int index = map->SearchTransition(kAccessor, *name, attributes);
if (index != TransitionArray::kNotFound) {
Handle<Map> transition(map->GetTransition(index));
DescriptorArray* descriptors = transition->instance_descriptors();
int descriptor = transition->LastAdded();
DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
- DCHECK_EQ(ACCESSOR, descriptors->GetDetails(descriptor).kind());
+ DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
@@ -7230,7 +7477,7 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
}
PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
- if (old_details.type() != CALLBACKS) {
+ if (old_details.type() != ACCESSOR_CONSTANT) {
return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
}
@@ -7260,7 +7507,7 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
pair->set(component, *accessor);
TransitionFlag flag = INSERT_TRANSITION;
- CallbacksDescriptor new_desc(name, pair, attributes);
+ AccessorConstantDescriptor new_desc(name, pair, attributes);
return Map::CopyInsertDescriptor(map, &new_desc, flag);
}
@@ -7279,13 +7526,14 @@ Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
return ShareDescriptor(map, descriptors, descriptor);
}
- Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
- descriptors, map->NumberOfOwnDescriptors(), 1);
+ int nof = map->NumberOfOwnDescriptors();
+ Handle<DescriptorArray> new_descriptors =
+ DescriptorArray::CopyUpTo(descriptors, nof, 1);
new_descriptors->Append(descriptor);
Handle<LayoutDescriptor> new_layout_descriptor =
FLAG_unbox_double_fields
- ? LayoutDescriptor::Append(map, descriptor->GetDetails())
+ ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
: handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
@@ -7344,7 +7592,7 @@ Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
if (!key->IsSymbol() || !Symbol::cast(key)->is_private()) {
int mask = DONT_DELETE | DONT_ENUM;
// READ_ONLY is an invalid attribute for JS setters/getters.
- if (details.type() != CALLBACKS || !value->IsAccessorPair()) {
+ if (details.type() != ACCESSOR_CONSTANT || !value->IsAccessorPair()) {
mask |= READ_ONLY;
}
details = details.CopyAddAttributes(
@@ -7534,13 +7782,8 @@ class IntrusivePrototypeTransitionIterator {
Map* GetTransition(int transitionNumber) {
FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
- return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
- }
-
- int IndexFor(int transitionNumber) {
- return Map::kProtoTransitionHeaderSize +
- Map::kProtoTransitionMapOffset +
- transitionNumber * Map::kProtoTransitionElementsPerEntry;
+ int index = Map::kProtoTransitionHeaderSize + transitionNumber;
+ return Map::cast(proto_trans->get(index));
}
Map* map_;
@@ -8391,7 +8634,6 @@ Object* AccessorPair::GetComponent(AccessorComponent component) {
Handle<DeoptimizationInputData> DeoptimizationInputData::New(
Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
- DCHECK(deopt_entry_count > 0);
return Handle<DeoptimizationInputData>::cast(
isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
pretenure));
@@ -8928,20 +9170,18 @@ static void CalculateLineEndsImpl(Isolate* isolate,
Vector<const SourceChar> src,
bool include_ending_line) {
const int src_len = src.length();
- StringSearch<uint8_t, SourceChar> search(isolate, STATIC_CHAR_VECTOR("\n"));
-
- // Find and record line ends.
- int position = 0;
- while (position != -1 && position < src_len) {
- position = search.Search(src, position);
- if (position != -1) {
- line_ends->Add(position);
- position++;
- } else if (include_ending_line) {
- // Even if the last line misses a line end, it is counted.
- line_ends->Add(src_len);
- return;
- }
+ UnicodeCache* cache = isolate->unicode_cache();
+ for (int i = 0; i < src_len - 1; i++) {
+ SourceChar current = src[i];
+ SourceChar next = src[i + 1];
+ if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
+ }
+
+ if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
+ line_ends->Add(src_len - 1);
+ } else if (include_ending_line) {
+ // Even if the last line misses a line end, it is counted.
+ line_ends->Add(src_len);
}
}
@@ -9222,23 +9462,6 @@ bool String::SlowEquals(Handle<String> one, Handle<String> two) {
}
-bool String::MarkAsUndetectable() {
- if (StringShape(this).IsInternalized()) return false;
-
- Map* map = this->map();
- Heap* heap = GetHeap();
- if (map == heap->string_map()) {
- this->set_map(heap->undetectable_string_map());
- return true;
- } else if (map == heap->one_byte_string_map()) {
- this->set_map(heap->undetectable_one_byte_string_map());
- return true;
- }
- // Rest cannot be marked as undetectable
- return false;
-}
-
-
bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
int slen = length();
// Can't check exact length equality, but we can check bounds.
@@ -9249,10 +9472,10 @@ bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
return false;
}
int i;
- unsigned remaining_in_str = static_cast<unsigned>(str_len);
+ size_t remaining_in_str = static_cast<size_t>(str_len);
const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
for (i = 0; i < slen && remaining_in_str > 0; i++) {
- unsigned cursor = 0;
+ size_t cursor = 0;
uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
DCHECK(cursor > 0 && cursor <= remaining_in_str);
if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
@@ -9426,13 +9649,13 @@ uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
// Start with a fake length which won't affect computation.
// It will be updated later.
StringHasher hasher(String::kMaxArrayIndexSize, seed);
- unsigned remaining = static_cast<unsigned>(vector_length);
+ size_t remaining = static_cast<size_t>(vector_length);
const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
int utf16_length = 0;
bool is_index = true;
DCHECK(hasher.is_array_index_);
while (remaining > 0) {
- unsigned consumed = 0;
+ size_t consumed = 0;
uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
DCHECK(consumed > 0 && consumed <= remaining);
stream += consumed;
@@ -9522,13 +9745,13 @@ int Map::Hash() {
static bool CheckEquivalent(Map* first, Map* second) {
- return
- first->constructor() == second->constructor() &&
- first->prototype() == second->prototype() &&
- first->instance_type() == second->instance_type() &&
- first->bit_field() == second->bit_field() &&
- first->bit_field2() == second->bit_field2() &&
- first->has_instance_call_handler() == second->has_instance_call_handler();
+ return first->constructor() == second->constructor() &&
+ first->prototype() == second->prototype() &&
+ first->instance_type() == second->instance_type() &&
+ first->bit_field() == second->bit_field() &&
+ first->is_extensible() == second->is_extensible() &&
+ first->has_instance_call_handler() ==
+ second->has_instance_call_handler();
}
@@ -9541,7 +9764,8 @@ bool Map::EquivalentToForNormalization(Map* other,
PropertyNormalizationMode mode) {
int properties = mode == CLEAR_INOBJECT_PROPERTIES
? 0 : other->inobject_properties();
- return CheckEquivalent(this, other) && inobject_properties() == properties;
+ return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
+ inobject_properties() == properties;
}
@@ -9601,9 +9825,7 @@ void JSFunction::MarkForOptimization() {
Isolate* isolate = GetIsolate();
DCHECK(isolate->use_crankshaft());
DCHECK(!IsOptimized());
- DCHECK(shared()->allows_lazy_compilation() ||
- code()->optimizable());
- DCHECK(!shared()->is_generator());
+ DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
set_code_no_write_barrier(
isolate->builtins()->builtin(Builtins::kCompileOptimized));
// No write barrier required, since the builtin is part of the root set.
@@ -9627,10 +9849,9 @@ void JSFunction::AttemptConcurrentOptimization() {
}
DCHECK(isolate->use_crankshaft());
DCHECK(!IsInOptimizationQueue());
- DCHECK(is_compiled() || isolate->DebuggerHasBreakPoints());
+ DCHECK(is_compiled() || isolate->debug()->has_break_points());
DCHECK(!IsOptimized());
DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
- DCHECK(!shared()->is_generator());
DCHECK(isolate->concurrent_recompilation_enabled());
if (FLAG_trace_concurrent_recompilation) {
PrintF(" ** Marking ");
@@ -9724,7 +9945,7 @@ FixedArray* SharedFunctionInfo::GetLiteralsFromOptimizedCodeMap(int index) {
FixedArray* code_map = FixedArray::cast(optimized_code_map());
if (!bound()) {
FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
- DCHECK_NE(NULL, cached_literals);
+ DCHECK_NOT_NULL(cached_literals);
return cached_literals;
}
return NULL;
@@ -9735,7 +9956,7 @@ Code* SharedFunctionInfo::GetCodeFromOptimizedCodeMap(int index) {
DCHECK(index > kEntriesStart);
FixedArray* code_map = FixedArray::cast(optimized_code_map());
Code* code = Code::cast(code_map->get(index));
- DCHECK_NE(NULL, code);
+ DCHECK_NOT_NULL(code);
return code;
}
@@ -9817,7 +10038,7 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
if (object->IsGlobalObject()) return;
if (object->IsJSGlobalProxy()) return;
if (mode == FAST_PROTOTYPE && !object->map()->is_prototype_map()) {
- // First normalize to ensure all JSFunctions are CONSTANT.
+ // First normalize to ensure all JSFunctions are DATA_CONSTANT.
JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
"NormalizeAsPrototype");
}
@@ -9832,6 +10053,19 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
JSObject::MigrateToMap(object, new_map);
}
+ if (object->map()->constructor()->IsJSFunction()) {
+ JSFunction* constructor = JSFunction::cast(object->map()->constructor());
+ // Replace the pointer to the exact constructor with the Object function
+ // from the same context if undetectable from JS. This is to avoid keeping
+ // memory alive unnecessarily.
+ if (!constructor->shared()->IsApiFunction() &&
+ object->class_name() ==
+ object->GetIsolate()->heap()->Object_string()) {
+ Context* context = constructor->context()->native_context();
+ JSFunction* object_function = context->object_function();
+ object->map()->set_constructor(object_function);
+ }
+ }
object->map()->set_is_prototype_map(true);
}
}
@@ -10027,16 +10261,17 @@ void JSFunction::SetPrototype(Handle<JSFunction> function,
bool JSFunction::RemovePrototype() {
Context* native_context = context()->native_context();
- Map* no_prototype_map = shared()->strict_mode() == SLOPPY
- ? native_context->sloppy_function_without_prototype_map()
- : native_context->strict_function_without_prototype_map();
+ Map* no_prototype_map =
+ is_strict(shared()->language_mode())
+ ? native_context->strict_function_without_prototype_map()
+ : native_context->sloppy_function_without_prototype_map();
if (map() == no_prototype_map) return true;
#ifdef DEBUG
- if (map() != (shared()->strict_mode() == SLOPPY
- ? native_context->sloppy_function_map()
- : native_context->strict_function_map())) {
+ if (map() != (is_strict(shared()->language_mode())
+ ? native_context->strict_function_map()
+ : native_context->sloppy_function_map())) {
return false;
}
#endif
@@ -10451,6 +10686,40 @@ void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
}
+void SharedFunctionInfo::InitFromFunctionLiteral(
+ Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
+ shared_info->set_length(lit->scope()->default_function_length());
+ if (IsSubclassConstructor(lit->kind())) {
+ shared_info->set_internal_formal_parameter_count(lit->parameter_count() +
+ 1);
+ } else {
+ shared_info->set_internal_formal_parameter_count(lit->parameter_count());
+ }
+ shared_info->set_function_token_position(lit->function_token_position());
+ shared_info->set_start_position(lit->start_position());
+ shared_info->set_end_position(lit->end_position());
+ shared_info->set_is_expression(lit->is_expression());
+ shared_info->set_is_anonymous(lit->is_anonymous());
+ shared_info->set_inferred_name(*lit->inferred_name());
+ shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
+ shared_info->set_allows_lazy_compilation_without_context(
+ lit->AllowsLazyCompilationWithoutContext());
+ shared_info->set_language_mode(lit->language_mode());
+ shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
+ shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
+ shared_info->set_ast_node_count(lit->ast_node_count());
+ shared_info->set_is_function(lit->is_function());
+ if (lit->dont_optimize_reason() != kNoReason) {
+ shared_info->DisableOptimization(lit->dont_optimize_reason());
+ }
+ shared_info->set_dont_cache(
+ lit->flags()->Contains(AstPropertiesFlag::kDontCache));
+ shared_info->set_kind(lit->kind());
+ shared_info->set_uses_super_property(lit->uses_super_property());
+ shared_info->set_asm_function(lit->scope()->asm_function());
+}
+
+
bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
DCHECK(!id.IsNone());
Code* unoptimized = code();
@@ -10966,6 +11235,13 @@ void Code::ClearInlineCaches(Code::Kind* kind) {
void SharedFunctionInfo::ClearTypeFeedbackInfo() {
feedback_vector()->ClearSlots(this);
+ feedback_vector()->ClearICSlots(this);
+}
+
+
+void SharedFunctionInfo::ClearTypeFeedbackInfoAtGCTime() {
+ feedback_vector()->ClearSlots(this);
+ feedback_vector()->ClearICSlotsAtGCTime(this);
}
@@ -11136,25 +11412,10 @@ Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
void Code::PrintDeoptLocation(FILE* out, int bailout_id) {
- const char* last_comment = NULL;
- int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
- | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- if (info->rmode() == RelocInfo::COMMENT) {
- last_comment = reinterpret_cast<const char*>(info->data());
- } else if (last_comment != NULL) {
- if ((bailout_id == Deoptimizer::GetDeoptimizationId(
- GetIsolate(), info->target_address(), Deoptimizer::EAGER)) ||
- (bailout_id == Deoptimizer::GetDeoptimizationId(
- GetIsolate(), info->target_address(), Deoptimizer::SOFT)) ||
- (bailout_id == Deoptimizer::GetDeoptimizationId(
- GetIsolate(), info->target_address(), Deoptimizer::LAZY))) {
- CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
- PrintF(out, " %s\n", last_comment);
- return;
- }
- }
+ Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, bailout_id);
+ if (info.deopt_reason != Deoptimizer::kNoReason || info.raw_position != 0) {
+ PrintF(out, " ;;; deoptimize at %d: %s\n", info.raw_position,
+ Deoptimizer::GetDeoptReason(info.deopt_reason));
}
}
@@ -11185,6 +11446,29 @@ const char* Code::Kind2String(Kind kind) {
}
+Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
+ DCHECK(code->kind() == OPTIMIZED_FUNCTION);
+ WeakCell* raw_cell = code->CachedWeakCell();
+ if (raw_cell != NULL) return Handle<WeakCell>(raw_cell);
+ Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
+ DeoptimizationInputData::cast(code->deoptimization_data())
+ ->SetWeakCellCache(*cell);
+ return cell;
+}
+
+
+WeakCell* Code::CachedWeakCell() {
+ DCHECK(kind() == OPTIMIZED_FUNCTION);
+ Object* weak_cell_cache =
+ DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache();
+ if (weak_cell_cache->IsWeakCell()) {
+ DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
+ return WeakCell::cast(weak_cell_cache);
+ }
+ return NULL;
+}
+
+
#ifdef ENABLE_DISASSEMBLER
void DeoptimizationInputData::DeoptimizationInputDataPrint(
@@ -11400,7 +11684,8 @@ const char* Code::StubType2String(StubType type) {
void Code::PrintExtraICState(std::ostream& os, // NOLINT
Kind kind, ExtraICState extra) {
os << "extra_ic_state = ";
- if ((kind == STORE_IC || kind == KEYED_STORE_IC) && (extra == STRICT)) {
+ if ((kind == STORE_IC || kind == KEYED_STORE_IC) &&
+ is_strict(static_cast<LanguageMode>(extra))) {
os << "STRICT\n";
} else {
os << extra << "\n";
@@ -11813,9 +12098,12 @@ MaybeHandle<Object> JSArray::SetElementsLength(
SLOPPY).Assert();
}
- SetProperty(deleted, isolate->factory()->length_string(),
- isolate->factory()->NewNumberFromUint(delete_count),
- STRICT).Assert();
+ RETURN_ON_EXCEPTION(
+ isolate,
+ SetProperty(deleted, isolate->factory()->length_string(),
+ isolate->factory()->NewNumberFromUint(delete_count),
+ STRICT),
+ Object);
}
RETURN_ON_EXCEPTION(
@@ -11827,17 +12115,12 @@ MaybeHandle<Object> JSArray::SetElementsLength(
Handle<Map> Map::GetPrototypeTransition(Handle<Map> map,
Handle<Object> prototype) {
+ DisallowHeapAllocation no_gc;
FixedArray* cache = map->GetPrototypeTransitions();
int number_of_transitions = map->NumberOfProtoTransitions();
- const int proto_offset =
- kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
- const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
- const int step = kProtoTransitionElementsPerEntry;
for (int i = 0; i < number_of_transitions; i++) {
- if (cache->get(proto_offset + i * step) == *prototype) {
- Object* result = cache->get(map_offset + i * step);
- return Handle<Map>(Map::cast(result));
- }
+ Map* map = Map::cast(cache->get(kProtoTransitionHeaderSize + i));
+ if (map->prototype() == *prototype) return handle(map);
}
return Handle<Map>();
}
@@ -11853,28 +12136,27 @@ Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
if (map->is_prototype_map()) return map;
if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map;
- const int step = kProtoTransitionElementsPerEntry;
const int header = kProtoTransitionHeaderSize;
Handle<FixedArray> cache(map->GetPrototypeTransitions());
- int capacity = (cache->length() - header) / step;
+ int capacity = cache->length() - header;
int transitions = map->NumberOfProtoTransitions() + 1;
if (transitions > capacity) {
- if (capacity > kMaxCachedPrototypeTransitions) return map;
+ // Grow array by factor 2 up to MaxCachedPrototypeTransitions.
+ int new_capacity = Min(kMaxCachedPrototypeTransitions, transitions * 2);
+ if (new_capacity == capacity) return map;
- // Grow array by factor 2 over and above what we need.
- cache = FixedArray::CopySize(cache, transitions * 2 * step + header);
+ cache = FixedArray::CopySize(cache, header + new_capacity);
SetPrototypeTransitions(map, cache);
}
// Reload number of transitions as GC might shrink them.
int last = map->NumberOfProtoTransitions();
- int entry = header + last * step;
+ int entry = header + last;
- cache->set(entry + kProtoTransitionPrototypeOffset, *prototype);
- cache->set(entry + kProtoTransitionMapOffset, *target_map);
+ cache->set(entry, *target_map);
map->SetNumberOfProtoTransitions(last + 1);
return map;
@@ -11906,9 +12188,9 @@ void Map::ZapPrototypeTransitions() {
void Map::AddDependentCompilationInfo(Handle<Map> map,
DependentCode::DependencyGroup group,
CompilationInfo* info) {
- Handle<DependentCode> codes =
- DependentCode::Insert(handle(map->dependent_code(), info->isolate()),
- group, info->object_wrapper());
+ Handle<DependentCode> codes = DependentCode::InsertCompilationInfo(
+ handle(map->dependent_code(), info->isolate()), group,
+ info->object_wrapper());
if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
info->dependencies(group)->Add(map, info->zone());
}
@@ -11918,8 +12200,9 @@ void Map::AddDependentCompilationInfo(Handle<Map> map,
void Map::AddDependentCode(Handle<Map> map,
DependentCode::DependencyGroup group,
Handle<Code> code) {
- Handle<DependentCode> codes = DependentCode::Insert(
- Handle<DependentCode>(map->dependent_code()), group, code);
+ Handle<WeakCell> cell = Code::WeakCellFor(code);
+ Handle<DependentCode> codes = DependentCode::InsertWeakCode(
+ Handle<DependentCode>(map->dependent_code()), group, cell);
if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
}
@@ -11951,6 +12234,20 @@ DependentCode* DependentCode::ForObject(Handle<HeapObject> object,
}
+Handle<DependentCode> DependentCode::InsertCompilationInfo(
+ Handle<DependentCode> entries, DependencyGroup group,
+ Handle<Foreign> info) {
+ return Insert(entries, group, info);
+}
+
+
+Handle<DependentCode> DependentCode::InsertWeakCode(
+ Handle<DependentCode> entries, DependencyGroup group,
+ Handle<WeakCell> code_cell) {
+ return Insert(entries, group, code_cell);
+}
+
+
Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
DependencyGroup group,
Handle<Object> object) {
@@ -11963,27 +12260,13 @@ Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
if (entries->object_at(i) == *object) return entries;
}
if (entries->length() < kCodesStartIndex + number_of_entries + 1) {
- int capacity = kCodesStartIndex + number_of_entries + 1;
- if (capacity > 5) capacity = capacity * 5 / 4;
- Handle<DependentCode> new_entries = Handle<DependentCode>::cast(
- FixedArray::CopySize(entries, capacity, TENURED));
- // The number of codes can change after GC.
+ entries = EnsureSpace(entries);
+ // The number of codes can change after Compact and GC.
starts.Recompute(*entries);
start = starts.at(group);
end = starts.at(group + 1);
- number_of_entries = starts.number_of_entries();
- for (int i = 0; i < number_of_entries; i++) {
- entries->clear_at(i);
- }
- // If the old fixed array was empty, we need to reset counters of the
- // new array.
- if (number_of_entries == 0) {
- for (int g = 0; g < kGroupCount; g++) {
- new_entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
- }
- }
- entries = new_entries;
}
+
entries->ExtendGroup(group);
entries->set_object_at(end, *object);
entries->set_number_of_entries(group, end + 1 - start);
@@ -11991,42 +12274,82 @@ Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
}
-void DependentCode::UpdateToFinishedCode(DependencyGroup group,
- CompilationInfo* info,
- Code* code) {
+Handle<DependentCode> DependentCode::EnsureSpace(
+ Handle<DependentCode> entries) {
+ if (entries->length() == 0) {
+ entries = Handle<DependentCode>::cast(
+ FixedArray::CopySize(entries, kCodesStartIndex + 1, TENURED));
+ for (int g = 0; g < kGroupCount; g++) {
+ entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
+ }
+ return entries;
+ }
+ if (entries->Compact()) return entries;
+ GroupStartIndexes starts(*entries);
+ int capacity =
+ kCodesStartIndex + DependentCode::Grow(starts.number_of_entries());
+ return Handle<DependentCode>::cast(
+ FixedArray::CopySize(entries, capacity, TENURED));
+}
+
+
+bool DependentCode::Compact() {
+ GroupStartIndexes starts(this);
+ int n = 0;
+ for (int g = 0; g < kGroupCount; g++) {
+ int start = starts.at(g);
+ int end = starts.at(g + 1);
+ int count = 0;
+ DCHECK(start >= n);
+ for (int i = start; i < end; i++) {
+ Object* obj = object_at(i);
+ if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
+ if (i != n + count) {
+ copy(i, n + count);
+ }
+ count++;
+ }
+ }
+ if (count != end - start) {
+ set_number_of_entries(static_cast<DependencyGroup>(g), count);
+ }
+ n += count;
+ }
+ return n < starts.number_of_entries();
+}
+
+
+void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
+ WeakCell* code_cell) {
DisallowHeapAllocation no_gc;
- AllowDeferredHandleDereference get_object_wrapper;
- Foreign* info_wrapper = *info->object_wrapper();
GroupStartIndexes starts(this);
int start = starts.at(group);
int end = starts.at(group + 1);
for (int i = start; i < end; i++) {
- if (object_at(i) == info_wrapper) {
- set_object_at(i, code);
+ if (object_at(i) == info) {
+ set_object_at(i, code_cell);
break;
}
}
#ifdef DEBUG
for (int i = start; i < end; i++) {
- DCHECK(is_code_at(i) || compilation_info_at(i) != info);
+ DCHECK(object_at(i) != info);
}
#endif
}
void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group,
- CompilationInfo* info) {
+ Foreign* info) {
DisallowHeapAllocation no_allocation;
- AllowDeferredHandleDereference get_object_wrapper;
- Foreign* info_wrapper = *info->object_wrapper();
GroupStartIndexes starts(this);
int start = starts.at(group);
int end = starts.at(group + 1);
// Find compilation info wrapper.
int info_pos = -1;
for (int i = start; i < end; i++) {
- if (object_at(i) == info_wrapper) {
+ if (object_at(i) == info) {
info_pos = i;
break;
}
@@ -12047,18 +12370,18 @@ void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group,
#ifdef DEBUG
for (int i = start; i < end - 1; i++) {
- DCHECK(is_code_at(i) || compilation_info_at(i) != info);
+ DCHECK(object_at(i) != info);
}
#endif
}
-bool DependentCode::Contains(DependencyGroup group, Code* code) {
+bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
GroupStartIndexes starts(this);
int start = starts.at(group);
int end = starts.at(group + 1);
for (int i = start; i < end; i++) {
- if (object_at(i) == code) return true;
+ if (object_at(i) == code_cell) return true;
}
return false;
}
@@ -12076,15 +12399,24 @@ bool DependentCode::MarkCodeForDeoptimization(
// Mark all the code that needs to be deoptimized.
bool marked = false;
+ bool invalidate_embedded_objects = group == kWeakCodeGroup;
for (int i = start; i < end; i++) {
- if (is_code_at(i)) {
- Code* code = code_at(i);
+ Object* obj = object_at(i);
+ if (obj->IsWeakCell()) {
+ WeakCell* cell = WeakCell::cast(obj);
+ if (cell->cleared()) continue;
+ Code* code = Code::cast(cell->value());
if (!code->marked_for_deoptimization()) {
SetMarkedForDeoptimization(code, group);
+ if (invalidate_embedded_objects) {
+ code->InvalidateEmbeddedObjects();
+ }
marked = true;
}
} else {
- CompilationInfo* info = compilation_info_at(i);
+ DCHECK(obj->IsForeign());
+ CompilationInfo* info = reinterpret_cast<CompilationInfo*>(
+ Foreign::cast(obj)->foreign_address());
info->AbortDueToDependencyChange();
}
}
@@ -12108,7 +12440,6 @@ void DependentCode::DeoptimizeDependentCodeGroup(
DCHECK(AllowCodeDependencyChange::IsAllowed());
DisallowHeapAllocation no_allocation_scope;
bool marked = MarkCodeForDeoptimization(isolate, group);
-
if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
}
@@ -12223,6 +12554,13 @@ MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
real_receiver =
Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
iter.Advance();
+ if (!real_receiver->map()->is_extensible()) {
+ Handle<Object> args[] = {object};
+ THROW_NEW_ERROR(isolate,
+ NewTypeError("non_extensible_proto",
+ HandleVector(args, arraysize(args))),
+ Object);
+ }
}
}
@@ -12279,18 +12617,14 @@ MaybeHandle<AccessorPair> JSObject::GetOwnElementAccessorPair(
// Check for lookup interceptor.
if (object->HasIndexedInterceptor()) return MaybeHandle<AccessorPair>();
- return object->GetElementsAccessor()->GetAccessorPair(object, object, index);
+ return object->GetElementsAccessor()->GetAccessorPair(object, index);
}
MaybeHandle<Object> JSObject::SetElementWithInterceptor(
- Handle<JSObject> object,
- uint32_t index,
- Handle<Object> value,
- PropertyAttributes attributes,
- StrictMode strict_mode,
- bool check_prototype,
- SetPropertyMode set_mode) {
+ Handle<JSObject> object, uint32_t index, Handle<Object> value,
+ PropertyAttributes attributes, LanguageMode language_mode,
+ bool check_prototype, SetPropertyMode set_mode) {
Isolate* isolate = object->GetIsolate();
// Make sure that the top context does not change when doing
@@ -12312,9 +12646,7 @@ MaybeHandle<Object> JSObject::SetElementWithInterceptor(
}
return SetElementWithoutInterceptor(object, index, value, attributes,
- strict_mode,
- check_prototype,
- set_mode);
+ language_mode, check_prototype, set_mode);
}
@@ -12362,11 +12694,6 @@ MaybeHandle<Object> JSObject::GetElementWithCallback(
return isolate->factory()->undefined_value();
}
- if (structure->IsDeclaredAccessorInfo()) {
- return GetDeclaredAccessorProperty(
- receiver, Handle<DeclaredAccessorInfo>::cast(structure), isolate);
- }
-
UNREACHABLE();
return MaybeHandle<Object>();
}
@@ -12374,7 +12701,7 @@ MaybeHandle<Object> JSObject::GetElementWithCallback(
MaybeHandle<Object> JSObject::SetElementWithCallback(
Handle<Object> object, Handle<Object> structure, uint32_t index,
- Handle<Object> value, Handle<JSObject> holder, StrictMode strict_mode) {
+ Handle<Object> value, Handle<JSObject> holder, LanguageMode language_mode) {
Isolate* isolate = holder->GetIsolate();
// We should never get here to initialize a const with the hole
@@ -12408,18 +12735,16 @@ MaybeHandle<Object> JSObject::SetElementWithCallback(
return SetPropertyWithDefinedSetter(
object, Handle<JSReceiver>::cast(setter), value);
} else {
- if (strict_mode == SLOPPY) return value;
+ if (is_sloppy(language_mode)) return value;
Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
- Handle<Object> args[2] = { key, holder };
- THROW_NEW_ERROR(
- isolate, NewTypeError("no_setter_in_callback", HandleVector(args, 2)),
- Object);
+ Handle<Object> args[] = {key, holder};
+ THROW_NEW_ERROR(isolate,
+ NewTypeError("no_setter_in_callback",
+ HandleVector(args, arraysize(args))),
+ Object);
}
}
- // TODO(dcarney): Handle correctly.
- if (structure->IsDeclaredAccessorInfo()) return value;
-
UNREACHABLE();
return MaybeHandle<Object>();
}
@@ -12455,7 +12780,7 @@ bool JSObject::HasDictionaryArgumentsElements() {
MaybeHandle<Object> JSObject::SetFastElement(Handle<JSObject> object,
uint32_t index,
Handle<Object> value,
- StrictMode strict_mode,
+ LanguageMode language_mode,
bool check_prototype) {
DCHECK(object->HasFastSmiOrObjectElements() ||
object->HasFastArgumentsElements());
@@ -12484,7 +12809,7 @@ MaybeHandle<Object> JSObject::SetFastElement(Handle<JSObject> object,
(index >= capacity || backing_store->get(index)->IsTheHole())) {
bool found;
MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
- object, index, value, &found, strict_mode);
+ object, index, value, &found, language_mode);
if (found) return result;
}
@@ -12527,7 +12852,7 @@ MaybeHandle<Object> JSObject::SetFastElement(Handle<JSObject> object,
}
if (convert_to_slow) {
NormalizeElements(object);
- return SetDictionaryElement(object, index, value, NONE, strict_mode,
+ return SetDictionaryElement(object, index, value, NONE, language_mode,
check_prototype);
}
}
@@ -12581,13 +12906,9 @@ MaybeHandle<Object> JSObject::SetFastElement(Handle<JSObject> object,
MaybeHandle<Object> JSObject::SetDictionaryElement(
- Handle<JSObject> object,
- uint32_t index,
- Handle<Object> value,
- PropertyAttributes attributes,
- StrictMode strict_mode,
- bool check_prototype,
- SetPropertyMode set_mode) {
+ Handle<JSObject> object, uint32_t index, Handle<Object> value,
+ PropertyAttributes attributes, LanguageMode language_mode,
+ bool check_prototype, SetPropertyMode set_mode) {
DCHECK(object->HasDictionaryElements() ||
object->HasDictionaryArgumentsElements());
Isolate* isolate = object->GetIsolate();
@@ -12604,29 +12925,33 @@ MaybeHandle<Object> JSObject::SetDictionaryElement(
if (entry != SeededNumberDictionary::kNotFound) {
Handle<Object> element(dictionary->ValueAt(entry), isolate);
PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
+ if (details.type() == ACCESSOR_CONSTANT && set_mode == SET_PROPERTY) {
return SetElementWithCallback(object, element, index, value, object,
- strict_mode);
+ language_mode);
+ } else if (set_mode == DEFINE_PROPERTY && !details.IsConfigurable() &&
+ details.kind() == kAccessor) {
+ return RedefineNonconfigurableProperty(
+ isolate, isolate->factory()->NewNumberFromUint(index),
+ isolate->factory()->undefined_value(), language_mode);
+
+ } else if ((set_mode == DEFINE_PROPERTY && !details.IsConfigurable() &&
+ details.IsReadOnly()) ||
+ (set_mode == SET_PROPERTY && details.IsReadOnly() &&
+ !element->IsTheHole())) {
+ // If a value has not been initialized we allow writing to it even if it
+ // is read-only (a declared const that has not been initialized).
+ return WriteToReadOnlyProperty(
+ isolate, object, isolate->factory()->NewNumberFromUint(index),
+ isolate->factory()->undefined_value(), language_mode);
} else {
+ DCHECK(details.IsConfigurable() || !details.IsReadOnly() ||
+ element->IsTheHole());
dictionary->UpdateMaxNumberKey(index);
- // If a value has not been initialized we allow writing to it even if it
- // is read-only (a declared const that has not been initialized). If a
- // value is being defined we skip attribute checks completely.
if (set_mode == DEFINE_PROPERTY) {
- details =
- PropertyDetails(attributes, FIELD, details.dictionary_index());
+ details = PropertyDetails(attributes, DATA, details.dictionary_index());
dictionary->DetailsAtPut(entry, details);
- } else if (details.IsReadOnly() && !element->IsTheHole()) {
- if (strict_mode == SLOPPY) {
- return isolate->factory()->undefined_value();
- } else {
- Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
- Handle<Object> args[2] = { number, object };
- THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
- HandleVector(args, 2)),
- Object);
- }
}
+
// Elements of the arguments object in slow mode might be slow aliases.
if (is_arguments && element->IsAliasedArgumentsEntry()) {
Handle<AliasedArgumentsEntry> entry =
@@ -12646,26 +12971,27 @@ MaybeHandle<Object> JSObject::SetDictionaryElement(
if (check_prototype) {
bool found;
MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
- object, index, value, &found, strict_mode);
+ object, index, value, &found, language_mode);
if (found) return result;
}
// When we set the is_extensible flag to false we always force the
// element into dictionary mode (and force them to stay there).
if (!object->map()->is_extensible()) {
- if (strict_mode == SLOPPY) {
+ if (is_sloppy(language_mode)) {
return isolate->factory()->undefined_value();
} else {
Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Handle<String> name = isolate->factory()->NumberToString(number);
- Handle<Object> args[1] = { name };
- THROW_NEW_ERROR(isolate, NewTypeError("object_not_extensible",
- HandleVector(args, 1)),
+ Handle<Object> args[] = {name};
+ THROW_NEW_ERROR(isolate,
+ NewTypeError("object_not_extensible",
+ HandleVector(args, arraysize(args))),
Object);
}
}
- PropertyDetails details(attributes, FIELD, 0);
+ PropertyDetails details(attributes, DATA, 0);
Handle<SeededNumberDictionary> new_dictionary =
SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
details);
@@ -12717,12 +13043,11 @@ MaybeHandle<Object> JSObject::SetDictionaryElement(
return value;
}
-MaybeHandle<Object> JSObject::SetFastDoubleElement(
- Handle<JSObject> object,
- uint32_t index,
- Handle<Object> value,
- StrictMode strict_mode,
- bool check_prototype) {
+MaybeHandle<Object> JSObject::SetFastDoubleElement(Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value,
+ LanguageMode language_mode,
+ bool check_prototype) {
DCHECK(object->HasFastDoubleElements());
Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements()));
@@ -12735,7 +13060,7 @@ MaybeHandle<Object> JSObject::SetFastDoubleElement(
Handle<FixedDoubleArray>::cast(base_elms)->is_the_hole(index))) {
bool found;
MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
- object, index, value, &found, strict_mode);
+ object, index, value, &found, language_mode);
if (found) return result;
}
@@ -12757,7 +13082,7 @@ MaybeHandle<Object> JSObject::SetFastDoubleElement(
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
object->GetIsolate(), result,
- SetFastElement(object, index, value, strict_mode, check_prototype),
+ SetFastElement(object, index, value, language_mode, check_prototype),
Object);
JSObject::ValidateElements(object);
return result;
@@ -12812,38 +13137,38 @@ MaybeHandle<Object> JSObject::SetFastDoubleElement(
NormalizeElements(object);
DCHECK(object->HasDictionaryElements());
- return SetElement(object, index, value, NONE, strict_mode, check_prototype);
+ return SetElement(object, index, value, NONE, language_mode, check_prototype);
}
MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
- uint32_t index,
- Handle<Object> value,
+ uint32_t index, Handle<Object> value,
PropertyAttributes attributes,
- StrictMode strict_mode) {
+ LanguageMode language_mode) {
if (object->IsJSProxy()) {
- return JSProxy::SetElementWithHandler(
- Handle<JSProxy>::cast(object), object, index, value, strict_mode);
+ return JSProxy::SetElementWithHandler(Handle<JSProxy>::cast(object), object,
+ index, value, language_mode);
}
- return JSObject::SetElement(
- Handle<JSObject>::cast(object), index, value, attributes, strict_mode);
+ return JSObject::SetElement(Handle<JSObject>::cast(object), index, value,
+ attributes, language_mode);
}
MaybeHandle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
uint32_t index,
Handle<Object> value,
- StrictMode strict_mode) {
+ PropertyAttributes attributes,
+ LanguageMode language_mode) {
DCHECK(!object->HasExternalArrayElements());
- return JSObject::SetElement(object, index, value, NONE, strict_mode, false);
+ return JSObject::SetElement(object, index, value, attributes, language_mode,
+ false);
}
MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
- uint32_t index,
- Handle<Object> value,
+ uint32_t index, Handle<Object> value,
PropertyAttributes attributes,
- StrictMode strict_mode,
+ LanguageMode language_mode,
bool check_prototype,
SetPropertyMode set_mode) {
Isolate* isolate = object->GetIsolate();
@@ -12872,7 +13197,7 @@ MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
return SetElement(
Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index,
- value, attributes, strict_mode, check_prototype, set_mode);
+ value, attributes, language_mode, check_prototype, set_mode);
}
// Don't allow element properties to be redefined for external arrays.
@@ -12895,10 +13220,12 @@ MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
if (!object->map()->is_observed()) {
return object->HasIndexedInterceptor()
- ? SetElementWithInterceptor(object, index, value, attributes,
- strict_mode, check_prototype, set_mode)
- : SetElementWithoutInterceptor(object, index, value, attributes,
- strict_mode, check_prototype, set_mode);
+ ? SetElementWithInterceptor(object, index, value, attributes,
+ language_mode, check_prototype,
+ set_mode)
+ : SetElementWithoutInterceptor(object, index, value, attributes,
+ language_mode, check_prototype,
+ set_mode);
}
Maybe<PropertyAttributes> maybe =
@@ -12925,12 +13252,11 @@ MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
object->HasIndexedInterceptor()
- ? SetElementWithInterceptor(
- object, index, value, attributes,
- strict_mode, check_prototype, set_mode)
- : SetElementWithoutInterceptor(
- object, index, value, attributes,
- strict_mode, check_prototype, set_mode),
+ ? SetElementWithInterceptor(object, index, value, attributes,
+ language_mode, check_prototype, set_mode)
+ : SetElementWithoutInterceptor(object, index, value, attributes,
+ language_mode, check_prototype,
+ set_mode),
Object);
Handle<String> name = isolate->factory()->Uint32ToString(index);
@@ -12995,13 +13321,9 @@ MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
MaybeHandle<Object> JSObject::SetElementWithoutInterceptor(
- Handle<JSObject> object,
- uint32_t index,
- Handle<Object> value,
- PropertyAttributes attributes,
- StrictMode strict_mode,
- bool check_prototype,
- SetPropertyMode set_mode) {
+ Handle<JSObject> object, uint32_t index, Handle<Object> value,
+ PropertyAttributes attributes, LanguageMode language_mode,
+ bool check_prototype, SetPropertyMode set_mode) {
DCHECK(object->HasDictionaryElements() ||
object->HasDictionaryArgumentsElements() ||
(attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
@@ -13018,7 +13340,7 @@ MaybeHandle<Object> JSObject::SetElementWithoutInterceptor(
}
if (object->IsJSArray() && JSArray::WouldChangeReadOnlyLength(
Handle<JSArray>::cast(object), index)) {
- if (strict_mode == SLOPPY) {
+ if (is_sloppy(language_mode)) {
return value;
} else {
return JSArray::ReadOnlyLengthError(Handle<JSArray>::cast(object));
@@ -13029,10 +13351,11 @@ MaybeHandle<Object> JSObject::SetElementWithoutInterceptor(
case FAST_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
- return SetFastElement(object, index, value, strict_mode, check_prototype);
+ return SetFastElement(object, index, value, language_mode,
+ check_prototype);
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
- return SetFastDoubleElement(object, index, value, strict_mode,
+ return SetFastDoubleElement(object, index, value, language_mode,
check_prototype);
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
@@ -13052,9 +13375,8 @@ MaybeHandle<Object> JSObject::SetElementWithoutInterceptor(
#undef TYPED_ARRAY_CASE
case DICTIONARY_ELEMENTS:
- return SetDictionaryElement(object, index, value, attributes, strict_mode,
- check_prototype,
- set_mode);
+ return SetDictionaryElement(object, index, value, attributes,
+ language_mode, check_prototype, set_mode);
case SLOPPY_ARGUMENTS_ELEMENTS: {
Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
uint32_t length = parameter_map->length();
@@ -13078,11 +13400,9 @@ MaybeHandle<Object> JSObject::SetElementWithoutInterceptor(
Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
if (arguments->IsDictionary()) {
return SetDictionaryElement(object, index, value, attributes,
- strict_mode,
- check_prototype,
- set_mode);
+ language_mode, check_prototype, set_mode);
} else {
- return SetFastElement(object, index, value, strict_mode,
+ return SetFastElement(object, index, value, language_mode,
check_prototype);
}
}
@@ -13207,7 +13527,7 @@ void AllocationSite::AddDependentCompilationInfo(
CompilationInfo* info) {
Handle<DependentCode> dep(site->dependent_code());
Handle<DependentCode> codes =
- DependentCode::Insert(dep, group, info->object_wrapper());
+ DependentCode::InsertCompilationInfo(dep, group, info->object_wrapper());
if (*codes != site->dependent_code()) site->set_dependent_code(*codes);
info->dependencies(group)->Add(Handle<HeapObject>(*site), info->zone());
}
@@ -13344,16 +13664,6 @@ void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array,
}
-bool JSArray::IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
- Isolate* isolate = jsarray_map->GetIsolate();
- DCHECK(!jsarray_map->is_dictionary_map());
- LookupResult lookup(isolate);
- Handle<Name> length_string = isolate->factory()->length_string();
- jsarray_map->LookupDescriptor(NULL, *length_string, &lookup);
- return lookup.IsReadOnly();
-}
-
-
bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
LookupIterator it(array, array->GetIsolate()->factory()->length_string(),
LookupIterator::OWN_SKIP_INTERCEPTOR);
@@ -13376,17 +13686,17 @@ bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) {
Isolate* isolate = array->GetIsolate();
Handle<Name> length = isolate->factory()->length_string();
- Handle<Object> args[2] = { length, array };
+ Handle<Object> args[] = {length, array};
THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
HandleVector(args, arraysize(args))),
Object);
}
-MaybeHandle<Object> JSObject::GetElementWithInterceptor(
- Handle<JSObject> object,
- Handle<Object> receiver,
- uint32_t index) {
+MaybeHandle<Object> JSObject::GetElementWithInterceptor(Handle<JSObject> object,
+ Handle<Object> receiver,
+ uint32_t index,
+ bool check_prototype) {
Isolate* isolate = object->GetIsolate();
// Make sure that the top context does not change when doing
@@ -13411,6 +13721,8 @@ MaybeHandle<Object> JSObject::GetElementWithInterceptor(
}
}
+ if (!check_prototype) return MaybeHandle<Object>();
+
ElementsAccessor* handler = object->GetElementsAccessor();
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
@@ -13713,10 +14025,8 @@ MaybeHandle<JSObject> JSObject::GetKeysForNamedInterceptor(
result = args.Call(enum_fun);
}
if (result.IsEmpty()) return MaybeHandle<JSObject>();
-#if ENABLE_EXTRA_CHECKS
- CHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
- v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
-#endif
+ DCHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
+ v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
// Rebox before returning.
return handle(*v8::Utils::OpenHandle(*result), isolate);
}
@@ -13738,10 +14048,8 @@ MaybeHandle<JSObject> JSObject::GetKeysForIndexedInterceptor(
result = args.Call(enum_fun);
}
if (result.IsEmpty()) return MaybeHandle<JSObject>();
-#if ENABLE_EXTRA_CHECKS
- CHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
- v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
-#endif
+ DCHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
+ v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
// Rebox before returning.
return handle(*v8::Utils::OpenHandle(*result), isolate);
}
@@ -14123,14 +14431,12 @@ void Symbol::SymbolShortPrint(std::ostream& os) {
// StringSharedKeys are used as keys in the eval cache.
class StringSharedKey : public HashTableKey {
public:
- StringSharedKey(Handle<String> source,
- Handle<SharedFunctionInfo> shared,
- StrictMode strict_mode,
- int scope_position)
+ StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
+ LanguageMode language_mode, int scope_position)
: source_(source),
shared_(shared),
- strict_mode_(strict_mode),
- scope_position_(scope_position) { }
+ language_mode_(language_mode),
+ scope_position_(scope_position) {}
bool IsMatch(Object* other) OVERRIDE {
DisallowHeapAllocation no_allocation;
@@ -14142,10 +14448,10 @@ class StringSharedKey : public HashTableKey {
FixedArray* other_array = FixedArray::cast(other);
SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
if (shared != *shared_) return false;
- int strict_unchecked = Smi::cast(other_array->get(2))->value();
- DCHECK(strict_unchecked == SLOPPY || strict_unchecked == STRICT);
- StrictMode strict_mode = static_cast<StrictMode>(strict_unchecked);
- if (strict_mode != strict_mode_) return false;
+ int language_unchecked = Smi::cast(other_array->get(2))->value();
+ DCHECK(is_valid_language_mode(language_unchecked));
+ LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
+ if (language_mode != language_mode_) return false;
int scope_position = Smi::cast(other_array->get(3))->value();
if (scope_position != scope_position_) return false;
String* source = String::cast(other_array->get(1));
@@ -14154,7 +14460,7 @@ class StringSharedKey : public HashTableKey {
static uint32_t StringSharedHashHelper(String* source,
SharedFunctionInfo* shared,
- StrictMode strict_mode,
+ LanguageMode language_mode,
int scope_position) {
uint32_t hash = source->Hash();
if (shared->HasSourceCode()) {
@@ -14165,14 +14471,16 @@ class StringSharedKey : public HashTableKey {
// collection.
Script* script(Script::cast(shared->script()));
hash ^= String::cast(script->source())->Hash();
- if (strict_mode == STRICT) hash ^= 0x8000;
+ STATIC_ASSERT(LANGUAGE_END == 3);
+ if (is_strict(language_mode)) hash ^= 0x8000;
+ if (is_strong(language_mode)) hash ^= 0x10000;
hash += scope_position;
}
return hash;
}
uint32_t Hash() OVERRIDE {
- return StringSharedHashHelper(*source_, *shared_, strict_mode_,
+ return StringSharedHashHelper(*source_, *shared_, language_mode_,
scope_position_);
}
@@ -14184,12 +14492,12 @@ class StringSharedKey : public HashTableKey {
FixedArray* other_array = FixedArray::cast(obj);
SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
String* source = String::cast(other_array->get(1));
- int strict_unchecked = Smi::cast(other_array->get(2))->value();
- DCHECK(strict_unchecked == SLOPPY || strict_unchecked == STRICT);
- StrictMode strict_mode = static_cast<StrictMode>(strict_unchecked);
+ int language_unchecked = Smi::cast(other_array->get(2))->value();
+ DCHECK(is_valid_language_mode(language_unchecked));
+ LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
int scope_position = Smi::cast(other_array->get(3))->value();
- return StringSharedHashHelper(
- source, shared, strict_mode, scope_position);
+ return StringSharedHashHelper(source, shared, language_mode,
+ scope_position);
}
@@ -14197,7 +14505,7 @@ class StringSharedKey : public HashTableKey {
Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
array->set(0, *shared_);
array->set(1, *source_);
- array->set(2, Smi::FromInt(strict_mode_));
+ array->set(2, Smi::FromInt(language_mode_));
array->set(3, Smi::FromInt(scope_position_));
return array;
}
@@ -14205,7 +14513,7 @@ class StringSharedKey : public HashTableKey {
private:
Handle<String> source_;
Handle<SharedFunctionInfo> shared_;
- StrictMode strict_mode_;
+ LanguageMode language_mode_;
int scope_position_;
};
@@ -14645,11 +14953,11 @@ Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
template Handle<Object>
Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
- Handle<NameDictionary>, int, JSObject::DeleteMode);
+ Handle<NameDictionary>, int);
template Handle<Object>
-Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
- DeleteProperty(Handle<SeededNumberDictionary>, int, JSObject::DeleteMode);
+Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
+ uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
template Handle<NameDictionary>
HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
@@ -14762,7 +15070,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
HandleScope scope(isolate);
Handle<Object> value(dict->ValueAt(i), isolate);
PropertyDetails details = dict->DetailsAt(i);
- if (details.type() == CALLBACKS || details.IsReadOnly()) {
+ if (details.type() == ACCESSOR_CONSTANT || details.IsReadOnly()) {
// Bail out and do the sorting of undefineds and array holes in JS.
// Also bail out if the element is not supposed to be moved.
return bailout;
@@ -14796,7 +15104,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
}
uint32_t result = pos;
- PropertyDetails no_details(NONE, FIELD, 0);
+ PropertyDetails no_details(NONE, DATA, 0);
while (undefs > 0) {
if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
// Adding an entry with the key beyond smi-range requires
@@ -15116,7 +15424,7 @@ Handle<Object> ExternalFloat32Array::SetValue(
Handle<ExternalFloat32Array> array,
uint32_t index,
Handle<Object> value) {
- float cast_value = static_cast<float>(base::OS::nan_value());
+ float cast_value = std::numeric_limits<float>::quiet_NaN();
if (index < static_cast<uint32_t>(array->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::cast(value)->value();
@@ -15139,7 +15447,7 @@ Handle<Object> ExternalFloat64Array::SetValue(
Handle<ExternalFloat64Array> array,
uint32_t index,
Handle<Object> value) {
- double double_value = base::OS::nan_value();
+ double double_value = std::numeric_limits<double>::quiet_NaN();
if (index < static_cast<uint32_t>(array->length())) {
if (value->IsNumber()) {
double_value = value->Number();
@@ -15173,16 +15481,14 @@ void GlobalObject::InvalidatePropertyCell(Handle<GlobalObject> global,
}
-Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
- Handle<JSGlobalObject> global,
- Handle<Name> name) {
+Handle<PropertyCell> GlobalObject::EnsurePropertyCell(
+ Handle<GlobalObject> global, Handle<Name> name) {
DCHECK(!global->HasFastProperties());
int entry = global->property_dictionary()->FindEntry(name);
if (entry == NameDictionary::kNotFound) {
Isolate* isolate = global->GetIsolate();
- Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
- isolate->factory()->the_hole_value());
- PropertyDetails details(NONE, FIELD, 0);
+ Handle<PropertyCell> cell = isolate->factory()->NewPropertyCellWithHole();
+ PropertyDetails details(NONE, DATA, 0);
details = details.AsDeleted();
Handle<NameDictionary> dictionary = NameDictionary::Add(
handle(global->property_dictionary()), name, cell, details);
@@ -15349,11 +15655,11 @@ Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
- Handle<Context> context) {
+ Handle<Context> context,
+ LanguageMode language_mode) {
Isolate* isolate = GetIsolate();
Handle<SharedFunctionInfo> shared(context->closure()->shared());
- StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
- RelocInfo::kNoPosition);
+ StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
int entry = FindEntry(&key);
if (entry == kNotFound) return isolate->factory()->undefined_value();
int index = EntryToIndex(entry);
@@ -15364,11 +15670,11 @@ Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
Handle<Object> CompilationCacheTable::LookupEval(
Handle<String> src, Handle<SharedFunctionInfo> outer_info,
- StrictMode strict_mode, int scope_position) {
+ LanguageMode language_mode, int scope_position) {
Isolate* isolate = GetIsolate();
// Cache key is the tuple (source, outer shared function info, scope position)
// to unambiguously identify the context chain the cached eval code assumes.
- StringSharedKey key(src, outer_info, strict_mode, scope_position);
+ StringSharedKey key(src, outer_info, language_mode, scope_position);
int entry = FindEntry(&key);
if (entry == kNotFound) return isolate->factory()->undefined_value();
int index = EntryToIndex(entry);
@@ -15390,11 +15696,10 @@ Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
Handle<CompilationCacheTable> CompilationCacheTable::Put(
Handle<CompilationCacheTable> cache, Handle<String> src,
- Handle<Context> context, Handle<Object> value) {
+ Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
Isolate* isolate = cache->GetIsolate();
Handle<SharedFunctionInfo> shared(context->closure()->shared());
- StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
- RelocInfo::kNoPosition);
+ StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
{
Handle<Object> k = key.AsHandle(isolate);
DisallowHeapAllocation no_allocation_scope;
@@ -15422,7 +15727,7 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
int scope_position) {
Isolate* isolate = cache->GetIsolate();
- StringSharedKey key(src, outer_info, value->strict_mode(), scope_position);
+ StringSharedKey key(src, outer_info, value->language_mode(), scope_position);
{
Handle<Object> k = key.AsHandle(isolate);
DisallowHeapAllocation no_allocation_scope;
@@ -15627,17 +15932,12 @@ Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
}
-template<typename Derived, typename Shape, typename Key>
+template <typename Derived, typename Shape, typename Key>
Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
- Handle<Derived> dictionary,
- int entry,
- JSObject::DeleteMode mode) {
+ Handle<Derived> dictionary, int entry) {
Factory* factory = dictionary->GetIsolate()->factory();
PropertyDetails details = dictionary->DetailsAt(entry);
- // Ignore attributes if forcing a deletion.
- if (!details.IsConfigurable() && mode != JSReceiver::FORCE_DELETION) {
- return factory->false_value();
- }
+ if (!details.IsConfigurable()) return factory->false_value();
dictionary->SetEntry(
entry, factory->the_hole_value(), factory->the_hole_value());
@@ -15662,7 +15962,7 @@ Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
#ifdef DEBUG
USE(Shape::AsHandle(dictionary->GetIsolate(), key));
#endif
- PropertyDetails details(NONE, FIELD, 0);
+ PropertyDetails details(NONE, DATA, 0);
AddEntry(dictionary, key, value, details, dictionary->Hash(key));
return dictionary;
@@ -15750,7 +16050,7 @@ Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
uint32_t key,
Handle<Object> value) {
SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
- return Add(dictionary, key, value, PropertyDetails(NONE, FIELD, 0));
+ return Add(dictionary, key, value, PropertyDetails(NONE, DATA, 0));
}
@@ -15838,7 +16138,7 @@ bool Dictionary<Derived, Shape, Key>::HasComplexElements() {
if (DerivedHashTable::IsKey(k) && !FilterKey(k, NONE)) {
PropertyDetails details = DetailsAt(i);
if (details.IsDeleted()) continue;
- if (details.type() == CALLBACKS) return true;
+ if (details.type() == ACCESSOR_CONSTANT) return true;
PropertyAttributes attr = details.attributes();
if (attr & (READ_ONLY | DONT_DELETE | DONT_ENUM)) return true;
}
@@ -16029,7 +16329,7 @@ void ObjectHashTable::RemoveEntry(int entry) {
}
-Object* WeakHashTable::Lookup(Handle<Object> key) {
+Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
DisallowHeapAllocation no_gc;
DCHECK(IsKey(*key));
int entry = FindEntry(key);
@@ -16039,36 +16339,31 @@ Object* WeakHashTable::Lookup(Handle<Object> key) {
Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
- Handle<Object> key,
- Handle<Object> value) {
+ Handle<HeapObject> key,
+ Handle<HeapObject> value) {
DCHECK(table->IsKey(*key));
int entry = table->FindEntry(key);
// Key is already in table, just overwrite value.
if (entry != kNotFound) {
- // TODO(ulan): Skipping write barrier is a temporary solution to avoid
- // memory leaks. Remove this once we have special visitor for weak fixed
- // arrays.
- table->set(EntryToValueIndex(entry), *value, SKIP_WRITE_BARRIER);
+ table->set(EntryToValueIndex(entry), *value);
return table;
}
+ Handle<WeakCell> key_cell = key->GetIsolate()->factory()->NewWeakCell(key);
+
// Check whether the hash table should be extended.
table = EnsureCapacity(table, 1, key, TENURED);
- table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key, value);
+ table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value);
return table;
}
-void WeakHashTable::AddEntry(int entry,
- Handle<Object> key,
- Handle<Object> value) {
+void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
+ Handle<HeapObject> value) {
DisallowHeapAllocation no_allocation;
- // TODO(ulan): Skipping write barrier is a temporary solution to avoid
- // memory leaks. Remove this once we have special visitor for weak fixed
- // arrays.
- set(EntryToIndex(entry), *key, SKIP_WRITE_BARRIER);
- set(EntryToValueIndex(entry), *value, SKIP_WRITE_BARRIER);
+ set(EntryToIndex(entry), *key_cell);
+ set(EntryToValueIndex(entry), *value);
ElementAdded();
}
@@ -16476,58 +16771,6 @@ template void
OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
-DeclaredAccessorDescriptorIterator::DeclaredAccessorDescriptorIterator(
- DeclaredAccessorDescriptor* descriptor)
- : array_(descriptor->serialized_data()->GetDataStartAddress()),
- length_(descriptor->serialized_data()->length()),
- offset_(0) {
-}
-
-
-const DeclaredAccessorDescriptorData*
- DeclaredAccessorDescriptorIterator::Next() {
- DCHECK(offset_ < length_);
- uint8_t* ptr = &array_[offset_];
- DCHECK(reinterpret_cast<uintptr_t>(ptr) % sizeof(uintptr_t) == 0);
- const DeclaredAccessorDescriptorData* data =
- reinterpret_cast<const DeclaredAccessorDescriptorData*>(ptr);
- offset_ += sizeof(*data);
- DCHECK(offset_ <= length_);
- return data;
-}
-
-
-Handle<DeclaredAccessorDescriptor> DeclaredAccessorDescriptor::Create(
- Isolate* isolate,
- const DeclaredAccessorDescriptorData& descriptor,
- Handle<DeclaredAccessorDescriptor> previous) {
- int previous_length =
- previous.is_null() ? 0 : previous->serialized_data()->length();
- int length = sizeof(descriptor) + previous_length;
- Handle<ByteArray> serialized_descriptor =
- isolate->factory()->NewByteArray(length);
- Handle<DeclaredAccessorDescriptor> value =
- isolate->factory()->NewDeclaredAccessorDescriptor();
- value->set_serialized_data(*serialized_descriptor);
- // Copy in the data.
- {
- DisallowHeapAllocation no_allocation;
- uint8_t* array = serialized_descriptor->GetDataStartAddress();
- if (previous_length != 0) {
- uint8_t* previous_array =
- previous->serialized_data()->GetDataStartAddress();
- MemCopy(array, previous_array, previous_length);
- array += previous_length;
- }
- DCHECK(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
- DeclaredAccessorDescriptorData* data =
- reinterpret_cast<DeclaredAccessorDescriptorData*>(array);
- *data = descriptor;
- }
- return value;
-}
-
-
// Check if there is a break point at this code position.
bool DebugInfo::HasBreakPoint(int code_position) {
// Get the break point info object for this code position.
@@ -17037,10 +17280,12 @@ Handle<Object> PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
const int kMaxLengthForInternalization = 200;
if ((cell->type()->Is(HeapType::None()) ||
cell->type()->Is(HeapType::Undefined())) &&
- value->IsString() &&
- Handle<String>::cast(value)->length() <= kMaxLengthForInternalization) {
- value = cell->GetIsolate()->factory()->InternalizeString(
- Handle<String>::cast(value));
+ value->IsString()) {
+ auto string = Handle<String>::cast(value);
+ if (string->length() <= kMaxLengthForInternalization &&
+ !string->map()->is_undetectable()) {
+ value = cell->GetIsolate()->factory()->InternalizeString(string);
+ }
}
cell->set_value(*value);
if (!HeapType::Any()->Is(cell->type())) {
@@ -17054,10 +17299,9 @@ Handle<Object> PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
// static
void PropertyCell::AddDependentCompilationInfo(Handle<PropertyCell> cell,
CompilationInfo* info) {
- Handle<DependentCode> codes =
- DependentCode::Insert(handle(cell->dependent_code(), info->isolate()),
- DependentCode::kPropertyCellChangedGroup,
- info->object_wrapper());
+ Handle<DependentCode> codes = DependentCode::InsertCompilationInfo(
+ handle(cell->dependent_code(), info->isolate()),
+ DependentCode::kPropertyCellChangedGroup, info->object_wrapper());
if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes);
info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add(
cell, info->zone());