| // Copyright 2011 the V8 project authors. All rights reserved. |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following |
| // disclaimer in the documentation and/or other materials provided |
| // with the distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived |
| // from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include "v8.h" |
| |
| #include "disassembler.h" |
| #include "disasm.h" |
| #include "jsregexp.h" |
| #include "objects-visiting.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| #ifdef DEBUG |
| |
| void MaybeObject::Verify() { |
| Object* this_as_object; |
| if (ToObject(&this_as_object)) { |
| if (this_as_object->IsSmi()) { |
| Smi::cast(this_as_object)->SmiVerify(); |
| } else { |
| HeapObject::cast(this_as_object)->HeapObjectVerify(); |
| } |
| } else { |
| Failure::cast(this)->FailureVerify(); |
| } |
| } |
| |
| |
| void Object::VerifyPointer(Object* p) { |
| if (p->IsHeapObject()) { |
| HeapObject::VerifyHeapPointer(p); |
| } else { |
| ASSERT(p->IsSmi()); |
| } |
| } |
| |
| |
| void Smi::SmiVerify() { |
| ASSERT(IsSmi()); |
| } |
| |
| |
| void Failure::FailureVerify() { |
| ASSERT(IsFailure()); |
| } |
| |
| |
| void HeapObject::HeapObjectVerify() { |
| InstanceType instance_type = map()->instance_type(); |
| |
| if (instance_type < FIRST_NONSTRING_TYPE) { |
| String::cast(this)->StringVerify(); |
| return; |
| } |
| |
| switch (instance_type) { |
| case MAP_TYPE: |
| Map::cast(this)->MapVerify(); |
| break; |
| case HEAP_NUMBER_TYPE: |
| HeapNumber::cast(this)->HeapNumberVerify(); |
| break; |
| case FIXED_ARRAY_TYPE: |
| FixedArray::cast(this)->FixedArrayVerify(); |
| break; |
| case FIXED_DOUBLE_ARRAY_TYPE: |
| FixedDoubleArray::cast(this)->FixedDoubleArrayVerify(); |
| break; |
| case BYTE_ARRAY_TYPE: |
| ByteArray::cast(this)->ByteArrayVerify(); |
| break; |
| case EXTERNAL_PIXEL_ARRAY_TYPE: |
| ExternalPixelArray::cast(this)->ExternalPixelArrayVerify(); |
| break; |
| case EXTERNAL_BYTE_ARRAY_TYPE: |
| ExternalByteArray::cast(this)->ExternalByteArrayVerify(); |
| break; |
| case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: |
| ExternalUnsignedByteArray::cast(this)->ExternalUnsignedByteArrayVerify(); |
| break; |
| case EXTERNAL_SHORT_ARRAY_TYPE: |
| ExternalShortArray::cast(this)->ExternalShortArrayVerify(); |
| break; |
| case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: |
| ExternalUnsignedShortArray::cast(this)-> |
| ExternalUnsignedShortArrayVerify(); |
| break; |
| case EXTERNAL_INT_ARRAY_TYPE: |
| ExternalIntArray::cast(this)->ExternalIntArrayVerify(); |
| break; |
| case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: |
| ExternalUnsignedIntArray::cast(this)->ExternalUnsignedIntArrayVerify(); |
| break; |
| case EXTERNAL_FLOAT_ARRAY_TYPE: |
| ExternalFloatArray::cast(this)->ExternalFloatArrayVerify(); |
| break; |
| case EXTERNAL_DOUBLE_ARRAY_TYPE: |
| ExternalDoubleArray::cast(this)->ExternalDoubleArrayVerify(); |
| break; |
| case CODE_TYPE: |
| Code::cast(this)->CodeVerify(); |
| break; |
| case ODDBALL_TYPE: |
| Oddball::cast(this)->OddballVerify(); |
| break; |
| case JS_OBJECT_TYPE: |
| case JS_CONTEXT_EXTENSION_OBJECT_TYPE: |
| JSObject::cast(this)->JSObjectVerify(); |
| break; |
| case JS_VALUE_TYPE: |
| JSValue::cast(this)->JSValueVerify(); |
| break; |
| case JS_FUNCTION_TYPE: |
| JSFunction::cast(this)->JSFunctionVerify(); |
| break; |
| case JS_GLOBAL_PROXY_TYPE: |
| JSGlobalProxy::cast(this)->JSGlobalProxyVerify(); |
| break; |
| case JS_GLOBAL_OBJECT_TYPE: |
| JSGlobalObject::cast(this)->JSGlobalObjectVerify(); |
| break; |
| case JS_BUILTINS_OBJECT_TYPE: |
| JSBuiltinsObject::cast(this)->JSBuiltinsObjectVerify(); |
| break; |
| case JS_GLOBAL_PROPERTY_CELL_TYPE: |
| JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellVerify(); |
| break; |
| case JS_ARRAY_TYPE: |
| JSArray::cast(this)->JSArrayVerify(); |
| break; |
| case JS_WEAK_MAP_TYPE: |
| JSWeakMap::cast(this)->JSWeakMapVerify(); |
| break; |
| case JS_REGEXP_TYPE: |
| JSRegExp::cast(this)->JSRegExpVerify(); |
| break; |
| case FILLER_TYPE: |
| break; |
| case JS_PROXY_TYPE: |
| JSProxy::cast(this)->JSProxyVerify(); |
| break; |
| case FOREIGN_TYPE: |
| Foreign::cast(this)->ForeignVerify(); |
| break; |
| case SHARED_FUNCTION_INFO_TYPE: |
| SharedFunctionInfo::cast(this)->SharedFunctionInfoVerify(); |
| break; |
| case JS_MESSAGE_OBJECT_TYPE: |
| JSMessageObject::cast(this)->JSMessageObjectVerify(); |
| break; |
| |
| #define MAKE_STRUCT_CASE(NAME, Name, name) \ |
| case NAME##_TYPE: \ |
| Name::cast(this)->Name##Verify(); \ |
| break; |
| STRUCT_LIST(MAKE_STRUCT_CASE) |
| #undef MAKE_STRUCT_CASE |
| |
| default: |
| UNREACHABLE(); |
| break; |
| } |
| } |
| |
| |
| void HeapObject::VerifyHeapPointer(Object* p) { |
| ASSERT(p->IsHeapObject()); |
| ASSERT(HEAP->Contains(HeapObject::cast(p))); |
| } |
| |
| |
| void HeapNumber::HeapNumberVerify() { |
| ASSERT(IsHeapNumber()); |
| } |
| |
| |
| void ByteArray::ByteArrayVerify() { |
| ASSERT(IsByteArray()); |
| } |
| |
| |
| void ExternalPixelArray::ExternalPixelArrayVerify() { |
| ASSERT(IsExternalPixelArray()); |
| } |
| |
| |
| void ExternalByteArray::ExternalByteArrayVerify() { |
| ASSERT(IsExternalByteArray()); |
| } |
| |
| |
| void ExternalUnsignedByteArray::ExternalUnsignedByteArrayVerify() { |
| ASSERT(IsExternalUnsignedByteArray()); |
| } |
| |
| |
| void ExternalShortArray::ExternalShortArrayVerify() { |
| ASSERT(IsExternalShortArray()); |
| } |
| |
| |
| void ExternalUnsignedShortArray::ExternalUnsignedShortArrayVerify() { |
| ASSERT(IsExternalUnsignedShortArray()); |
| } |
| |
| |
| void ExternalIntArray::ExternalIntArrayVerify() { |
| ASSERT(IsExternalIntArray()); |
| } |
| |
| |
| void ExternalUnsignedIntArray::ExternalUnsignedIntArrayVerify() { |
| ASSERT(IsExternalUnsignedIntArray()); |
| } |
| |
| |
| void ExternalFloatArray::ExternalFloatArrayVerify() { |
| ASSERT(IsExternalFloatArray()); |
| } |
| |
| |
| void ExternalDoubleArray::ExternalDoubleArrayVerify() { |
| ASSERT(IsExternalDoubleArray()); |
| } |
| |
| |
| void JSObject::JSObjectVerify() { |
| VerifyHeapPointer(properties()); |
| VerifyHeapPointer(elements()); |
| if (HasFastProperties()) { |
| CHECK_EQ(map()->unused_property_fields(), |
| (map()->inobject_properties() + properties()->length() - |
| map()->NextFreePropertyIndex())); |
| } |
| ASSERT(map()->has_fast_elements() == |
| (elements()->map() == GetHeap()->fixed_array_map() || |
| elements()->map() == GetHeap()->fixed_cow_array_map())); |
| ASSERT(map()->has_fast_elements() == HasFastElements()); |
| } |
| |
| |
| void Map::MapVerify() { |
| ASSERT(!HEAP->InNewSpace(this)); |
| ASSERT(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE); |
| ASSERT(instance_size() == kVariableSizeSentinel || |
| (kPointerSize <= instance_size() && |
| instance_size() < HEAP->Capacity())); |
| VerifyHeapPointer(prototype()); |
| VerifyHeapPointer(instance_descriptors()); |
| } |
| |
| |
| void Map::SharedMapVerify() { |
| MapVerify(); |
| ASSERT(is_shared()); |
| ASSERT(instance_descriptors()->IsEmpty()); |
| ASSERT_EQ(0, pre_allocated_property_fields()); |
| ASSERT_EQ(0, unused_property_fields()); |
| ASSERT_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()), |
| visitor_id()); |
| } |
| |
| |
| void CodeCache::CodeCacheVerify() { |
| VerifyHeapPointer(default_cache()); |
| VerifyHeapPointer(normal_type_cache()); |
| ASSERT(default_cache()->IsFixedArray()); |
| ASSERT(normal_type_cache()->IsUndefined() |
| || normal_type_cache()->IsCodeCacheHashTable()); |
| } |
| |
| |
| void PolymorphicCodeCache::PolymorphicCodeCacheVerify() { |
| VerifyHeapPointer(cache()); |
| ASSERT(cache()->IsUndefined() || cache()->IsPolymorphicCodeCacheHashTable()); |
| } |
| |
| |
| void FixedArray::FixedArrayVerify() { |
| for (int i = 0; i < length(); i++) { |
| Object* e = get(i); |
| if (e->IsHeapObject()) { |
| VerifyHeapPointer(e); |
| } else { |
| e->Verify(); |
| } |
| } |
| } |
| |
| |
| void FixedDoubleArray::FixedDoubleArrayVerify() { |
| for (int i = 0; i < length(); i++) { |
| if (!is_the_hole(i)) { |
| double value = get_scalar(i); |
| ASSERT(!isnan(value) || |
| (BitCast<uint64_t>(value) == |
| BitCast<uint64_t>(canonical_not_the_hole_nan_as_double()))); |
| } |
| } |
| } |
| |
| |
| void JSValue::JSValueVerify() { |
| Object* v = value(); |
| if (v->IsHeapObject()) { |
| VerifyHeapPointer(v); |
| } |
| } |
| |
| |
| void JSMessageObject::JSMessageObjectVerify() { |
| CHECK(IsJSMessageObject()); |
| CHECK(type()->IsString()); |
| CHECK(arguments()->IsJSArray()); |
| VerifyObjectField(kStartPositionOffset); |
| VerifyObjectField(kEndPositionOffset); |
| VerifyObjectField(kArgumentsOffset); |
| VerifyObjectField(kScriptOffset); |
| VerifyObjectField(kStackTraceOffset); |
| VerifyObjectField(kStackFramesOffset); |
| } |
| |
| |
| void String::StringVerify() { |
| CHECK(IsString()); |
| CHECK(length() >= 0 && length() <= Smi::kMaxValue); |
| if (IsSymbol()) { |
| CHECK(!HEAP->InNewSpace(this)); |
| } |
| if (IsConsString()) { |
| ConsString::cast(this)->ConsStringVerify(); |
| } else if (IsSlicedString()) { |
| SlicedString::cast(this)->SlicedStringVerify(); |
| } |
| } |
| |
| |
| void ConsString::ConsStringVerify() { |
| CHECK(this->first()->IsString()); |
| CHECK(this->second() == GetHeap()->empty_string() || |
| this->second()->IsString()); |
| CHECK(this->length() >= String::kMinNonFlatLength); |
| if (this->IsFlat()) { |
| // A flat cons can only be created by String::SlowTryFlatten. |
| // Afterwards, the first part may be externalized. |
| CHECK(this->first()->IsSeqString() || this->first()->IsExternalString()); |
| } |
| } |
| |
| |
| void SlicedString::SlicedStringVerify() { |
| CHECK(!this->parent()->IsConsString()); |
| CHECK(!this->parent()->IsSlicedString()); |
| CHECK(this->length() >= SlicedString::kMinLength); |
| } |
| |
| |
| void JSFunction::JSFunctionVerify() { |
| CHECK(IsJSFunction()); |
| VerifyObjectField(kPrototypeOrInitialMapOffset); |
| VerifyObjectField(kNextFunctionLinkOffset); |
| CHECK(next_function_link()->IsUndefined() || |
| next_function_link()->IsJSFunction()); |
| } |
| |
| |
| void SharedFunctionInfo::SharedFunctionInfoVerify() { |
| CHECK(IsSharedFunctionInfo()); |
| VerifyObjectField(kNameOffset); |
| VerifyObjectField(kCodeOffset); |
| VerifyObjectField(kScopeInfoOffset); |
| VerifyObjectField(kInstanceClassNameOffset); |
| VerifyObjectField(kFunctionDataOffset); |
| VerifyObjectField(kScriptOffset); |
| VerifyObjectField(kDebugInfoOffset); |
| } |
| |
| |
| void JSGlobalProxy::JSGlobalProxyVerify() { |
| CHECK(IsJSGlobalProxy()); |
| JSObjectVerify(); |
| VerifyObjectField(JSGlobalProxy::kContextOffset); |
| // Make sure that this object has no properties, elements. |
| CHECK_EQ(0, properties()->length()); |
| CHECK(HasFastElements()); |
| CHECK_EQ(0, FixedArray::cast(elements())->length()); |
| } |
| |
| |
| void JSGlobalObject::JSGlobalObjectVerify() { |
| CHECK(IsJSGlobalObject()); |
| JSObjectVerify(); |
| for (int i = GlobalObject::kBuiltinsOffset; |
| i < JSGlobalObject::kSize; |
| i += kPointerSize) { |
| VerifyObjectField(i); |
| } |
| } |
| |
| |
| void JSBuiltinsObject::JSBuiltinsObjectVerify() { |
| CHECK(IsJSBuiltinsObject()); |
| JSObjectVerify(); |
| for (int i = GlobalObject::kBuiltinsOffset; |
| i < JSBuiltinsObject::kSize; |
| i += kPointerSize) { |
| VerifyObjectField(i); |
| } |
| } |
| |
| |
| void Oddball::OddballVerify() { |
| CHECK(IsOddball()); |
| VerifyHeapPointer(to_string()); |
| Object* number = to_number(); |
| if (number->IsHeapObject()) { |
| ASSERT(number == HEAP->nan_value()); |
| } else { |
| ASSERT(number->IsSmi()); |
| int value = Smi::cast(number)->value(); |
| // Hidden oddballs have negative smis. |
| const int kLeastHiddenOddballNumber = -4; |
| ASSERT(value <= 1); |
| ASSERT(value >= kLeastHiddenOddballNumber); |
| } |
| } |
| |
| |
| void JSGlobalPropertyCell::JSGlobalPropertyCellVerify() { |
| CHECK(IsJSGlobalPropertyCell()); |
| VerifyObjectField(kValueOffset); |
| } |
| |
| |
| void Code::CodeVerify() { |
| CHECK(IsAligned(reinterpret_cast<intptr_t>(instruction_start()), |
| kCodeAlignment)); |
| Address last_gc_pc = NULL; |
| for (RelocIterator it(this); !it.done(); it.next()) { |
| it.rinfo()->Verify(); |
| // Ensure that GC will not iterate twice over the same pointer. |
| if (RelocInfo::IsGCRelocMode(it.rinfo()->rmode())) { |
| CHECK(it.rinfo()->pc() != last_gc_pc); |
| last_gc_pc = it.rinfo()->pc(); |
| } |
| } |
| } |
| |
| |
| void JSArray::JSArrayVerify() { |
| JSObjectVerify(); |
| ASSERT(length()->IsNumber() || length()->IsUndefined()); |
| ASSERT(elements()->IsUndefined() || |
| elements()->IsFixedArray() || |
| elements()->IsFixedDoubleArray()); |
| } |
| |
| |
| void JSWeakMap::JSWeakMapVerify() { |
| CHECK(IsJSWeakMap()); |
| JSObjectVerify(); |
| VerifyHeapPointer(table()); |
| ASSERT(table()->IsHashTable()); |
| } |
| |
| |
| void JSRegExp::JSRegExpVerify() { |
| JSObjectVerify(); |
| ASSERT(data()->IsUndefined() || data()->IsFixedArray()); |
| switch (TypeTag()) { |
| case JSRegExp::ATOM: { |
| FixedArray* arr = FixedArray::cast(data()); |
| ASSERT(arr->get(JSRegExp::kAtomPatternIndex)->IsString()); |
| break; |
| } |
| case JSRegExp::IRREGEXP: { |
| bool is_native = RegExpImpl::UsesNativeRegExp(); |
| |
| FixedArray* arr = FixedArray::cast(data()); |
| Object* ascii_data = arr->get(JSRegExp::kIrregexpASCIICodeIndex); |
| // Smi : Not compiled yet (-1) or code prepared for flushing. |
| // JSObject: Compilation error. |
| // Code/ByteArray: Compiled code. |
| ASSERT(ascii_data->IsSmi() || |
| (is_native ? ascii_data->IsCode() : ascii_data->IsByteArray())); |
| Object* uc16_data = arr->get(JSRegExp::kIrregexpUC16CodeIndex); |
| ASSERT(uc16_data->IsSmi() || |
| (is_native ? uc16_data->IsCode() : uc16_data->IsByteArray())); |
| |
| Object* ascii_saved = arr->get(JSRegExp::kIrregexpASCIICodeSavedIndex); |
| ASSERT(ascii_saved->IsSmi() || ascii_saved->IsString() || |
| ascii_saved->IsCode()); |
| Object* uc16_saved = arr->get(JSRegExp::kIrregexpUC16CodeSavedIndex); |
| ASSERT(uc16_saved->IsSmi() || uc16_saved->IsString() || |
| uc16_saved->IsCode()); |
| |
| ASSERT(arr->get(JSRegExp::kIrregexpCaptureCountIndex)->IsSmi()); |
| ASSERT(arr->get(JSRegExp::kIrregexpMaxRegisterCountIndex)->IsSmi()); |
| break; |
| } |
| default: |
| ASSERT_EQ(JSRegExp::NOT_COMPILED, TypeTag()); |
| ASSERT(data()->IsUndefined()); |
| break; |
| } |
| } |
| |
| |
| void JSProxy::JSProxyVerify() { |
| ASSERT(IsJSProxy()); |
| VerifyPointer(handler()); |
| } |
| |
| void Foreign::ForeignVerify() { |
| ASSERT(IsForeign()); |
| } |
| |
| |
| void AccessorInfo::AccessorInfoVerify() { |
| CHECK(IsAccessorInfo()); |
| VerifyPointer(getter()); |
| VerifyPointer(setter()); |
| VerifyPointer(name()); |
| VerifyPointer(data()); |
| VerifyPointer(flag()); |
| } |
| |
| |
| void AccessCheckInfo::AccessCheckInfoVerify() { |
| CHECK(IsAccessCheckInfo()); |
| VerifyPointer(named_callback()); |
| VerifyPointer(indexed_callback()); |
| VerifyPointer(data()); |
| } |
| |
| |
| void InterceptorInfo::InterceptorInfoVerify() { |
| CHECK(IsInterceptorInfo()); |
| VerifyPointer(getter()); |
| VerifyPointer(setter()); |
| VerifyPointer(query()); |
| VerifyPointer(deleter()); |
| VerifyPointer(enumerator()); |
| VerifyPointer(data()); |
| } |
| |
| |
| void CallHandlerInfo::CallHandlerInfoVerify() { |
| CHECK(IsCallHandlerInfo()); |
| VerifyPointer(callback()); |
| VerifyPointer(data()); |
| } |
| |
| |
| void TemplateInfo::TemplateInfoVerify() { |
| VerifyPointer(tag()); |
| VerifyPointer(property_list()); |
| } |
| |
| void FunctionTemplateInfo::FunctionTemplateInfoVerify() { |
| CHECK(IsFunctionTemplateInfo()); |
| TemplateInfoVerify(); |
| VerifyPointer(serial_number()); |
| VerifyPointer(call_code()); |
| VerifyPointer(property_accessors()); |
| VerifyPointer(prototype_template()); |
| VerifyPointer(parent_template()); |
| VerifyPointer(named_property_handler()); |
| VerifyPointer(indexed_property_handler()); |
| VerifyPointer(instance_template()); |
| VerifyPointer(signature()); |
| VerifyPointer(access_check_info()); |
| } |
| |
| |
| void ObjectTemplateInfo::ObjectTemplateInfoVerify() { |
| CHECK(IsObjectTemplateInfo()); |
| TemplateInfoVerify(); |
| VerifyPointer(constructor()); |
| VerifyPointer(internal_field_count()); |
| } |
| |
| |
| void SignatureInfo::SignatureInfoVerify() { |
| CHECK(IsSignatureInfo()); |
| VerifyPointer(receiver()); |
| VerifyPointer(args()); |
| } |
| |
| |
| void TypeSwitchInfo::TypeSwitchInfoVerify() { |
| CHECK(IsTypeSwitchInfo()); |
| VerifyPointer(types()); |
| } |
| |
| |
| void Script::ScriptVerify() { |
| CHECK(IsScript()); |
| VerifyPointer(source()); |
| VerifyPointer(name()); |
| line_offset()->SmiVerify(); |
| column_offset()->SmiVerify(); |
| VerifyPointer(data()); |
| VerifyPointer(wrapper()); |
| type()->SmiVerify(); |
| VerifyPointer(line_ends()); |
| VerifyPointer(id()); |
| } |
| |
| |
| #ifdef ENABLE_DEBUGGER_SUPPORT |
| void DebugInfo::DebugInfoVerify() { |
| CHECK(IsDebugInfo()); |
| VerifyPointer(shared()); |
| VerifyPointer(original_code()); |
| VerifyPointer(code()); |
| VerifyPointer(break_points()); |
| } |
| |
| |
| void BreakPointInfo::BreakPointInfoVerify() { |
| CHECK(IsBreakPointInfo()); |
| code_position()->SmiVerify(); |
| source_position()->SmiVerify(); |
| statement_position()->SmiVerify(); |
| VerifyPointer(break_point_objects()); |
| } |
| #endif // ENABLE_DEBUGGER_SUPPORT |
| |
| |
| void JSObject::IncrementSpillStatistics(SpillInformation* info) { |
| info->number_of_objects_++; |
| // Named properties |
| if (HasFastProperties()) { |
| info->number_of_objects_with_fast_properties_++; |
| info->number_of_fast_used_fields_ += map()->NextFreePropertyIndex(); |
| info->number_of_fast_unused_fields_ += map()->unused_property_fields(); |
| } else { |
| StringDictionary* dict = property_dictionary(); |
| info->number_of_slow_used_properties_ += dict->NumberOfElements(); |
| info->number_of_slow_unused_properties_ += |
| dict->Capacity() - dict->NumberOfElements(); |
| } |
| // Indexed properties |
| switch (GetElementsKind()) { |
| case FAST_ELEMENTS: { |
| info->number_of_objects_with_fast_elements_++; |
| int holes = 0; |
| FixedArray* e = FixedArray::cast(elements()); |
| int len = e->length(); |
| Heap* heap = HEAP; |
| for (int i = 0; i < len; i++) { |
| if (e->get(i) == heap->the_hole_value()) holes++; |
| } |
| info->number_of_fast_used_elements_ += len - holes; |
| info->number_of_fast_unused_elements_ += holes; |
| break; |
| } |
| case EXTERNAL_PIXEL_ELEMENTS: { |
| info->number_of_objects_with_fast_elements_++; |
| ExternalPixelArray* e = ExternalPixelArray::cast(elements()); |
| info->number_of_fast_used_elements_ += e->length(); |
| break; |
| } |
| case DICTIONARY_ELEMENTS: { |
| NumberDictionary* dict = element_dictionary(); |
| info->number_of_slow_used_elements_ += dict->NumberOfElements(); |
| info->number_of_slow_unused_elements_ += |
| dict->Capacity() - dict->NumberOfElements(); |
| break; |
| } |
| default: |
| UNREACHABLE(); |
| break; |
| } |
| } |
| |
| |
| void JSObject::SpillInformation::Clear() { |
| number_of_objects_ = 0; |
| number_of_objects_with_fast_properties_ = 0; |
| number_of_objects_with_fast_elements_ = 0; |
| number_of_fast_used_fields_ = 0; |
| number_of_fast_unused_fields_ = 0; |
| number_of_slow_used_properties_ = 0; |
| number_of_slow_unused_properties_ = 0; |
| number_of_fast_used_elements_ = 0; |
| number_of_fast_unused_elements_ = 0; |
| number_of_slow_used_elements_ = 0; |
| number_of_slow_unused_elements_ = 0; |
| } |
| |
| void JSObject::SpillInformation::Print() { |
| PrintF("\n JSObject Spill Statistics (#%d):\n", number_of_objects_); |
| |
| PrintF(" - fast properties (#%d): %d (used) %d (unused)\n", |
| number_of_objects_with_fast_properties_, |
| number_of_fast_used_fields_, number_of_fast_unused_fields_); |
| |
| PrintF(" - slow properties (#%d): %d (used) %d (unused)\n", |
| number_of_objects_ - number_of_objects_with_fast_properties_, |
| number_of_slow_used_properties_, number_of_slow_unused_properties_); |
| |
| PrintF(" - fast elements (#%d): %d (used) %d (unused)\n", |
| number_of_objects_with_fast_elements_, |
| number_of_fast_used_elements_, number_of_fast_unused_elements_); |
| |
| PrintF(" - slow elements (#%d): %d (used) %d (unused)\n", |
| number_of_objects_ - number_of_objects_with_fast_elements_, |
| number_of_slow_used_elements_, number_of_slow_unused_elements_); |
| |
| PrintF("\n"); |
| } |
| |
| |
| bool DescriptorArray::IsSortedNoDuplicates() { |
| String* current_key = NULL; |
| uint32_t current = 0; |
| for (int i = 0; i < number_of_descriptors(); i++) { |
| String* key = GetKey(i); |
| if (key == current_key) { |
| PrintDescriptors(); |
| return false; |
| } |
| current_key = key; |
| uint32_t hash = GetKey(i)->Hash(); |
| if (hash < current) { |
| PrintDescriptors(); |
| return false; |
| } |
| current = hash; |
| } |
| return true; |
| } |
| |
| |
| void JSFunctionResultCache::JSFunctionResultCacheVerify() { |
| JSFunction::cast(get(kFactoryIndex))->Verify(); |
| |
| int size = Smi::cast(get(kCacheSizeIndex))->value(); |
| ASSERT(kEntriesIndex <= size); |
| ASSERT(size <= length()); |
| ASSERT_EQ(0, size % kEntrySize); |
| |
| int finger = Smi::cast(get(kFingerIndex))->value(); |
| ASSERT(kEntriesIndex <= finger); |
| ASSERT((finger < size) || (finger == kEntriesIndex && finger == size)); |
| ASSERT_EQ(0, finger % kEntrySize); |
| |
| if (FLAG_enable_slow_asserts) { |
| for (int i = kEntriesIndex; i < size; i++) { |
| ASSERT(!get(i)->IsTheHole()); |
| get(i)->Verify(); |
| } |
| for (int i = size; i < length(); i++) { |
| ASSERT(get(i)->IsTheHole()); |
| get(i)->Verify(); |
| } |
| } |
| } |
| |
| |
| void NormalizedMapCache::NormalizedMapCacheVerify() { |
| FixedArray::cast(this)->Verify(); |
| if (FLAG_enable_slow_asserts) { |
| for (int i = 0; i < length(); i++) { |
| Object* e = get(i); |
| if (e->IsMap()) { |
| Map::cast(e)->SharedMapVerify(); |
| } else { |
| ASSERT(e->IsUndefined()); |
| } |
| } |
| } |
| } |
| |
| |
| #endif // DEBUG |
| |
| } } // namespace v8::internal |