[runtime] making heap verification more aggressive
- check that packed elements do not contain the_hole (with fix) - verify argument objects with elements kind - use JSObjectVerifiy in all JSObject "subclasses" - change initialization order for ArrayLiteralBoilerplate to simplify verification BUG=v8:5188 Review-Url: https://codereview.chromium.org/2126613002 Cr-Commit-Position: refs/heads/master@{#37680}
This commit is contained in:
parent
c70dc6acd7
commit
599aa2e106
@ -1647,19 +1647,29 @@ void Factory::NewJSArrayStorage(Handle<JSArray> array,
|
||||
Handle<FixedArrayBase> elms;
|
||||
ElementsKind elements_kind = array->GetElementsKind();
|
||||
if (IsFastDoubleElementsKind(elements_kind)) {
|
||||
if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
|
||||
elms = NewFixedDoubleArray(capacity);
|
||||
} else {
|
||||
DCHECK(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
|
||||
elms = NewFixedDoubleArrayWithHoles(capacity);
|
||||
switch (mode) {
|
||||
case DONT_INITIALIZE_ARRAY_ELEMENTS:
|
||||
elms = NewFixedDoubleArray(capacity);
|
||||
break;
|
||||
case INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE:
|
||||
elms = NewFixedDoubleArrayWithHoles(capacity);
|
||||
break;
|
||||
case INITIALIZE_ARRAY_ELEMENTS_WITH_UNDEFINED:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
DCHECK(IsFastSmiOrObjectElementsKind(elements_kind));
|
||||
if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
|
||||
elms = NewUninitializedFixedArray(capacity);
|
||||
} else {
|
||||
DCHECK(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
|
||||
elms = NewFixedArrayWithHoles(capacity);
|
||||
switch (mode) {
|
||||
case DONT_INITIALIZE_ARRAY_ELEMENTS:
|
||||
elms = NewUninitializedFixedArray(capacity);
|
||||
break;
|
||||
case INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE:
|
||||
elms = NewFixedArrayWithHoles(capacity);
|
||||
break;
|
||||
case INITIALIZE_ARRAY_ELEMENTS_WITH_UNDEFINED:
|
||||
elms = NewFixedArray(capacity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,10 +441,10 @@ class PromotionQueue {
|
||||
DISALLOW_COPY_AND_ASSIGN(PromotionQueue);
|
||||
};
|
||||
|
||||
|
||||
enum ArrayStorageAllocationMode {
|
||||
DONT_INITIALIZE_ARRAY_ELEMENTS,
|
||||
INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
|
||||
INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE,
|
||||
INITIALIZE_ARRAY_ELEMENTS_WITH_UNDEFINED
|
||||
};
|
||||
|
||||
enum class ClearRecordedSlots { kYes, kNo };
|
||||
|
@ -100,13 +100,15 @@ void HeapObject::HeapObjectVerify() {
|
||||
break;
|
||||
case JS_OBJECT_TYPE:
|
||||
case JS_ERROR_TYPE:
|
||||
case JS_ARGUMENTS_TYPE:
|
||||
case JS_API_OBJECT_TYPE:
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
|
||||
case JS_PROMISE_TYPE:
|
||||
JSObject::cast(this)->JSObjectVerify();
|
||||
break;
|
||||
case JS_ARGUMENTS_TYPE:
|
||||
JSArgumentsObject::cast(this)->JSArgumentsObjectVerify();
|
||||
break;
|
||||
case JS_GENERATOR_OBJECT_TYPE:
|
||||
JSGeneratorObject::cast(this)->JSGeneratorObjectVerify();
|
||||
break;
|
||||
@ -246,9 +248,9 @@ void FreeSpace::FreeSpaceVerify() {
|
||||
|
||||
template <class Traits>
|
||||
void FixedTypedArray<Traits>::FixedTypedArrayVerify() {
|
||||
CHECK(IsHeapObject() &&
|
||||
HeapObject::cast(this)->map()->instance_type() ==
|
||||
Traits::kInstanceType);
|
||||
CHECK(IsHeapObject());
|
||||
CHECK(HeapObject::cast(this)->map()->instance_type() ==
|
||||
Traits::kInstanceType);
|
||||
if (base_pointer() == this) {
|
||||
CHECK(external_pointer() ==
|
||||
ExternalReference::fixed_typed_array_base_data_offset().address());
|
||||
@ -265,76 +267,166 @@ bool JSObject::ElementsAreSafeToExamine() {
|
||||
GetHeap()->one_pointer_filler_map();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void JSObject::JSObjectVerify() {
|
||||
VerifyHeapPointer(properties());
|
||||
VerifyHeapPointer(elements());
|
||||
|
||||
if (HasSloppyArgumentsElements()) {
|
||||
CHECK(this->elements()->IsFixedArray());
|
||||
CHECK_GE(this->elements()->length(), 2);
|
||||
void VerifyFastProperties(JSReceiver* receiver) {
|
||||
// TODO(cbruni): JSProxy support for slow properties
|
||||
if (!receiver->IsJSObject()) return;
|
||||
Isolate* isolate = receiver->GetIsolate();
|
||||
Map* map = receiver->map();
|
||||
CHECK(!map->is_dictionary_map());
|
||||
JSObject* obj = JSObject::cast(receiver);
|
||||
int actual_unused_property_fields = map->GetInObjectProperties() +
|
||||
obj->properties()->length() -
|
||||
map->NextFreePropertyIndex();
|
||||
if (map->unused_property_fields() != actual_unused_property_fields) {
|
||||
// This could actually happen in the middle of StoreTransitionStub
|
||||
// when the new extended backing store is already set into the object and
|
||||
// the allocation of the MutableHeapNumber triggers GC (in this case map
|
||||
// is not updated yet).
|
||||
CHECK_EQ(map->unused_property_fields(),
|
||||
actual_unused_property_fields - JSObject::kFieldsAdded);
|
||||
}
|
||||
|
||||
if (HasFastProperties()) {
|
||||
int actual_unused_property_fields = map()->GetInObjectProperties() +
|
||||
properties()->length() -
|
||||
map()->NextFreePropertyIndex();
|
||||
if (map()->unused_property_fields() != actual_unused_property_fields) {
|
||||
// This could actually happen in the middle of StoreTransitionStub
|
||||
// when the new extended backing store is already set into the object and
|
||||
// the allocation of the MutableHeapNumber triggers GC (in this case map
|
||||
// is not updated yet).
|
||||
CHECK_EQ(map()->unused_property_fields(),
|
||||
actual_unused_property_fields - JSObject::kFieldsAdded);
|
||||
DescriptorArray* descriptors = map->instance_descriptors();
|
||||
for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
|
||||
if (descriptors->GetDetails(i).type() != DATA) continue;
|
||||
Representation r = descriptors->GetDetails(i).representation();
|
||||
FieldIndex index = FieldIndex::ForDescriptor(map, i);
|
||||
if (obj->IsUnboxedDoubleField(index)) {
|
||||
DCHECK(r.IsDouble());
|
||||
continue;
|
||||
}
|
||||
DescriptorArray* descriptors = map()->instance_descriptors();
|
||||
Isolate* isolate = GetIsolate();
|
||||
for (int i = 0; i < map()->NumberOfOwnDescriptors(); i++) {
|
||||
if (descriptors->GetDetails(i).type() == DATA) {
|
||||
Representation r = descriptors->GetDetails(i).representation();
|
||||
FieldIndex index = FieldIndex::ForDescriptor(map(), i);
|
||||
if (IsUnboxedDoubleField(index)) {
|
||||
DCHECK(r.IsDouble());
|
||||
continue;
|
||||
}
|
||||
Object* value = RawFastPropertyAt(index);
|
||||
if (r.IsDouble()) DCHECK(value->IsMutableHeapNumber());
|
||||
if (value->IsUninitialized(isolate)) continue;
|
||||
if (r.IsSmi()) DCHECK(value->IsSmi());
|
||||
if (r.IsHeapObject()) DCHECK(value->IsHeapObject());
|
||||
FieldType* field_type = descriptors->GetFieldType(i);
|
||||
bool type_is_none = field_type->IsNone();
|
||||
bool type_is_any = field_type->IsAny();
|
||||
if (r.IsNone()) {
|
||||
CHECK(type_is_none);
|
||||
} else if (!type_is_any && !(type_is_none && r.IsHeapObject())) {
|
||||
// If allocation folding is off then GC could happen during inner
|
||||
// object literal creation and we will end up having and undefined
|
||||
// value that does not match the field type.
|
||||
CHECK(!field_type->NowStable() || field_type->NowContains(value) ||
|
||||
(!FLAG_use_allocation_folding && value->IsUndefined(isolate)));
|
||||
}
|
||||
}
|
||||
Object* value = obj->RawFastPropertyAt(index);
|
||||
if (r.IsDouble()) DCHECK(value->IsMutableHeapNumber());
|
||||
if (value->IsUninitialized(isolate)) continue;
|
||||
if (r.IsSmi()) DCHECK(value->IsSmi());
|
||||
if (r.IsHeapObject()) DCHECK(value->IsHeapObject());
|
||||
FieldType* field_type = descriptors->GetFieldType(i);
|
||||
bool type_is_none = field_type->IsNone();
|
||||
bool type_is_any = field_type->IsAny();
|
||||
if (r.IsNone()) {
|
||||
CHECK(type_is_none);
|
||||
} else if (!type_is_any && !(type_is_none && r.IsHeapObject())) {
|
||||
// If allocation folding is off then GC could happen during inner
|
||||
// object literal creation and we will end up having and undefined
|
||||
// value that does not match the field type.
|
||||
CHECK(!field_type->NowStable() || field_type->NowContains(value) ||
|
||||
(!FLAG_use_allocation_folding && value->IsUndefined(isolate)));
|
||||
}
|
||||
}
|
||||
|
||||
// If a GC was caused while constructing this object, the elements
|
||||
// pointer may point to a one pointer filler map.
|
||||
if (ElementsAreSafeToExamine()) {
|
||||
CHECK_EQ((map()->has_fast_smi_or_object_elements() ||
|
||||
(elements() == GetHeap()->empty_fixed_array()) ||
|
||||
HasFastStringWrapperElements()),
|
||||
(elements()->map() == GetHeap()->fixed_array_map() ||
|
||||
elements()->map() == GetHeap()->fixed_cow_array_map()));
|
||||
CHECK(map()->has_fast_object_elements() == HasFastObjectElements());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void VerifyDictionary(T* dict) {
|
||||
CHECK(dict->IsFixedArray());
|
||||
CHECK(dict->IsDictionary());
|
||||
int capacity = dict->Capacity();
|
||||
int nof = dict->NumberOfElements();
|
||||
int nod = dict->NumberOfDeletedElements();
|
||||
CHECK_LE(capacity, dict->length());
|
||||
CHECK_LE(nof, capacity);
|
||||
CHECK_LE(0, nof + nod);
|
||||
CHECK_LE(nof + nod, capacity);
|
||||
}
|
||||
|
||||
void VerifySlowProperties(JSReceiver* obj) {
|
||||
Map* map = obj->map();
|
||||
CHECK(map->is_dictionary_map());
|
||||
CHECK_EQ(0, map->NumberOfOwnDescriptors());
|
||||
CHECK_EQ(0, map->unused_property_fields());
|
||||
CHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
|
||||
CHECK(obj->properties()->IsDictionary());
|
||||
// Kept in-object properties for sow-mode object need to be zapped:
|
||||
int nof_in_object_properties = map->GetInObjectProperties();
|
||||
if (nof_in_object_properties > 0) {
|
||||
JSObject* js_object = JSObject::cast(obj);
|
||||
Smi* zap_value = Smi::FromInt(0);
|
||||
for (int i = 0; i < nof_in_object_properties; i++) {
|
||||
FieldIndex index = FieldIndex::ForLoadByFieldIndex(map, i);
|
||||
Object* field = js_object->RawFastPropertyAt(index);
|
||||
CHECK_EQ(field, zap_value);
|
||||
}
|
||||
}
|
||||
if (obj->IsJSGlobalObject()) {
|
||||
VerifyDictionary(JSObject::cast(obj)->global_dictionary());
|
||||
} else {
|
||||
VerifyDictionary(obj->property_dictionary());
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyProperties(JSReceiver* obj) {
|
||||
obj->VerifyHeapPointer(obj->properties());
|
||||
if (obj->HasFastProperties()) {
|
||||
VerifyFastProperties(obj);
|
||||
} else {
|
||||
VerifySlowProperties(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyElements(JSObject* obj) {
|
||||
obj->VerifyHeapPointer(obj->elements());
|
||||
// If a GC was caused while constructing this object, the elements
|
||||
// pointer may point to a one pointer filler map.
|
||||
if (!obj->ElementsAreSafeToExamine()) return;
|
||||
Map* map = obj->map();
|
||||
Heap* heap = obj->GetHeap();
|
||||
FixedArrayBase* elements = obj->elements();
|
||||
CHECK_EQ((map->has_fast_smi_or_object_elements() ||
|
||||
(elements == heap->empty_fixed_array()) ||
|
||||
obj->HasFastStringWrapperElements()),
|
||||
(elements->map() == heap->fixed_array_map() ||
|
||||
elements->map() == heap->fixed_cow_array_map()));
|
||||
CHECK_EQ(map->has_fast_object_elements(), obj->HasFastObjectElements());
|
||||
|
||||
ElementsKind kind = obj->GetElementsKind();
|
||||
if (IsFastSmiOrObjectElementsKind(kind)) {
|
||||
CHECK(elements->map() == heap->fixed_array_map() ||
|
||||
elements->map() == heap->fixed_cow_array_map());
|
||||
} else if (IsFastDoubleElementsKind(kind)) {
|
||||
CHECK(elements->IsFixedDoubleArray() ||
|
||||
elements == heap->empty_fixed_array());
|
||||
} else if (kind == DICTIONARY_ELEMENTS) {
|
||||
CHECK(elements->IsSeededNumberDictionary());
|
||||
VerifyDictionary(SeededNumberDictionary::cast(elements));
|
||||
return;
|
||||
} else {
|
||||
CHECK(kind > DICTIONARY_ELEMENTS);
|
||||
}
|
||||
CHECK(!IsSloppyArgumentsElements(kind) ||
|
||||
(elements->IsFixedArray() && elements->length() >= 2));
|
||||
|
||||
if (IsFastPackedElementsKind(kind)) {
|
||||
uint32_t length = elements->length();
|
||||
if (obj->IsJSArray()) {
|
||||
Object* number = JSArray::cast(obj)->length();
|
||||
if (number->IsSmi()) {
|
||||
length = Min(length, static_cast<uint32_t>(Smi::cast(number)->value()));
|
||||
}
|
||||
}
|
||||
if (kind == FAST_DOUBLE_ELEMENTS) {
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
CHECK(!FixedDoubleArray::cast(elements)->is_the_hole(i));
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
CHECK_NE(FixedArray::cast(elements)->get(i), heap->the_hole_value());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void JSObject::JSObjectVerify() {
|
||||
VerifyProperties(this);
|
||||
VerifyElements(this);
|
||||
}
|
||||
|
||||
void Map::MapVerify() {
|
||||
Heap* heap = GetHeap();
|
||||
CHECK(!heap->InNewSpace(this));
|
||||
CHECK(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE);
|
||||
CHECK_LE(FIRST_TYPE, instance_type());
|
||||
CHECK_LE(instance_type(), LAST_TYPE);
|
||||
CHECK(instance_size() == kVariableSizeSentinel ||
|
||||
(kPointerSize <= instance_size() &&
|
||||
instance_size() < heap->Capacity()));
|
||||
@ -357,6 +449,7 @@ void Map::DictionaryMapVerify() {
|
||||
CHECK(instance_descriptors()->IsEmpty());
|
||||
CHECK_EQ(0, unused_property_fields());
|
||||
CHECK_EQ(Heap::GetStaticVisitorIdForMap(this), visitor_id());
|
||||
CHECK_EQ(kInvalidEnumCacheSentinel, EnumLength());
|
||||
}
|
||||
|
||||
|
||||
@ -426,6 +519,59 @@ void JSGeneratorObject::JSGeneratorObjectVerify() {
|
||||
VerifyObjectField(kReceiverOffset);
|
||||
VerifyObjectField(kOperandStackOffset);
|
||||
VerifyObjectField(kContinuationOffset);
|
||||
JSObjectVerify();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void VerifyArgumentsParameterMap(FixedArray* elements) {
|
||||
Isolate* isolate = elements->GetIsolate();
|
||||
CHECK(elements->IsFixedArray());
|
||||
CHECK_GE(elements->length(), 2);
|
||||
HeapObject* context = HeapObject::cast(elements->get(0));
|
||||
HeapObject* arguments = HeapObject::cast(elements->get(1));
|
||||
// TODO(cbruni): fix arguments creation to be atomic.
|
||||
CHECK_IMPLIES(context->IsUndefined(isolate), arguments->IsUndefined(isolate));
|
||||
CHECK(context->IsUndefined(isolate) || context->IsContext());
|
||||
CHECK(arguments->IsUndefined(isolate) || arguments->IsFixedArray());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void JSArgumentsObject::JSArgumentsObjectVerify() {
|
||||
VerifyObjectField(kLengthOffset);
|
||||
JSObjectVerify();
|
||||
Isolate* isolate = GetIsolate();
|
||||
|
||||
if (isolate->bootstrapper()->IsActive()) return;
|
||||
Context* context = isolate->context();
|
||||
Object* constructor = map()->GetConstructor();
|
||||
if (constructor->IsJSFunction()) {
|
||||
context = JSFunction::cast(constructor)->context();
|
||||
}
|
||||
// TODO(cbruni): replace with NULL check once all hydrogren stubs manage to
|
||||
// set up the contexts properly.
|
||||
if (isolate->context()->IsSmi()) return;
|
||||
Context* native_context = context->native_context();
|
||||
if (map() == native_context->sloppy_arguments_map()) {
|
||||
// Sloppy arguments without aliased arguments has a normal elements backing
|
||||
// store which is already verified by JSObjectVerify() above.
|
||||
} else if (map() == native_context->fast_aliased_arguments_map()) {
|
||||
CHECK(HasFastArgumentsElements());
|
||||
FixedArray* elements = FixedArray::cast(this->elements());
|
||||
VerifyArgumentsParameterMap(FixedArray::cast(elements));
|
||||
CHECK_EQ(elements->map(), isolate->heap()->sloppy_arguments_elements_map());
|
||||
} else if (map() == native_context->slow_aliased_arguments_map()) {
|
||||
CHECK(HasSlowArgumentsElements());
|
||||
FixedArray* elements = FixedArray::cast(this->elements());
|
||||
VerifyArgumentsParameterMap(elements);
|
||||
VerifyDictionary(SeededNumberDictionary::cast(elements->get(1)));
|
||||
CHECK_EQ(elements->map(), isolate->heap()->sloppy_arguments_elements_map());
|
||||
} else if (map() == native_context->strict_arguments_map()) {
|
||||
CHECK(HasFastElements());
|
||||
} else {
|
||||
// TODO(cbruni): follow up on normalized argument maps.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -434,10 +580,12 @@ void JSValue::JSValueVerify() {
|
||||
if (v->IsHeapObject()) {
|
||||
VerifyHeapPointer(v);
|
||||
}
|
||||
JSObjectVerify();
|
||||
}
|
||||
|
||||
|
||||
void JSDate::JSDateVerify() {
|
||||
JSObjectVerify();
|
||||
if (value()->IsHeapObject()) {
|
||||
VerifyHeapPointer(value());
|
||||
}
|
||||
@ -487,6 +635,7 @@ void JSDate::JSDateVerify() {
|
||||
|
||||
|
||||
void JSMessageObject::JSMessageObjectVerify() {
|
||||
JSObjectVerify();
|
||||
CHECK(IsJSMessageObject());
|
||||
VerifyObjectField(kStartPositionOffset);
|
||||
VerifyObjectField(kEndPositionOffset);
|
||||
@ -545,6 +694,7 @@ void JSBoundFunction::JSBoundFunctionVerify() {
|
||||
|
||||
void JSFunction::JSFunctionVerify() {
|
||||
CHECK(IsJSFunction());
|
||||
JSObjectVerify();
|
||||
VerifyObjectField(kPrototypeOrInitialMapOffset);
|
||||
VerifyObjectField(kNextFunctionLinkOffset);
|
||||
CHECK(code()->IsCode());
|
||||
@ -591,6 +741,7 @@ void JSGlobalObject::JSGlobalObjectVerify() {
|
||||
elements()->length() == 0) {
|
||||
return;
|
||||
}
|
||||
CHECK(!HasFastProperties());
|
||||
JSObjectVerify();
|
||||
}
|
||||
|
||||
@ -694,7 +845,7 @@ void Code::VerifyEmbeddedObjectsDependency() {
|
||||
} else if (obj->IsJSObject()) {
|
||||
if (isolate->heap()->InNewSpace(obj)) {
|
||||
ArrayList* list =
|
||||
GetIsolate()->heap()->weak_new_space_object_to_code_list();
|
||||
isolate->heap()->weak_new_space_object_to_code_list();
|
||||
bool found = false;
|
||||
for (int i = 0; i < list->Length(); i += 2) {
|
||||
WeakCell* obj_cell = WeakCell::cast(list->Get(i));
|
||||
@ -708,7 +859,7 @@ void Code::VerifyEmbeddedObjectsDependency() {
|
||||
} else {
|
||||
Handle<HeapObject> key_obj(HeapObject::cast(obj), isolate);
|
||||
DependentCode* dep =
|
||||
GetIsolate()->heap()->LookupWeakObjectToCodeDependency(key_obj);
|
||||
isolate->heap()->LookupWeakObjectToCodeDependency(key_obj);
|
||||
dep->Contains(DependentCode::kWeakCodeGroup, cell);
|
||||
}
|
||||
}
|
||||
@ -718,18 +869,23 @@ void Code::VerifyEmbeddedObjectsDependency() {
|
||||
|
||||
|
||||
void JSArray::JSArrayVerify() {
|
||||
CHECK(IsJSArray());
|
||||
JSObjectVerify();
|
||||
Isolate* isolate = GetIsolate();
|
||||
CHECK(length()->IsNumber() || length()->IsUndefined(isolate));
|
||||
// Allow undefined for not fully initialized JSArrays
|
||||
if (length()->IsUndefined(isolate)) {
|
||||
CHECK_EQ(FixedArray::cast(elements()),
|
||||
isolate->heap()->empty_fixed_array());
|
||||
return;
|
||||
}
|
||||
CHECK(length()->IsNumber());
|
||||
// If a GC was caused while constructing this array, the elements
|
||||
// pointer may point to a one pointer filler map.
|
||||
if (ElementsAreSafeToExamine()) {
|
||||
CHECK(elements()->IsUndefined(isolate) || elements()->IsFixedArray() ||
|
||||
elements()->IsFixedDoubleArray());
|
||||
CHECK(elements()->IsFixedArray() || elements()->IsFixedDoubleArray());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void JSSet::JSSetVerify() {
|
||||
CHECK(IsJSSet());
|
||||
JSObjectVerify();
|
||||
@ -1296,7 +1452,8 @@ void Code::VerifyRecompiledCode(Code* old_code, Code* new_code) {
|
||||
while (!old_it.done()) {
|
||||
RelocInfo* rinfo = old_it.rinfo();
|
||||
Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
|
||||
CHECK(!target->is_handler() && !target->is_inline_cache_stub());
|
||||
CHECK(!target->is_handler());
|
||||
CHECK(!target->is_inline_cache_stub());
|
||||
if (target == stack_check) break;
|
||||
old_it.next();
|
||||
}
|
||||
@ -1304,7 +1461,8 @@ void Code::VerifyRecompiledCode(Code* old_code, Code* new_code) {
|
||||
while (!new_it.done()) {
|
||||
RelocInfo* rinfo = new_it.rinfo();
|
||||
Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
|
||||
CHECK(!target->is_handler() && !target->is_inline_cache_stub());
|
||||
CHECK(!target->is_handler());
|
||||
CHECK(!target->is_inline_cache_stub());
|
||||
if (target == stack_check) break;
|
||||
new_it.next();
|
||||
}
|
||||
|
@ -796,6 +796,7 @@ TYPE_CHECKER(Cell, CELL_TYPE)
|
||||
TYPE_CHECKER(PropertyCell, PROPERTY_CELL_TYPE)
|
||||
TYPE_CHECKER(WeakCell, WEAK_CELL_TYPE)
|
||||
TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE)
|
||||
TYPE_CHECKER(JSArgumentsObject, JS_ARGUMENTS_TYPE)
|
||||
TYPE_CHECKER(JSDate, JS_DATE_TYPE)
|
||||
TYPE_CHECKER(JSError, JS_ERROR_TYPE)
|
||||
TYPE_CHECKER(JSGeneratorObject, JS_GENERATOR_OBJECT_TYPE)
|
||||
@ -2355,8 +2356,8 @@ void FixedArray::set(int index, Object* value) {
|
||||
|
||||
|
||||
double FixedDoubleArray::get_scalar(int index) {
|
||||
DCHECK(map() != GetHeap()->fixed_cow_array_map() &&
|
||||
map() != GetHeap()->fixed_array_map());
|
||||
DCHECK_NE(GetHeap()->fixed_cow_array_map(), map());
|
||||
DCHECK_NE(GetHeap()->fixed_array_map(), map());
|
||||
DCHECK(index >= 0 && index < this->length());
|
||||
DCHECK(!is_the_hole(index));
|
||||
return READ_DOUBLE_FIELD(this, kHeaderSize + index * kDoubleSize);
|
||||
@ -2364,8 +2365,8 @@ double FixedDoubleArray::get_scalar(int index) {
|
||||
|
||||
|
||||
uint64_t FixedDoubleArray::get_representation(int index) {
|
||||
DCHECK(map() != GetHeap()->fixed_cow_array_map() &&
|
||||
map() != GetHeap()->fixed_array_map());
|
||||
DCHECK_NE(GetHeap()->fixed_cow_array_map(), map());
|
||||
DCHECK_NE(GetHeap()->fixed_array_map(), map());
|
||||
DCHECK(index >= 0 && index < this->length());
|
||||
int offset = kHeaderSize + index * kDoubleSize;
|
||||
return READ_UINT64_FIELD(this, offset);
|
||||
@ -3207,6 +3208,7 @@ CAST_ACCESSOR(HeapObject)
|
||||
CAST_ACCESSOR(Int16x8)
|
||||
CAST_ACCESSOR(Int32x4)
|
||||
CAST_ACCESSOR(Int8x16)
|
||||
CAST_ACCESSOR(JSArgumentsObject)
|
||||
CAST_ACCESSOR(JSArray)
|
||||
CAST_ACCESSOR(JSArrayBuffer)
|
||||
CAST_ACCESSOR(JSArrayBufferView)
|
||||
@ -6880,30 +6882,6 @@ void JSRegExp::SetDataAt(int index, Object* value) {
|
||||
|
||||
ElementsKind JSObject::GetElementsKind() {
|
||||
ElementsKind kind = map()->elements_kind();
|
||||
#if VERIFY_HEAP && DEBUG
|
||||
FixedArrayBase* fixed_array =
|
||||
reinterpret_cast<FixedArrayBase*>(READ_FIELD(this, kElementsOffset));
|
||||
|
||||
// If a GC was caused while constructing this object, the elements
|
||||
// pointer may point to a one pointer filler map.
|
||||
if (ElementsAreSafeToExamine()) {
|
||||
Map* map = fixed_array->map();
|
||||
if (IsFastSmiOrObjectElementsKind(kind)) {
|
||||
DCHECK(map == GetHeap()->fixed_array_map() ||
|
||||
map == GetHeap()->fixed_cow_array_map());
|
||||
} else if (IsFastDoubleElementsKind(kind)) {
|
||||
DCHECK(fixed_array->IsFixedDoubleArray() ||
|
||||
fixed_array == GetHeap()->empty_fixed_array());
|
||||
} else if (kind == DICTIONARY_ELEMENTS) {
|
||||
DCHECK(fixed_array->IsFixedArray());
|
||||
DCHECK(fixed_array->IsDictionary());
|
||||
} else {
|
||||
DCHECK(kind > DICTIONARY_ELEMENTS);
|
||||
}
|
||||
DCHECK(!IsSloppyArgumentsElements(kind) ||
|
||||
(elements()->IsFixedArray() && elements()->length() >= 2));
|
||||
}
|
||||
#endif
|
||||
return kind;
|
||||
}
|
||||
|
||||
|
@ -962,6 +962,7 @@ template <class C> inline bool Is(Object* obj);
|
||||
V(StringWrapper) \
|
||||
V(Foreign) \
|
||||
V(Boolean) \
|
||||
V(JSArgumentsObject) \
|
||||
V(JSArray) \
|
||||
V(JSArrayBuffer) \
|
||||
V(JSArrayBufferView) \
|
||||
@ -2578,6 +2579,9 @@ class JSArgumentsObject: public JSObject {
|
||||
// Indices of in-object properties.
|
||||
static const int kLengthIndex = 0;
|
||||
|
||||
DECLARE_VERIFIER(JSArgumentsObject)
|
||||
DECLARE_CAST(JSArgumentsObject)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSArgumentsObject);
|
||||
};
|
||||
@ -2593,6 +2597,8 @@ class JSSloppyArgumentsObject: public JSArgumentsObject {
|
||||
// Indices of in-object properties.
|
||||
static const int kCalleeIndex = 1;
|
||||
|
||||
DECLARE_CAST(JSSloppyArgumentsObject)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSSloppyArgumentsObject);
|
||||
};
|
||||
@ -2605,6 +2611,8 @@ class JSStrictArgumentsObject: public JSArgumentsObject {
|
||||
// Offsets of object fields.
|
||||
static const int kSize = JSArgumentsObject::kHeaderSize;
|
||||
|
||||
DECLARE_CAST(JSStrictArgumentsObject)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSStrictArgumentsObject);
|
||||
};
|
||||
|
@ -114,30 +114,13 @@ MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate(
|
||||
static MaybeHandle<Object> CreateArrayLiteralBoilerplate(
|
||||
Isolate* isolate, Handle<LiteralsArray> literals,
|
||||
Handle<FixedArray> elements) {
|
||||
// Create the JSArray.
|
||||
Handle<JSFunction> constructor = isolate->array_function();
|
||||
|
||||
PretenureFlag pretenure_flag =
|
||||
isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
|
||||
|
||||
Handle<JSArray> object = Handle<JSArray>::cast(
|
||||
isolate->factory()->NewJSObject(constructor, pretenure_flag));
|
||||
|
||||
ElementsKind constant_elements_kind =
|
||||
static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
|
||||
DCHECK(IsFastElementsKind(constant_elements_kind));
|
||||
Handle<FixedArrayBase> constant_elements_values(
|
||||
FixedArrayBase::cast(elements->get(1)));
|
||||
|
||||
{
|
||||
DisallowHeapAllocation no_gc;
|
||||
DCHECK(IsFastElementsKind(constant_elements_kind));
|
||||
Context* native_context = isolate->context()->native_context();
|
||||
Object* map =
|
||||
native_context->get(Context::ArrayMapIndex(constant_elements_kind));
|
||||
object->set_map(Map::cast(map));
|
||||
}
|
||||
|
||||
Handle<FixedArrayBase> copied_elements_values;
|
||||
|
||||
if (IsFastDoubleElementsKind(constant_elements_kind)) {
|
||||
copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
|
||||
Handle<FixedDoubleArray>::cast(constant_elements_values));
|
||||
@ -176,9 +159,12 @@ static MaybeHandle<Object> CreateArrayLiteralBoilerplate(
|
||||
});
|
||||
}
|
||||
}
|
||||
object->set_elements(*copied_elements_values);
|
||||
object->set_length(Smi::FromInt(copied_elements_values->length()));
|
||||
|
||||
// Create the JSArray.
|
||||
PretenureFlag pretenure_flag =
|
||||
isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
|
||||
Handle<JSArray> object = isolate->factory()->NewJSArrayWithElements(
|
||||
copied_elements_values, constant_elements_kind,
|
||||
copied_elements_values->length(), pretenure_flag);
|
||||
JSObject::ValidateElements(object);
|
||||
return object;
|
||||
}
|
||||
|
@ -734,7 +734,7 @@ RUNTIME_FUNCTION(Runtime_StringSplit) {
|
||||
|
||||
Handle<JSArray> result =
|
||||
isolate->factory()->NewJSArray(FAST_ELEMENTS, part_count, part_count,
|
||||
INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
|
||||
INITIALIZE_ARRAY_ELEMENTS_WITH_UNDEFINED);
|
||||
|
||||
DCHECK(result->HasFastObjectElements());
|
||||
|
||||
|
@ -3,11 +3,6 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function loader(dst, src, i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
var ab = new ArrayBuffer(8);
|
||||
var i_view = new Int32Array(ab);
|
||||
i_view[0] = %GetHoleNaNUpper()
|
||||
@ -26,10 +21,20 @@ opt_store();
|
||||
var i32 = new Int32Array(fixed_double_elements.buffer);
|
||||
assertEquals(i_view[0], i32[0]);
|
||||
assertEquals(i_view[1], i32[1]);
|
||||
assertTrue(isNaN(f_view [0]));
|
||||
|
||||
|
||||
function loader(dst, src, i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
var doubles = [0.5];
|
||||
loader(doubles, fixed_double_elements, 0);
|
||||
loader(doubles, fixed_double_elements, 0);
|
||||
assertTrue(doubles[0] !== undefined);
|
||||
assertTrue(isNaN(doubles[0]));
|
||||
|
||||
%OptimizeFunctionOnNextCall(loader);
|
||||
loader(doubles, fixed_double_elements, 0);
|
||||
assertTrue(doubles[0] !== undefined);
|
||||
assertTrue(isNaN(doubles[0]));
|
||||
|
Loading…
Reference in New Issue
Block a user