[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:
cbruni 2016-07-12 06:30:37 -07:00 committed by Commit bot
parent c70dc6acd7
commit 599aa2e106
8 changed files with 284 additions and 139 deletions

View File

@ -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;
}
}

View File

@ -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 };

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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());

View File

@ -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]));